2016-04-07 15:14:39

by Michal Hocko

[permalink] [raw]
Subject: [PATCH 0/11] introduce down_write_killable for rw_semaphore v3

Hi,
the following patchset implements a killable variant of write lock
for rw_semaphore. My usecase is to turn as many mmap_sem write users
to use a killable variant which will be helpful for the oom_reaper
merged in 4.6-rc1 (aac453635549 ("mm, oom: introduce oom reaper")) to
asynchronously tear down the oom victim address space which requires
mmap_sem for read. This will reduce a likelihood of OOM livelocks caused
by oom victim being stuck on a lock or other resource which prevents it
to reach its exit path and release the memory. I haven't implemented the
killable variant of the read lock because I do not have any usecase for
this API.

The previous version of this series was posted [1]. I have dropped patches 7-9
based on Davidlohr Bueso feedback because he pointed out that sh and extensa
can use the generic implementation. Further investigation has shown the same
is true for sparc. While those patches were removed 3 new ones were added for
same archs to use the generic implementation. Other than that there were no
functional changes since the last version.

The patchset is organized as follows.
- Patch 1 is a trivial cleanup
- Patch 2, I belive, shouldn't introduce any functional changes as per
Documentation/memory-barriers.txt.
- Patches 3-5 are moving xtensa, sh and sparc to generic implementation
- Patch 6 is the preparatory work and necessary infrastructure for
down_write_killable. It implements generic __down_write_killable
and prepares the write lock slow path to bail out earlier when told so
- Patch 7-10 are implementing arch specific __down_write_killable. One
patch per architecture.
- finally patch 11 implements down_write_killable and ties everything
together. I am not really an expert on lockdep so I hope I got it right.

Follow up patches to change mmap_sem write users to killable form is not
part of the series because that will be routed via mmotm tree later on.

I have tested on x86 with OOM situations with high mmap_sem contention
(basically many parallel page faults racing with many parallel mmap/munmap
tight loops) so the waiters for the write locks are routinely interrupted
by SIGKILL.

Thanks!
---
[1] http://lkml.kernel.org/r/[email protected]


2016-04-07 15:12:48

by Michal Hocko

[permalink] [raw]
Subject: [PATCH 01/11] locking, rwsem: get rid of __down_write_nested

From: Michal Hocko <[email protected]>

This is no longer used anywhere and all callers (__down_write) use
0 as a subclass. Ditch __down_write_nested to make the code easier
to follow.

This shouldn't introduce any functional change.

Acked-by: Davidlohr Bueso <[email protected]>
Signed-off-by: Michal Hocko <[email protected]>
---
arch/s390/include/asm/rwsem.h | 7 +------
arch/sh/include/asm/rwsem.h | 5 -----
arch/sparc/include/asm/rwsem.h | 7 +------
arch/x86/include/asm/rwsem.h | 7 +------
include/asm-generic/rwsem.h | 7 +------
include/linux/rwsem-spinlock.h | 1 -
kernel/locking/rwsem-spinlock.c | 7 +------
7 files changed, 5 insertions(+), 36 deletions(-)

diff --git a/arch/s390/include/asm/rwsem.h b/arch/s390/include/asm/rwsem.h
index 4b43ee7e6776..8e52e72f3efc 100644
--- a/arch/s390/include/asm/rwsem.h
+++ b/arch/s390/include/asm/rwsem.h
@@ -90,7 +90,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
+static inline void __down_write(struct rw_semaphore *sem)
{
signed long old, new, tmp;

@@ -108,11 +108,6 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
rwsem_down_write_failed(sem);
}

-static inline void __down_write(struct rw_semaphore *sem)
-{
- __down_write_nested(sem, 0);
-}
-
/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/
diff --git a/arch/sh/include/asm/rwsem.h b/arch/sh/include/asm/rwsem.h
index edab57265293..a5104bebd1eb 100644
--- a/arch/sh/include/asm/rwsem.h
+++ b/arch/sh/include/asm/rwsem.h
@@ -114,11 +114,6 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
rwsem_downgrade_wake(sem);
}

-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
-{
- __down_write(sem);
-}
-
/*
* implement exchange and add functionality
*/
diff --git a/arch/sparc/include/asm/rwsem.h b/arch/sparc/include/asm/rwsem.h
index 069bf4d663a1..e5a0d575bc7f 100644
--- a/arch/sparc/include/asm/rwsem.h
+++ b/arch/sparc/include/asm/rwsem.h
@@ -45,7 +45,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
+static inline void __down_write(struct rw_semaphore *sem)
{
long tmp;

@@ -55,11 +55,6 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
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;
diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
index cad82c9c2fde..d79a218675bc 100644
--- a/arch/x86/include/asm/rwsem.h
+++ b/arch/x86/include/asm/rwsem.h
@@ -99,7 +99,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
+static inline void __down_write(struct rw_semaphore *sem)
{
long tmp;
asm volatile("# beginning down_write\n\t"
@@ -116,11 +116,6 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
: "memory", "cc");
}

-static inline void __down_write(struct rw_semaphore *sem)
-{
- __down_write_nested(sem, 0);
-}
-
/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/
diff --git a/include/asm-generic/rwsem.h b/include/asm-generic/rwsem.h
index d6d5dc98d7da..b8d8a6cf4ca8 100644
--- a/include/asm-generic/rwsem.h
+++ b/include/asm-generic/rwsem.h
@@ -53,7 +53,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
+static inline void __down_write(struct rw_semaphore *sem)
{
long tmp;

@@ -63,11 +63,6 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
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;
diff --git a/include/linux/rwsem-spinlock.h b/include/linux/rwsem-spinlock.h
index 561e8615528d..a733a5467e6c 100644
--- a/include/linux/rwsem-spinlock.h
+++ b/include/linux/rwsem-spinlock.h
@@ -34,7 +34,6 @@ struct rw_semaphore {
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 void __down_write_nested(struct rw_semaphore *sem, int subclass);
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);
diff --git a/kernel/locking/rwsem-spinlock.c b/kernel/locking/rwsem-spinlock.c
index 3a5048572065..bab26104a5d0 100644
--- a/kernel/locking/rwsem-spinlock.c
+++ b/kernel/locking/rwsem-spinlock.c
@@ -191,7 +191,7 @@ int __down_read_trylock(struct rw_semaphore *sem)
/*
* get a write lock on the semaphore
*/
-void __sched __down_write_nested(struct rw_semaphore *sem, int subclass)
+void __sched __down_write(struct rw_semaphore *sem)
{
struct rwsem_waiter waiter;
struct task_struct *tsk;
@@ -227,11 +227,6 @@ void __sched __down_write_nested(struct rw_semaphore *sem, int subclass)
raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
}

-void __sched __down_write(struct rw_semaphore *sem)
-{
- __down_write_nested(sem, 0);
-}
-
/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/
--
2.8.0.rc3

2016-04-07 15:12:58

by Michal Hocko

[permalink] [raw]
Subject: [PATCH 09/11] s390, rwsem: provide __down_write_killable

From: Michal Hocko <[email protected]>

Introduce ___down_write for the fast path and reuse it for __down_write
resp. __down_write_killable each using the respective generic slow path
(rwsem_down_write_failed resp. rwsem_down_write_failed_killable).

Signed-off-by: Michal Hocko <[email protected]>
---
arch/s390/include/asm/rwsem.h | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/arch/s390/include/asm/rwsem.h b/arch/s390/include/asm/rwsem.h
index 8e52e72f3efc..8e7b2b7e10f3 100644
--- a/arch/s390/include/asm/rwsem.h
+++ b/arch/s390/include/asm/rwsem.h
@@ -90,7 +90,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
-static inline void __down_write(struct rw_semaphore *sem)
+static inline long ___down_write(struct rw_semaphore *sem)
{
signed long old, new, tmp;

@@ -104,10 +104,25 @@ static inline void __down_write(struct rw_semaphore *sem)
: "=&d" (old), "=&d" (new), "=Q" (sem->count)
: "Q" (sem->count), "m" (tmp)
: "cc", "memory");
- if (old != 0)
+
+ return old;
+}
+
+static inline void __down_write(struct rw_semaphore *sem)
+{
+ if (___down_write(sem))
rwsem_down_write_failed(sem);
}

+static inline int __down_write_killable(struct rw_semaphore *sem)
+{
+ if (___down_write(sem))
+ if (IS_ERR(rwsem_down_write_failed_killable(sem)))
+ return -EINTR;
+
+ return 0;
+}
+
/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/
--
2.8.0.rc3

2016-04-07 15:12:54

by Michal Hocko

[permalink] [raw]
Subject: [PATCH 05/11] sparc, rwsem: drop superfluous arch specific implementation

From: Michal Hocko <[email protected]>

sparc basically reuses generic implementation of rwsem so we can
reuse the code rather than duplicate it.

Signed-off-by: Michal Hocko <[email protected]>
---
arch/sparc/include/asm/Kbuild | 1 +
arch/sparc/include/asm/rwsem.h | 119 -----------------------------------------
2 files changed, 1 insertion(+), 119 deletions(-)
delete mode 100644 arch/sparc/include/asm/rwsem.h

diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index e928618838bc..6024c26c0585 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -16,6 +16,7 @@ generic-y += mm-arch-hooks.h
generic-y += module.h
generic-y += mutex.h
generic-y += preempt.h
+generic-y += rwsem.h
generic-y += serial.h
generic-y += trace_clock.h
generic-y += types.h
diff --git a/arch/sparc/include/asm/rwsem.h b/arch/sparc/include/asm/rwsem.h
deleted file mode 100644
index e5a0d575bc7f..000000000000
--- a/arch/sparc/include/asm/rwsem.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * rwsem.h: R/W semaphores implemented using CAS
- *
- * Written by David S. Miller ([email protected]), 2001.
- * Derived from asm-i386/rwsem.h
- */
-#ifndef _SPARC64_RWSEM_H
-#define _SPARC64_RWSEM_H
-
-#ifndef _LINUX_RWSEM_H
-#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
-#endif
-
-#ifdef __KERNEL__
-
-#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)
-
-/*
- * 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(struct rw_semaphore *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 __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 = 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)
-{
- return atomic64_add_return(delta, (atomic64_t *)(&sem->count));
-}
-
-#endif /* __KERNEL__ */
-
-#endif /* _SPARC64_RWSEM_H */
--
2.8.0.rc3

2016-04-07 15:13:36

by Michal Hocko

[permalink] [raw]
Subject: [PATCH 10/11] x86, rwsem: provide __down_write_killable

From: Michal Hocko <[email protected]>

which uses the same fast path as __down_write except it falls back to
call_rwsem_down_write_failed_killable slow path and return -EINTR if
killed. To prevent from code duplication extract the skeleton of
__down_write into a helper macro which just takes the semaphore
and the slow path function to be called.

Signed-off-by: Michal Hocko <[email protected]>
---
arch/x86/include/asm/rwsem.h | 41 ++++++++++++++++++++++++++++-------------
arch/x86/lib/rwsem.S | 8 ++++++++
2 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
index d79a218675bc..4c3d90dbe89a 100644
--- a/arch/x86/include/asm/rwsem.h
+++ b/arch/x86/include/asm/rwsem.h
@@ -99,21 +99,36 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
+#define ____down_write(sem, slow_path) \
+({ \
+ long tmp; \
+ struct rw_semaphore* ret = sem; \
+ asm volatile("# beginning down_write\n\t" \
+ LOCK_PREFIX " xadd %1,(%2)\n\t" \
+ /* adds 0xffff0001, returns the old value */ \
+ " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" \
+ /* was the active mask 0 before? */\
+ " jz 1f\n" \
+ " call " slow_path "\n" \
+ "1:\n" \
+ "# ending down_write" \
+ : "+m" (sem->count), "=d" (tmp), "+a" (ret) \
+ : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
+ : "memory", "cc"); \
+ ret; \
+})
+
static inline void __down_write(struct rw_semaphore *sem)
{
- long tmp;
- asm volatile("# beginning down_write\n\t"
- LOCK_PREFIX " xadd %1,(%2)\n\t"
- /* adds 0xffff0001, returns the old value */
- " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t"
- /* was the active mask 0 before? */
- " jz 1f\n"
- " call call_rwsem_down_write_failed\n"
- "1:\n"
- "# ending down_write"
- : "+m" (sem->count), "=d" (tmp)
- : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS)
- : "memory", "cc");
+ ____down_write(sem, "call_rwsem_down_write_failed");
+}
+
+static inline int __down_write_killable(struct rw_semaphore *sem)
+{
+ if (IS_ERR(____down_write(sem, "call_rwsem_down_write_failed_killable")))
+ return -EINTR;
+
+ return 0;
}

/*
diff --git a/arch/x86/lib/rwsem.S b/arch/x86/lib/rwsem.S
index 40027db99140..d1a1397e1fb3 100644
--- a/arch/x86/lib/rwsem.S
+++ b/arch/x86/lib/rwsem.S
@@ -101,6 +101,14 @@ ENTRY(call_rwsem_down_write_failed)
ret
ENDPROC(call_rwsem_down_write_failed)

+ENTRY(call_rwsem_down_write_failed_killable)
+ save_common_regs
+ movq %rax,%rdi
+ call rwsem_down_write_failed_killable
+ restore_common_regs
+ ret
+ENDPROC(call_rwsem_down_write_failed_killable)
+
ENTRY(call_rwsem_wake)
/* do nothing if still outstanding active readers */
__ASM_HALF_SIZE(dec) %__ASM_HALF_REG(dx)
--
2.8.0.rc3

2016-04-07 15:14:05

by Michal Hocko

[permalink] [raw]
Subject: [PATCH 07/11] alpha, rwsem: provide __down_write_killable

From: Michal Hocko <[email protected]>

Introduce ___down_write for the fast path and reuse it for __down_write
resp. __down_write_killable each using the respective generic slow path
(rwsem_down_write_failed resp. rwsem_down_write_failed_killable).

Signed-off-by: Michal Hocko <[email protected]>
---
arch/alpha/include/asm/rwsem.h | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/arch/alpha/include/asm/rwsem.h b/arch/alpha/include/asm/rwsem.h
index a83bbea62c67..0131a7058778 100644
--- a/arch/alpha/include/asm/rwsem.h
+++ b/arch/alpha/include/asm/rwsem.h
@@ -63,7 +63,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
return res >= 0 ? 1 : 0;
}

-static inline void __down_write(struct rw_semaphore *sem)
+static inline long ___down_write(struct rw_semaphore *sem)
{
long oldcount;
#ifndef CONFIG_SMP
@@ -83,10 +83,24 @@ static inline void __down_write(struct rw_semaphore *sem)
:"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
:"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory");
#endif
- if (unlikely(oldcount))
+ return oldcount;
+}
+
+static inline void __down_write(struct rw_semaphore *sem)
+{
+ if (unlikely(___down_write(sem)))
rwsem_down_write_failed(sem);
}

+static inline int __down_write_killable(struct rw_semaphore *sem)
+{
+ if (unlikely(___down_write(sem)))
+ if (IS_ERR(rwsem_down_write_failed_killable(sem)))
+ return -EINTR;
+
+ return 0;
+}
+
/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/
--
2.8.0.rc3

2016-04-07 15:12:52

by Michal Hocko

[permalink] [raw]
Subject: [PATCH 04/11] sh, rwsem: drop superfluous arch specific implementation

From: Michal Hocko <[email protected]>

since "locking, rwsem: drop explicit memory barriers" the arch specific
code is basically same as the the generic one so we can drop the
superfluous code.

Suggested-by: Davidlohr Bueso <[email protected]>
Signed-off-by: Michal Hocko <[email protected]>
---
arch/sh/include/asm/Kbuild | 1 +
arch/sh/include/asm/rwsem.h | 117 --------------------------------------------
2 files changed, 1 insertion(+), 117 deletions(-)
delete mode 100644 arch/sh/include/asm/rwsem.h

diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild
index aac452b26aa8..6d866c7a9b74 100644
--- a/arch/sh/include/asm/Kbuild
+++ b/arch/sh/include/asm/Kbuild
@@ -25,6 +25,7 @@ generic-y += percpu.h
generic-y += poll.h
generic-y += preempt.h
generic-y += resource.h
+generic-y += rwsem.h
generic-y += sembuf.h
generic-y += serial.h
generic-y += shmbuf.h
diff --git a/arch/sh/include/asm/rwsem.h b/arch/sh/include/asm/rwsem.h
deleted file mode 100644
index f6c951c7a875..000000000000
--- a/arch/sh/include/asm/rwsem.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * include/asm-sh/rwsem.h: R/W semaphores for SH using the stuff
- * in lib/rwsem.c.
- */
-
-#ifndef _ASM_SH_RWSEM_H
-#define _ASM_SH_RWSEM_H
-
-#ifndef _LINUX_RWSEM_H
-#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
-#endif
-
-#ifdef __KERNEL__
-
-#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)
-
-/*
- * lock for reading
- */
-static inline void __down_read(struct rw_semaphore *sem)
-{
- if (atomic_inc_return((atomic_t *)(&sem->count)) <= 0)
- rwsem_down_read_failed(sem);
-}
-
-static inline int __down_read_trylock(struct rw_semaphore *sem)
-{
- int 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(struct rw_semaphore *sem)
-{
- int tmp;
-
- tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
- (atomic_t *)(&sem->count));
- if (tmp != RWSEM_ACTIVE_WRITE_BIAS)
- rwsem_down_write_failed(sem);
-}
-
-static inline int __down_write_trylock(struct rw_semaphore *sem)
-{
- int 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)
-{
- int tmp;
-
- tmp = atomic_dec_return((atomic_t *)(&sem->count));
- if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
- rwsem_wake(sem);
-}
-
-/*
- * unlock after writing
- */
-static inline void __up_write(struct rw_semaphore *sem)
-{
- if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
- (atomic_t *)(&sem->count)) < 0)
- rwsem_wake(sem);
-}
-
-/*
- * implement atomic add functionality
- */
-static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
-{
- atomic_add(delta, (atomic_t *)(&sem->count));
-}
-
-/*
- * downgrade write lock to read lock
- */
-static inline void __downgrade_write(struct rw_semaphore *sem)
-{
- int tmp;
-
- tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
- if (tmp < 0)
- rwsem_downgrade_wake(sem);
-}
-
-/*
- * implement exchange and add functionality
- */
-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
-{
- return atomic_add_return(delta, (atomic_t *)(&sem->count));
-}
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_SH_RWSEM_H */
--
2.8.0.rc3

2016-04-07 15:15:18

by Michal Hocko

[permalink] [raw]
Subject: [PATCH 02/11] locking, rwsem: drop explicit memory barriers

From: Michal Hocko <[email protected]>

sh and xtensa seem to be the only architectures which use explicit
memory barriers for rw_semaphore operations even though they are not
really needed because there is the full memory barrier is always implied
by atomic_{inc,dec,add,sub}_return resp. cmpxchg. Remove them.

Signed-off-by: Michal Hocko <[email protected]>
---
arch/sh/include/asm/rwsem.h | 14 ++------------
arch/xtensa/include/asm/rwsem.h | 14 ++------------
2 files changed, 4 insertions(+), 24 deletions(-)

diff --git a/arch/sh/include/asm/rwsem.h b/arch/sh/include/asm/rwsem.h
index a5104bebd1eb..f6c951c7a875 100644
--- a/arch/sh/include/asm/rwsem.h
+++ b/arch/sh/include/asm/rwsem.h
@@ -24,9 +24,7 @@
*/
static inline void __down_read(struct rw_semaphore *sem)
{
- if (atomic_inc_return((atomic_t *)(&sem->count)) > 0)
- smp_wmb();
- else
+ if (atomic_inc_return((atomic_t *)(&sem->count)) <= 0)
rwsem_down_read_failed(sem);
}

@@ -37,7 +35,6 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
while ((tmp = sem->count) >= 0) {
if (tmp == cmpxchg(&sem->count, tmp,
tmp + RWSEM_ACTIVE_READ_BIAS)) {
- smp_wmb();
return 1;
}
}
@@ -53,9 +50,7 @@ static inline void __down_write(struct rw_semaphore *sem)

tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
(atomic_t *)(&sem->count));
- if (tmp == RWSEM_ACTIVE_WRITE_BIAS)
- smp_wmb();
- else
+ if (tmp != RWSEM_ACTIVE_WRITE_BIAS)
rwsem_down_write_failed(sem);
}

@@ -65,7 +60,6 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)

tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
RWSEM_ACTIVE_WRITE_BIAS);
- smp_wmb();
return tmp == RWSEM_UNLOCKED_VALUE;
}

@@ -76,7 +70,6 @@ static inline void __up_read(struct rw_semaphore *sem)
{
int tmp;

- smp_wmb();
tmp = atomic_dec_return((atomic_t *)(&sem->count));
if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
rwsem_wake(sem);
@@ -87,7 +80,6 @@ static inline void __up_read(struct rw_semaphore *sem)
*/
static inline void __up_write(struct rw_semaphore *sem)
{
- smp_wmb();
if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
(atomic_t *)(&sem->count)) < 0)
rwsem_wake(sem);
@@ -108,7 +100,6 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
{
int tmp;

- smp_wmb();
tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
if (tmp < 0)
rwsem_downgrade_wake(sem);
@@ -119,7 +110,6 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
*/
static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
{
- smp_mb();
return atomic_add_return(delta, (atomic_t *)(&sem->count));
}

diff --git a/arch/xtensa/include/asm/rwsem.h b/arch/xtensa/include/asm/rwsem.h
index 249619e7e7f2..593483f6e1ff 100644
--- a/arch/xtensa/include/asm/rwsem.h
+++ b/arch/xtensa/include/asm/rwsem.h
@@ -29,9 +29,7 @@
*/
static inline void __down_read(struct rw_semaphore *sem)
{
- if (atomic_add_return(1,(atomic_t *)(&sem->count)) > 0)
- smp_wmb();
- else
+ if (atomic_add_return(1,(atomic_t *)(&sem->count)) <= 0)
rwsem_down_read_failed(sem);
}

@@ -42,7 +40,6 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
while ((tmp = sem->count) >= 0) {
if (tmp == cmpxchg(&sem->count, tmp,
tmp + RWSEM_ACTIVE_READ_BIAS)) {
- smp_wmb();
return 1;
}
}
@@ -58,9 +55,7 @@ static inline void __down_write(struct rw_semaphore *sem)

tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
(atomic_t *)(&sem->count));
- if (tmp == RWSEM_ACTIVE_WRITE_BIAS)
- smp_wmb();
- else
+ if (tmp != RWSEM_ACTIVE_WRITE_BIAS)
rwsem_down_write_failed(sem);
}

@@ -70,7 +65,6 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)

tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
RWSEM_ACTIVE_WRITE_BIAS);
- smp_wmb();
return tmp == RWSEM_UNLOCKED_VALUE;
}

@@ -81,7 +75,6 @@ static inline void __up_read(struct rw_semaphore *sem)
{
int tmp;

- smp_wmb();
tmp = atomic_sub_return(1,(atomic_t *)(&sem->count));
if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
rwsem_wake(sem);
@@ -92,7 +85,6 @@ static inline void __up_read(struct rw_semaphore *sem)
*/
static inline void __up_write(struct rw_semaphore *sem)
{
- smp_wmb();
if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
(atomic_t *)(&sem->count)) < 0)
rwsem_wake(sem);
@@ -113,7 +105,6 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
{
int tmp;

- smp_wmb();
tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
if (tmp < 0)
rwsem_downgrade_wake(sem);
@@ -124,7 +115,6 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
*/
static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
{
- smp_mb();
return atomic_add_return(delta, (atomic_t *)(&sem->count));
}

--
2.8.0.rc3

2016-04-07 15:25:24

by Michal Hocko

[permalink] [raw]
Subject: [PATCH 11/11] locking, rwsem: provide down_write_killable

From: Michal Hocko <[email protected]>

Now that all the architectures implement the necessary glue code
we can introduce down_write_killable. The only difference wrt. regular
down_write is that the slow path waits in TASK_KILLABLE state and the
interruption by the fatal signal is reported as -EINTR to the caller.

Signed-off-by: Michal Hocko <[email protected]>
---
include/linux/lockdep.h | 15 +++++++++++++++
include/linux/rwsem.h | 1 +
kernel/locking/rwsem.c | 19 +++++++++++++++++++
3 files changed, 35 insertions(+)

diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 4dca42fd32f5..13a80779b6da 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -446,6 +446,18 @@ do { \
lock_acquired(&(_lock)->dep_map, _RET_IP_); \
} while (0)

+#define LOCK_CONTENDED_RETURN(_lock, try, lock) \
+({ \
+ int ____err = 0; \
+ if (!try(_lock)) { \
+ lock_contended(&(_lock)->dep_map, _RET_IP_); \
+ ____err = lock(_lock); \
+ } \
+ if (!____err) \
+ lock_acquired(&(_lock)->dep_map, _RET_IP_); \
+ ____err; \
+})
+
#else /* CONFIG_LOCK_STAT */

#define lock_contended(lockdep_map, ip) do {} while (0)
@@ -454,6 +466,9 @@ do { \
#define LOCK_CONTENDED(_lock, try, lock) \
lock(_lock)

+#define LOCK_CONTENDED_RETURN(_lock, try, lock) \
+ lock(_lock)
+
#endif /* CONFIG_LOCK_STAT */

#ifdef CONFIG_LOCKDEP
diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
index 7d7ae029dac5..d1c12d160ace 100644
--- a/include/linux/rwsem.h
+++ b/include/linux/rwsem.h
@@ -118,6 +118,7 @@ extern int down_read_trylock(struct rw_semaphore *sem);
* lock for writing
*/
extern void down_write(struct rw_semaphore *sem);
+extern int __must_check down_write_killable(struct rw_semaphore *sem);

/*
* trylock for writing -- returns 1 if successful, 0 if contention
diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c
index 205be0ce34de..c817216c1615 100644
--- a/kernel/locking/rwsem.c
+++ b/kernel/locking/rwsem.c
@@ -55,6 +55,25 @@ void __sched down_write(struct rw_semaphore *sem)
EXPORT_SYMBOL(down_write);

/*
+ * lock for writing
+ */
+int __sched down_write_killable(struct rw_semaphore *sem)
+{
+ might_sleep();
+ rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
+
+ if (LOCK_CONTENDED_RETURN(sem, __down_write_trylock, __down_write_killable)) {
+ rwsem_release(&sem->dep_map, 1, _RET_IP_);
+ return -EINTR;
+ }
+
+ rwsem_set_owner(sem);
+ return 0;
+}
+
+EXPORT_SYMBOL(down_write_killable);
+
+/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/
int down_write_trylock(struct rw_semaphore *sem)
--
2.8.0.rc3

2016-04-07 15:25:33

by Michal Hocko

[permalink] [raw]
Subject: [PATCH 03/11] xtensa, rwsem: drop superfluous arch specific implementation

From: Michal Hocko <[email protected]>

since "locking, rwsem: drop explicit memory barriers" the arch specific
code is basically same as the the generic one so we can drop the
superfluous code.

Suggested-by: Davidlohr Bueso <[email protected]>
Acked-by: Max Filippov <[email protected]>
Signed-off-by: Michal Hocko <[email protected]>
---
arch/xtensa/include/asm/Kbuild | 1 +
arch/xtensa/include/asm/rwsem.h | 121 ----------------------------------------
2 files changed, 1 insertion(+), 121 deletions(-)
delete mode 100644 arch/xtensa/include/asm/rwsem.h

diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild
index b56855a1382a..28cf4c5d65ef 100644
--- a/arch/xtensa/include/asm/Kbuild
+++ b/arch/xtensa/include/asm/Kbuild
@@ -22,6 +22,7 @@ generic-y += mm-arch-hooks.h
generic-y += percpu.h
generic-y += preempt.h
generic-y += resource.h
+generic-y += rwsem.h
generic-y += sections.h
generic-y += siginfo.h
generic-y += statfs.h
diff --git a/arch/xtensa/include/asm/rwsem.h b/arch/xtensa/include/asm/rwsem.h
deleted file mode 100644
index 593483f6e1ff..000000000000
--- a/arch/xtensa/include/asm/rwsem.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * include/asm-xtensa/rwsem.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Largely copied from include/asm-ppc/rwsem.h
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_RWSEM_H
-#define _XTENSA_RWSEM_H
-
-#ifndef _LINUX_RWSEM_H
-#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
-#endif
-
-#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)
-
-/*
- * lock for reading
- */
-static inline void __down_read(struct rw_semaphore *sem)
-{
- if (atomic_add_return(1,(atomic_t *)(&sem->count)) <= 0)
- rwsem_down_read_failed(sem);
-}
-
-static inline int __down_read_trylock(struct rw_semaphore *sem)
-{
- int 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(struct rw_semaphore *sem)
-{
- int tmp;
-
- tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
- (atomic_t *)(&sem->count));
- if (tmp != RWSEM_ACTIVE_WRITE_BIAS)
- rwsem_down_write_failed(sem);
-}
-
-static inline int __down_write_trylock(struct rw_semaphore *sem)
-{
- int 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)
-{
- int tmp;
-
- tmp = atomic_sub_return(1,(atomic_t *)(&sem->count));
- if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
- rwsem_wake(sem);
-}
-
-/*
- * unlock after writing
- */
-static inline void __up_write(struct rw_semaphore *sem)
-{
- if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
- (atomic_t *)(&sem->count)) < 0)
- rwsem_wake(sem);
-}
-
-/*
- * implement atomic add functionality
- */
-static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
-{
- atomic_add(delta, (atomic_t *)(&sem->count));
-}
-
-/*
- * downgrade write lock to read lock
- */
-static inline void __downgrade_write(struct rw_semaphore *sem)
-{
- int tmp;
-
- tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
- if (tmp < 0)
- rwsem_downgrade_wake(sem);
-}
-
-/*
- * implement exchange and add functionality
- */
-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
-{
- return atomic_add_return(delta, (atomic_t *)(&sem->count));
-}
-
-#endif /* _XTENSA_RWSEM_H */
--
2.8.0.rc3

2016-04-07 15:26:46

by Michal Hocko

[permalink] [raw]
Subject: [PATCH 06/11] locking, rwsem: introduce basis for down_write_killable

From: Michal Hocko <[email protected]>

Introduce a generic implementation necessary for down_write_killable.
This is a trivial extension of the already existing down_write call
which can be interrupted by SIGKILL. This patch doesn't provide
down_write_killable yet because arches have to provide the necessary
pieces before.

rwsem_down_write_failed which is a generic slow path for the
write lock is extended to take a task state and renamed to
__rwsem_down_write_failed_common. The return value is either a valid
semaphore pointer or ERR_PTR(-EINTR).

rwsem_down_write_failed_killable is exported as a new way to wait for
the lock and be killable.

For rwsem-spinlock implementation the current __down_write it updated
in a similar way as __rwsem_down_write_failed_common except it doesn't
need new exports just visible __down_write_killable.

Architectures which are not using the generic rwsem implementation are
supposed to provide their __down_write_killable implementation and
use rwsem_down_write_failed_killable for the slow path.

[[email protected] - rename __rwsem_down_write_failed_state to
__rwsem_down_write_failed_common]
Signed-off-by: Michal Hocko <[email protected]>
---
include/asm-generic/rwsem.h | 12 ++++++++++++
include/linux/rwsem-spinlock.h | 1 +
include/linux/rwsem.h | 2 ++
kernel/locking/rwsem-spinlock.c | 22 ++++++++++++++++++++--
kernel/locking/rwsem-xadd.c | 31 +++++++++++++++++++++++++------
5 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/include/asm-generic/rwsem.h b/include/asm-generic/rwsem.h
index b8d8a6cf4ca8..3fc94a046bf5 100644
--- a/include/asm-generic/rwsem.h
+++ b/include/asm-generic/rwsem.h
@@ -63,6 +63,18 @@ static inline void __down_write(struct rw_semaphore *sem)
rwsem_down_write_failed(sem);
}

+static inline int __down_write_killable(struct rw_semaphore *sem)
+{
+ long tmp;
+
+ tmp = atomic_long_add_return_acquire(RWSEM_ACTIVE_WRITE_BIAS,
+ (atomic_long_t *)&sem->count);
+ if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
+ if (IS_ERR(rwsem_down_write_failed_killable(sem)))
+ return -EINTR;
+ return 0;
+}
+
static inline int __down_write_trylock(struct rw_semaphore *sem)
{
long tmp;
diff --git a/include/linux/rwsem-spinlock.h b/include/linux/rwsem-spinlock.h
index a733a5467e6c..ae0528b834cd 100644
--- a/include/linux/rwsem-spinlock.h
+++ b/include/linux/rwsem-spinlock.h
@@ -34,6 +34,7 @@ struct rw_semaphore {
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 __must_check __down_write_killable(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);
diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
index 8f498cdde280..7d7ae029dac5 100644
--- a/include/linux/rwsem.h
+++ b/include/linux/rwsem.h
@@ -14,6 +14,7 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/atomic.h>
+#include <linux/err.h>
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
#include <linux/osq_lock.h>
#endif
@@ -43,6 +44,7 @@ struct rw_semaphore {

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_down_write_failed_killable(struct rw_semaphore *sem);
extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);

diff --git a/kernel/locking/rwsem-spinlock.c b/kernel/locking/rwsem-spinlock.c
index bab26104a5d0..1591f6b3539f 100644
--- a/kernel/locking/rwsem-spinlock.c
+++ b/kernel/locking/rwsem-spinlock.c
@@ -191,11 +191,12 @@ int __down_read_trylock(struct rw_semaphore *sem)
/*
* get a write lock on the semaphore
*/
-void __sched __down_write(struct rw_semaphore *sem)
+int __sched __down_write_common(struct rw_semaphore *sem, int state)
{
struct rwsem_waiter waiter;
struct task_struct *tsk;
unsigned long flags;
+ int ret = 0;

raw_spin_lock_irqsave(&sem->wait_lock, flags);

@@ -215,16 +216,33 @@ void __sched __down_write(struct rw_semaphore *sem)
*/
if (sem->count == 0)
break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (signal_pending_state(state, current)) {
+ ret = -EINTR;
+ goto out;
+ }
+ set_task_state(tsk, state);
raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
schedule();
raw_spin_lock_irqsave(&sem->wait_lock, flags);
}
/* got the lock */
sem->count = -1;
+out:
list_del(&waiter.list);

raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
+
+ return ret;
+}
+
+void __sched __down_write(struct rw_semaphore *sem)
+{
+ __down_write_common(sem, TASK_UNINTERRUPTIBLE);
+}
+
+int __sched __down_write_killable(struct rw_semaphore *sem)
+{
+ return __down_write_common(sem, TASK_KILLABLE);
}

/*
diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c
index a4d4de05b2d1..df4dcb883b50 100644
--- a/kernel/locking/rwsem-xadd.c
+++ b/kernel/locking/rwsem-xadd.c
@@ -433,12 +433,13 @@ static inline bool rwsem_has_spinner(struct rw_semaphore *sem)
/*
* Wait until we successfully acquire the write lock
*/
-__visible
-struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
+static inline struct rw_semaphore *
+__rwsem_down_write_failed_common(struct rw_semaphore *sem, int state)
{
long count;
bool waiting = true; /* any queued threads before us */
struct rwsem_waiter waiter;
+ struct rw_semaphore *ret = sem;

/* undo write bias from down_write operation, stop active locking */
count = rwsem_atomic_update(-RWSEM_ACTIVE_WRITE_BIAS, sem);
@@ -478,7 +479,7 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
count = rwsem_atomic_update(RWSEM_WAITING_BIAS, sem);

/* wait until we successfully acquire the lock */
- set_current_state(TASK_UNINTERRUPTIBLE);
+ set_current_state(state);
while (true) {
if (rwsem_try_write_lock(count, sem))
break;
@@ -486,21 +487,39 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)

/* Block until there are no active lockers. */
do {
+ if (signal_pending_state(state, current)) {
+ raw_spin_lock_irq(&sem->wait_lock);
+ ret = ERR_PTR(-EINTR);
+ goto out;
+ }
schedule();
- set_current_state(TASK_UNINTERRUPTIBLE);
+ set_current_state(state);
} while ((count = sem->count) & RWSEM_ACTIVE_MASK);

raw_spin_lock_irq(&sem->wait_lock);
}
+out:
__set_current_state(TASK_RUNNING);
-
list_del(&waiter.list);
raw_spin_unlock_irq(&sem->wait_lock);

- return sem;
+ return ret;
+}
+
+__visible struct rw_semaphore * __sched
+rwsem_down_write_failed(struct rw_semaphore *sem)
+{
+ return __rwsem_down_write_failed_common(sem, TASK_UNINTERRUPTIBLE);
}
EXPORT_SYMBOL(rwsem_down_write_failed);

+__visible struct rw_semaphore * __sched
+rwsem_down_write_failed_killable(struct rw_semaphore *sem)
+{
+ return __rwsem_down_write_failed_common(sem, TASK_KILLABLE);
+}
+EXPORT_SYMBOL(rwsem_down_write_failed_killable);
+
/*
* handle waking up a waiter on the semaphore
* - up_read/up_write has decremented the active part of count if we come here
--
2.8.0.rc3

2016-04-07 15:28:28

by Michal Hocko

[permalink] [raw]
Subject: [PATCH 08/11] ia64, rwsem: provide __down_write_killable

From: Michal Hocko <[email protected]>

Introduce ___down_write for the fast path and reuse it for __down_write
resp. __down_write_killable each using the respective generic slow path
(rwsem_down_write_failed resp. rwsem_down_write_failed_killable).

Signed-off-by: Michal Hocko <[email protected]>
---
arch/ia64/include/asm/rwsem.h | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/arch/ia64/include/asm/rwsem.h b/arch/ia64/include/asm/rwsem.h
index 3027e7516d85..5e78cb40d9df 100644
--- a/arch/ia64/include/asm/rwsem.h
+++ b/arch/ia64/include/asm/rwsem.h
@@ -49,8 +49,8 @@ __down_read (struct rw_semaphore *sem)
/*
* lock for writing
*/
-static inline void
-__down_write (struct rw_semaphore *sem)
+static inline long
+___down_write (struct rw_semaphore *sem)
{
long old, new;

@@ -59,10 +59,26 @@ __down_write (struct rw_semaphore *sem)
new = old + RWSEM_ACTIVE_WRITE_BIAS;
} while (cmpxchg_acq(&sem->count, old, new) != old);

- if (old != 0)
+ return old;
+}
+
+static inline void
+__down_write (struct rw_semaphore *sem)
+{
+ if (___down_write(sem))
rwsem_down_write_failed(sem);
}

+static inline int
+__down_write_killable (struct rw_semaphore *sem)
+{
+ if (___down_write(sem))
+ if (IS_ERR(rwsem_down_write_failed_killable(sem)))
+ return -EINTR;
+
+ return 0;
+}
+
/*
* unlock after reading
*/
--
2.8.0.rc3

2016-04-07 17:28:28

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH 08/11] ia64, rwsem: provide __down_write_killable

Hello.

On 04/07/2016 06:12 PM, Michal Hocko wrote:

> From: Michal Hocko <[email protected]>
>
> Introduce ___down_write for the fast path and reuse it for __down_write
> resp. __down_write_killable each using the respective generic slow path
> (rwsem_down_write_failed resp. rwsem_down_write_failed_killable).
>
> Signed-off-by: Michal Hocko <[email protected]>
> ---
> arch/ia64/include/asm/rwsem.h | 22 +++++++++++++++++++---
> 1 file changed, 19 insertions(+), 3 deletions(-)
>
> diff --git a/arch/ia64/include/asm/rwsem.h b/arch/ia64/include/asm/rwsem.h
> index 3027e7516d85..5e78cb40d9df 100644
> --- a/arch/ia64/include/asm/rwsem.h
> +++ b/arch/ia64/include/asm/rwsem.h
> @@ -49,8 +49,8 @@ __down_read (struct rw_semaphore *sem)
> /*
> * lock for writing
> */
> -static inline void
> -__down_write (struct rw_semaphore *sem)
> +static inline long
> +___down_write (struct rw_semaphore *sem)
> {
> long old, new;
>
> @@ -59,10 +59,26 @@ __down_write (struct rw_semaphore *sem)
> new = old + RWSEM_ACTIVE_WRITE_BIAS;
> } while (cmpxchg_acq(&sem->count, old, new) != old);
>
> - if (old != 0)
> + return old;
> +}
> +
> +static inline void
> +__down_write (struct rw_semaphore *sem)
> +{
> + if (___down_write(sem))
> rwsem_down_write_failed(sem);
> }
>
> +static inline int
> +__down_write_killable (struct rw_semaphore *sem)

Looks like you haven't run this patch thru scripts/checkpatch.pl. Hint:
space before ( isn't allowed.

[...]

MNBR, Sergei

2016-04-08 06:22:56

by Michal Hocko

[permalink] [raw]
Subject: Re: [PATCH 08/11] ia64, rwsem: provide __down_write_killable

On Thu 07-04-16 20:28:16, Sergei Shtylyov wrote:
> Hello.
>
> On 04/07/2016 06:12 PM, Michal Hocko wrote:
>
> >From: Michal Hocko <[email protected]>
> >
> >Introduce ___down_write for the fast path and reuse it for __down_write
> >resp. __down_write_killable each using the respective generic slow path
> >(rwsem_down_write_failed resp. rwsem_down_write_failed_killable).
> >
> >Signed-off-by: Michal Hocko <[email protected]>
> >---
> > arch/ia64/include/asm/rwsem.h | 22 +++++++++++++++++++---
> > 1 file changed, 19 insertions(+), 3 deletions(-)
> >
> >diff --git a/arch/ia64/include/asm/rwsem.h b/arch/ia64/include/asm/rwsem.h
> >index 3027e7516d85..5e78cb40d9df 100644
> >--- a/arch/ia64/include/asm/rwsem.h
> >+++ b/arch/ia64/include/asm/rwsem.h
> >@@ -49,8 +49,8 @@ __down_read (struct rw_semaphore *sem)
> > /*
> > * lock for writing
> > */
> >-static inline void
> >-__down_write (struct rw_semaphore *sem)
> >+static inline long
> >+___down_write (struct rw_semaphore *sem)
> > {
> > long old, new;
> >
> >@@ -59,10 +59,26 @@ __down_write (struct rw_semaphore *sem)
> > new = old + RWSEM_ACTIVE_WRITE_BIAS;
> > } while (cmpxchg_acq(&sem->count, old, new) != old);
> >
> >- if (old != 0)
> >+ return old;
> >+}
> >+
> >+static inline void
> >+__down_write (struct rw_semaphore *sem)
> >+{
> >+ if (___down_write(sem))
> > rwsem_down_write_failed(sem);
> > }
> >
> >+static inline int
> >+__down_write_killable (struct rw_semaphore *sem)
>
> Looks like you haven't run this patch thru scripts/checkpatch.pl. Hint:
> space before ( isn't allowed.

I have just kept the original code styling because I didn't feel like
changing the whole file.

--
Michal Hocko
SUSE Labs

2016-04-12 09:37:22

by Michal Hocko

[permalink] [raw]
Subject: Re: [PATCH 0/11] introduce down_write_killable for rw_semaphore v3

Hi Ingo, Peter,
do you plan to pull this into tip/locking or are you waiting for some
more feedback or things to resolve?

Thanks!
--
Michal Hocko
SUSE Labs

2016-04-12 15:40:27

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH 0/11] introduce down_write_killable for rw_semaphore v3

On Tue, Apr 12, 2016 at 11:37:08AM +0200, Michal Hocko wrote:
> Hi Ingo, Peter,
> do you plan to pull this into tip/locking or are you waiting for some
> more feedback or things to resolve?

I am planning to take it; but I'm traveling this week.

2016-04-12 18:01:42

by Michal Hocko

[permalink] [raw]
Subject: Re: [PATCH 0/11] introduce down_write_killable for rw_semaphore v3

On Tue 12-04-16 17:40:04, Peter Zijlstra wrote:
> On Tue, Apr 12, 2016 at 11:37:08AM +0200, Michal Hocko wrote:
> > Hi Ingo, Peter,
> > do you plan to pull this into tip/locking or are you waiting for some
> > more feedback or things to resolve?
>
> I am planning to take it; but I'm traveling this week.

OK, thanks!

--
Michal Hocko
SUSE Labs

2016-04-13 09:08:40

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable


* Michal Hocko <[email protected]> wrote:

> From: Michal Hocko <[email protected]>
>
> which uses the same fast path as __down_write except it falls back to
> call_rwsem_down_write_failed_killable slow path and return -EINTR if
> killed. To prevent from code duplication extract the skeleton of
> __down_write into a helper macro which just takes the semaphore
> and the slow path function to be called.
>
> Signed-off-by: Michal Hocko <[email protected]>
> ---
> arch/x86/include/asm/rwsem.h | 41 ++++++++++++++++++++++++++++-------------
> arch/x86/lib/rwsem.S | 8 ++++++++
> 2 files changed, 36 insertions(+), 13 deletions(-)
>
> diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
> index d79a218675bc..4c3d90dbe89a 100644
> --- a/arch/x86/include/asm/rwsem.h
> +++ b/arch/x86/include/asm/rwsem.h
> @@ -99,21 +99,36 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
> /*
> * lock for writing
> */
> +#define ____down_write(sem, slow_path) \
> +({ \
> + long tmp; \
> + struct rw_semaphore* ret = sem; \
> + asm volatile("# beginning down_write\n\t" \
> + LOCK_PREFIX " xadd %1,(%2)\n\t" \
> + /* adds 0xffff0001, returns the old value */ \
> + " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" \
> + /* was the active mask 0 before? */\
> + " jz 1f\n" \
> + " call " slow_path "\n" \
> + "1:\n" \
> + "# ending down_write" \
> + : "+m" (sem->count), "=d" (tmp), "+a" (ret) \
> + : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
> + : "memory", "cc"); \
> + ret; \
> +})
> +
> static inline void __down_write(struct rw_semaphore *sem)
> {
> - long tmp;
> - asm volatile("# beginning down_write\n\t"
> - LOCK_PREFIX " xadd %1,(%2)\n\t"
> - /* adds 0xffff0001, returns the old value */
> - " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t"
> - /* was the active mask 0 before? */
> - " jz 1f\n"
> - " call call_rwsem_down_write_failed\n"
> - "1:\n"
> - "# ending down_write"
> - : "+m" (sem->count), "=d" (tmp)
> - : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS)
> - : "memory", "cc");
> + ____down_write(sem, "call_rwsem_down_write_failed");
> +}
> +
> +static inline int __down_write_killable(struct rw_semaphore *sem)
> +{
> + if (IS_ERR(____down_write(sem, "call_rwsem_down_write_failed_killable")))
> + return -EINTR;
> +
> + return 0;
> }
>
> /*
> diff --git a/arch/x86/lib/rwsem.S b/arch/x86/lib/rwsem.S
> index 40027db99140..d1a1397e1fb3 100644
> --- a/arch/x86/lib/rwsem.S
> +++ b/arch/x86/lib/rwsem.S
> @@ -101,6 +101,14 @@ ENTRY(call_rwsem_down_write_failed)
> ret
> ENDPROC(call_rwsem_down_write_failed)
>
> +ENTRY(call_rwsem_down_write_failed_killable)
> + save_common_regs
> + movq %rax,%rdi
> + call rwsem_down_write_failed_killable
> + restore_common_regs
> + ret
> +ENDPROC(call_rwsem_down_write_failed_killable)

Got this objtool warning on x86-64 allyesconfig:

arch/x86/lib/rwsem.o: warning: objtool: call_rwsem_down_write_failed_killable()+0xe: call without frame pointer save/setup

Thanks,

Ingo

2016-04-13 09:16:35

by Michal Hocko

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On Wed 13-04-16 11:08:30, Ingo Molnar wrote:
>
> * Michal Hocko <[email protected]> wrote:
[...]
> > +ENTRY(call_rwsem_down_write_failed_killable)
> > + save_common_regs
> > + movq %rax,%rdi
> > + call rwsem_down_write_failed_killable
> > + restore_common_regs
> > + ret
> > +ENDPROC(call_rwsem_down_write_failed_killable)
>
> Got this objtool warning on x86-64 allyesconfig:
>
> arch/x86/lib/rwsem.o: warning: objtool: call_rwsem_down_write_failed_killable()+0xe: call without frame pointer save/setup

Peter has already pointed that out. This is because the 4.5 which I was
basing my work on doesn't have 3387a535ce62 ("x86/asm: Create stack
frames in rwsem functions") which shown up in 4.6-rc1. He mentioned to
add the missing FRAME_{BEGIN,END} during the merge AFAIR.

Does that sound reasonable to you or should I rebase?

--
Michal Hocko
SUSE Labs

2016-04-13 09:19:54

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable


* Michal Hocko <[email protected]> wrote:

> On Wed 13-04-16 11:08:30, Ingo Molnar wrote:
> >
> > * Michal Hocko <[email protected]> wrote:
> [...]
> > > +ENTRY(call_rwsem_down_write_failed_killable)
> > > + save_common_regs
> > > + movq %rax,%rdi
> > > + call rwsem_down_write_failed_killable
> > > + restore_common_regs
> > > + ret
> > > +ENDPROC(call_rwsem_down_write_failed_killable)
> >
> > Got this objtool warning on x86-64 allyesconfig:
> >
> > arch/x86/lib/rwsem.o: warning: objtool: call_rwsem_down_write_failed_killable()+0xe: call without frame pointer save/setup
>
> Peter has already pointed that out. This is because the 4.5 which I was
> basing my work on doesn't have 3387a535ce62 ("x86/asm: Create stack
> frames in rwsem functions") which shown up in 4.6-rc1. He mentioned to
> add the missing FRAME_{BEGIN,END} during the merge AFAIR.
>
> Does that sound reasonable to you or should I rebase?

I'm testing your patches today, if they are otherwise OK then please send a delta
patch against the tip:locking/rwsem tree I'll push out.

Thanks,

Ingo

2016-04-13 09:57:23

by Michal Hocko

[permalink] [raw]
Subject: [PATCH] x86: add frame annotation for call_rwsem_down_write_failed_killable

From: Michal Hocko <[email protected]>

3387a535ce62 ("x86/asm: Create stack frames in rwsem functions") has
added FRAME_{BEGIN,END} annotations to rwsem asm stubs. The patch
which has added call_rwsem_down_write_failed_killable was based on an
older tree so it didn't know about annotations. Let's add them.

Reported-by: Ingo Molnar <[email protected]>
Signed-off-by: Michal Hocko <[email protected]>
---

Hi Ingo,
please apply this on top of [1] when merging to tip/locking/rwsem.
Thanks!

[1] http://lkml.kernel.org/r/[email protected]
arch/x86/lib/rwsem.S | 2 ++
1 file changed, 2 insertions(+)

diff --git a/arch/x86/lib/rwsem.S b/arch/x86/lib/rwsem.S
index 4534a7e912f3..a37462a23546 100644
--- a/arch/x86/lib/rwsem.S
+++ b/arch/x86/lib/rwsem.S
@@ -107,10 +107,12 @@ ENTRY(call_rwsem_down_write_failed)
ENDPROC(call_rwsem_down_write_failed)

ENTRY(call_rwsem_down_write_failed_killable)
+ FRAME_BEGIN
save_common_regs
movq %rax,%rdi
call rwsem_down_write_failed_killable
restore_common_regs
+ FRAME_END
ret
ENDPROC(call_rwsem_down_write_failed_killable)

--
2.8.0.rc3

2016-04-13 10:27:46

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable


* Ingo Molnar <[email protected]> wrote:

> I'm testing your patches today, if they are otherwise OK [...]

got this build failure:

./arch/x86/include/asm/rwsem.h:106:2: error: ‘asm’ operand has impossible constraints

with the attached config and with:

gcc version 5.3.1 20151207 (Red Hat 5.3.1-2) (GCC)

Please send a delta patch for this bug too - I'll squash the fix into the
originating commit.

Thanks,

Ingo


Attachments:
(No filename) (428.00 B)
config (120.17 kB)
Download all attachments
Subject: [tip:locking/rwsem] locking/rwsem: Get rid of __down_write_nested()

Commit-ID: f8e04d854506ddfeba9cb41b601972b28521f104
Gitweb: http://git.kernel.org/tip/f8e04d854506ddfeba9cb41b601972b28521f104
Author: Michal Hocko <[email protected]>
AuthorDate: Thu, 7 Apr 2016 17:12:21 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Wed, 13 Apr 2016 10:42:16 +0200

locking/rwsem: Get rid of __down_write_nested()

This is no longer used anywhere and all callers (__down_write()) use
0 as a subclass. Ditch __down_write_nested() to make the code easier
to follow.

This shouldn't introduce any functional change.

Signed-off-by: Michal Hocko <[email protected]>
Acked-by: Davidlohr Bueso <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Chris Zankel <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Signed-off-by: Davidlohr Bueso <[email protected]>
Cc: Signed-off-by: Jason Low <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
arch/s390/include/asm/rwsem.h | 7 +------
arch/sh/include/asm/rwsem.h | 5 -----
arch/sparc/include/asm/rwsem.h | 7 +------
arch/x86/include/asm/rwsem.h | 7 +------
include/asm-generic/rwsem.h | 7 +------
include/linux/rwsem-spinlock.h | 1 -
kernel/locking/rwsem-spinlock.c | 7 +------
7 files changed, 5 insertions(+), 36 deletions(-)

diff --git a/arch/s390/include/asm/rwsem.h b/arch/s390/include/asm/rwsem.h
index fead491..555d23b 100644
--- a/arch/s390/include/asm/rwsem.h
+++ b/arch/s390/include/asm/rwsem.h
@@ -90,7 +90,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
+static inline void __down_write(struct rw_semaphore *sem)
{
signed long old, new, tmp;

@@ -108,11 +108,6 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
rwsem_down_write_failed(sem);
}

-static inline void __down_write(struct rw_semaphore *sem)
-{
- __down_write_nested(sem, 0);
-}
-
/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/
diff --git a/arch/sh/include/asm/rwsem.h b/arch/sh/include/asm/rwsem.h
index edab572..a5104be 100644
--- a/arch/sh/include/asm/rwsem.h
+++ b/arch/sh/include/asm/rwsem.h
@@ -114,11 +114,6 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
rwsem_downgrade_wake(sem);
}

-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
-{
- __down_write(sem);
-}
-
/*
* implement exchange and add functionality
*/
diff --git a/arch/sparc/include/asm/rwsem.h b/arch/sparc/include/asm/rwsem.h
index 069bf4d..e5a0d57 100644
--- a/arch/sparc/include/asm/rwsem.h
+++ b/arch/sparc/include/asm/rwsem.h
@@ -45,7 +45,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
+static inline void __down_write(struct rw_semaphore *sem)
{
long tmp;

@@ -55,11 +55,6 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
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;
diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
index ceec86eb..4a8292a 100644
--- a/arch/x86/include/asm/rwsem.h
+++ b/arch/x86/include/asm/rwsem.h
@@ -99,7 +99,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
+static inline void __down_write(struct rw_semaphore *sem)
{
long tmp;
asm volatile("# beginning down_write\n\t"
@@ -116,11 +116,6 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
: "memory", "cc");
}

-static inline void __down_write(struct rw_semaphore *sem)
-{
- __down_write_nested(sem, 0);
-}
-
/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/
diff --git a/include/asm-generic/rwsem.h b/include/asm-generic/rwsem.h
index d6d5dc9..b8d8a6c 100644
--- a/include/asm-generic/rwsem.h
+++ b/include/asm-generic/rwsem.h
@@ -53,7 +53,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
-static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
+static inline void __down_write(struct rw_semaphore *sem)
{
long tmp;

@@ -63,11 +63,6 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
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;
diff --git a/include/linux/rwsem-spinlock.h b/include/linux/rwsem-spinlock.h
index 561e861..a733a54 100644
--- a/include/linux/rwsem-spinlock.h
+++ b/include/linux/rwsem-spinlock.h
@@ -34,7 +34,6 @@ struct rw_semaphore {
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 void __down_write_nested(struct rw_semaphore *sem, int subclass);
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);
diff --git a/kernel/locking/rwsem-spinlock.c b/kernel/locking/rwsem-spinlock.c
index 3a50485..bab2610 100644
--- a/kernel/locking/rwsem-spinlock.c
+++ b/kernel/locking/rwsem-spinlock.c
@@ -191,7 +191,7 @@ int __down_read_trylock(struct rw_semaphore *sem)
/*
* get a write lock on the semaphore
*/
-void __sched __down_write_nested(struct rw_semaphore *sem, int subclass)
+void __sched __down_write(struct rw_semaphore *sem)
{
struct rwsem_waiter waiter;
struct task_struct *tsk;
@@ -227,11 +227,6 @@ void __sched __down_write_nested(struct rw_semaphore *sem, int subclass)
raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
}

-void __sched __down_write(struct rw_semaphore *sem)
-{
- __down_write_nested(sem, 0);
-}
-
/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/

Subject: [tip:locking/rwsem] locking/rwsem, sparc: Drop superfluous arch specific implementation

Commit-ID: 938072e32ce13e5537ef001cdabcb8a6932b09a0
Gitweb: http://git.kernel.org/tip/938072e32ce13e5537ef001cdabcb8a6932b09a0
Author: Michal Hocko <[email protected]>
AuthorDate: Thu, 7 Apr 2016 17:12:25 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Wed, 13 Apr 2016 10:42:19 +0200

locking/rwsem, sparc: Drop superfluous arch specific implementation

sparc basically reuses the generic implementation of rwsem so we can
reuse the code rather than duplicate it.

Signed-off-by: Michal Hocko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Chris Zankel <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Signed-off-by: Davidlohr Bueso <[email protected]>
Cc: Signed-off-by: Jason Low <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
arch/sparc/include/asm/Kbuild | 1 +
arch/sparc/include/asm/rwsem.h | 119 -----------------------------------------
2 files changed, 1 insertion(+), 119 deletions(-)

diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index e9286188..6024c26 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -16,6 +16,7 @@ generic-y += mm-arch-hooks.h
generic-y += module.h
generic-y += mutex.h
generic-y += preempt.h
+generic-y += rwsem.h
generic-y += serial.h
generic-y += trace_clock.h
generic-y += types.h
diff --git a/arch/sparc/include/asm/rwsem.h b/arch/sparc/include/asm/rwsem.h
deleted file mode 100644
index e5a0d57..0000000
--- a/arch/sparc/include/asm/rwsem.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * rwsem.h: R/W semaphores implemented using CAS
- *
- * Written by David S. Miller ([email protected]), 2001.
- * Derived from asm-i386/rwsem.h
- */
-#ifndef _SPARC64_RWSEM_H
-#define _SPARC64_RWSEM_H
-
-#ifndef _LINUX_RWSEM_H
-#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
-#endif
-
-#ifdef __KERNEL__
-
-#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)
-
-/*
- * 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(struct rw_semaphore *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 __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 = 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)
-{
- return atomic64_add_return(delta, (atomic64_t *)(&sem->count));
-}
-
-#endif /* __KERNEL__ */
-
-#endif /* _SPARC64_RWSEM_H */

Subject: [tip:locking/rwsem] locking/rwsem: Drop explicit memory barriers

Commit-ID: 2e927c6422fea5ce36b24b00c2c84f2e9ead31b6
Gitweb: http://git.kernel.org/tip/2e927c6422fea5ce36b24b00c2c84f2e9ead31b6
Author: Michal Hocko <[email protected]>
AuthorDate: Thu, 7 Apr 2016 17:12:22 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Wed, 13 Apr 2016 10:42:18 +0200

locking/rwsem: Drop explicit memory barriers

sh and xtensa seem to be the only architectures which use explicit
memory barriers for rw_semaphore operations even though they are not
really needed because there is the full memory barrier is always implied
by atomic_{inc,dec,add,sub}_return() resp. cmpxchg(). Remove them.

Signed-off-by: Michal Hocko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Chris Zankel <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Signed-off-by: Davidlohr Bueso <[email protected]>
Cc: Signed-off-by: Jason Low <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
arch/sh/include/asm/rwsem.h | 14 ++------------
arch/xtensa/include/asm/rwsem.h | 14 ++------------
2 files changed, 4 insertions(+), 24 deletions(-)

diff --git a/arch/sh/include/asm/rwsem.h b/arch/sh/include/asm/rwsem.h
index a5104be..f6c951c 100644
--- a/arch/sh/include/asm/rwsem.h
+++ b/arch/sh/include/asm/rwsem.h
@@ -24,9 +24,7 @@
*/
static inline void __down_read(struct rw_semaphore *sem)
{
- if (atomic_inc_return((atomic_t *)(&sem->count)) > 0)
- smp_wmb();
- else
+ if (atomic_inc_return((atomic_t *)(&sem->count)) <= 0)
rwsem_down_read_failed(sem);
}

@@ -37,7 +35,6 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
while ((tmp = sem->count) >= 0) {
if (tmp == cmpxchg(&sem->count, tmp,
tmp + RWSEM_ACTIVE_READ_BIAS)) {
- smp_wmb();
return 1;
}
}
@@ -53,9 +50,7 @@ static inline void __down_write(struct rw_semaphore *sem)

tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
(atomic_t *)(&sem->count));
- if (tmp == RWSEM_ACTIVE_WRITE_BIAS)
- smp_wmb();
- else
+ if (tmp != RWSEM_ACTIVE_WRITE_BIAS)
rwsem_down_write_failed(sem);
}

@@ -65,7 +60,6 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)

tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
RWSEM_ACTIVE_WRITE_BIAS);
- smp_wmb();
return tmp == RWSEM_UNLOCKED_VALUE;
}

@@ -76,7 +70,6 @@ static inline void __up_read(struct rw_semaphore *sem)
{
int tmp;

- smp_wmb();
tmp = atomic_dec_return((atomic_t *)(&sem->count));
if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
rwsem_wake(sem);
@@ -87,7 +80,6 @@ static inline void __up_read(struct rw_semaphore *sem)
*/
static inline void __up_write(struct rw_semaphore *sem)
{
- smp_wmb();
if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
(atomic_t *)(&sem->count)) < 0)
rwsem_wake(sem);
@@ -108,7 +100,6 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
{
int tmp;

- smp_wmb();
tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
if (tmp < 0)
rwsem_downgrade_wake(sem);
@@ -119,7 +110,6 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
*/
static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
{
- smp_mb();
return atomic_add_return(delta, (atomic_t *)(&sem->count));
}

diff --git a/arch/xtensa/include/asm/rwsem.h b/arch/xtensa/include/asm/rwsem.h
index 249619e..593483f 100644
--- a/arch/xtensa/include/asm/rwsem.h
+++ b/arch/xtensa/include/asm/rwsem.h
@@ -29,9 +29,7 @@
*/
static inline void __down_read(struct rw_semaphore *sem)
{
- if (atomic_add_return(1,(atomic_t *)(&sem->count)) > 0)
- smp_wmb();
- else
+ if (atomic_add_return(1,(atomic_t *)(&sem->count)) <= 0)
rwsem_down_read_failed(sem);
}

@@ -42,7 +40,6 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
while ((tmp = sem->count) >= 0) {
if (tmp == cmpxchg(&sem->count, tmp,
tmp + RWSEM_ACTIVE_READ_BIAS)) {
- smp_wmb();
return 1;
}
}
@@ -58,9 +55,7 @@ static inline void __down_write(struct rw_semaphore *sem)

tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
(atomic_t *)(&sem->count));
- if (tmp == RWSEM_ACTIVE_WRITE_BIAS)
- smp_wmb();
- else
+ if (tmp != RWSEM_ACTIVE_WRITE_BIAS)
rwsem_down_write_failed(sem);
}

@@ -70,7 +65,6 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)

tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
RWSEM_ACTIVE_WRITE_BIAS);
- smp_wmb();
return tmp == RWSEM_UNLOCKED_VALUE;
}

@@ -81,7 +75,6 @@ static inline void __up_read(struct rw_semaphore *sem)
{
int tmp;

- smp_wmb();
tmp = atomic_sub_return(1,(atomic_t *)(&sem->count));
if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
rwsem_wake(sem);
@@ -92,7 +85,6 @@ static inline void __up_read(struct rw_semaphore *sem)
*/
static inline void __up_write(struct rw_semaphore *sem)
{
- smp_wmb();
if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
(atomic_t *)(&sem->count)) < 0)
rwsem_wake(sem);
@@ -113,7 +105,6 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
{
int tmp;

- smp_wmb();
tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
if (tmp < 0)
rwsem_downgrade_wake(sem);
@@ -124,7 +115,6 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
*/
static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
{
- smp_mb();
return atomic_add_return(delta, (atomic_t *)(&sem->count));
}


Subject: [tip:locking/rwsem] locking/rwsem, xtensa: Drop superfluous arch specific implementation

Commit-ID: 3aa2591dc2ea292d068dc3a263f1976806c2c281
Gitweb: http://git.kernel.org/tip/3aa2591dc2ea292d068dc3a263f1976806c2c281
Author: Michal Hocko <[email protected]>
AuthorDate: Thu, 7 Apr 2016 17:12:23 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Wed, 13 Apr 2016 10:42:18 +0200

locking/rwsem, xtensa: Drop superfluous arch specific implementation

Since "locking, rwsem: drop explicit memory barriers" the arch specific
code is basically same as the the generic one so we can drop the
superfluous code.

Suggested-by: Davidlohr Bueso <[email protected]>
Signed-off-by: Michal Hocko <[email protected]>
Acked-by: Max Filippov <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Chris Zankel <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Signed-off-by: Davidlohr Bueso <[email protected]>
Cc: Signed-off-by: Jason Low <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
arch/xtensa/include/asm/Kbuild | 1 +
arch/xtensa/include/asm/rwsem.h | 121 ----------------------------------------
2 files changed, 1 insertion(+), 121 deletions(-)

diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild
index b56855a..28cf4c5 100644
--- a/arch/xtensa/include/asm/Kbuild
+++ b/arch/xtensa/include/asm/Kbuild
@@ -22,6 +22,7 @@ generic-y += mm-arch-hooks.h
generic-y += percpu.h
generic-y += preempt.h
generic-y += resource.h
+generic-y += rwsem.h
generic-y += sections.h
generic-y += siginfo.h
generic-y += statfs.h
diff --git a/arch/xtensa/include/asm/rwsem.h b/arch/xtensa/include/asm/rwsem.h
deleted file mode 100644
index 593483f..0000000
--- a/arch/xtensa/include/asm/rwsem.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * include/asm-xtensa/rwsem.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Largely copied from include/asm-ppc/rwsem.h
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
-
-#ifndef _XTENSA_RWSEM_H
-#define _XTENSA_RWSEM_H
-
-#ifndef _LINUX_RWSEM_H
-#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
-#endif
-
-#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)
-
-/*
- * lock for reading
- */
-static inline void __down_read(struct rw_semaphore *sem)
-{
- if (atomic_add_return(1,(atomic_t *)(&sem->count)) <= 0)
- rwsem_down_read_failed(sem);
-}
-
-static inline int __down_read_trylock(struct rw_semaphore *sem)
-{
- int 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(struct rw_semaphore *sem)
-{
- int tmp;
-
- tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
- (atomic_t *)(&sem->count));
- if (tmp != RWSEM_ACTIVE_WRITE_BIAS)
- rwsem_down_write_failed(sem);
-}
-
-static inline int __down_write_trylock(struct rw_semaphore *sem)
-{
- int 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)
-{
- int tmp;
-
- tmp = atomic_sub_return(1,(atomic_t *)(&sem->count));
- if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
- rwsem_wake(sem);
-}
-
-/*
- * unlock after writing
- */
-static inline void __up_write(struct rw_semaphore *sem)
-{
- if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
- (atomic_t *)(&sem->count)) < 0)
- rwsem_wake(sem);
-}
-
-/*
- * implement atomic add functionality
- */
-static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
-{
- atomic_add(delta, (atomic_t *)(&sem->count));
-}
-
-/*
- * downgrade write lock to read lock
- */
-static inline void __downgrade_write(struct rw_semaphore *sem)
-{
- int tmp;
-
- tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
- if (tmp < 0)
- rwsem_downgrade_wake(sem);
-}
-
-/*
- * implement exchange and add functionality
- */
-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
-{
- return atomic_add_return(delta, (atomic_t *)(&sem->count));
-}
-
-#endif /* _XTENSA_RWSEM_H */

Subject: [tip:locking/rwsem] locking/rwsem, sh: Drop superfluous arch specific implementation

Commit-ID: e4a2b01ed3d1591437f93a42f6c4c039b60e0c0a
Gitweb: http://git.kernel.org/tip/e4a2b01ed3d1591437f93a42f6c4c039b60e0c0a
Author: Michal Hocko <[email protected]>
AuthorDate: Thu, 7 Apr 2016 17:12:24 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Wed, 13 Apr 2016 10:42:19 +0200

locking/rwsem, sh: Drop superfluous arch specific implementation

Since "locking, rwsem: drop explicit memory barriers" the arch specific
code is basically same as the the generic one so we can drop the
superfluous code.

Suggested-by: Davidlohr Bueso <[email protected]>
Signed-off-by: Michal Hocko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Chris Zankel <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Signed-off-by: Davidlohr Bueso <[email protected]>
Cc: Signed-off-by: Jason Low <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
arch/sh/include/asm/Kbuild | 1 +
arch/sh/include/asm/rwsem.h | 117 --------------------------------------------
2 files changed, 1 insertion(+), 117 deletions(-)

diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild
index a319745..751c337 100644
--- a/arch/sh/include/asm/Kbuild
+++ b/arch/sh/include/asm/Kbuild
@@ -26,6 +26,7 @@ generic-y += percpu.h
generic-y += poll.h
generic-y += preempt.h
generic-y += resource.h
+generic-y += rwsem.h
generic-y += sembuf.h
generic-y += serial.h
generic-y += shmbuf.h
diff --git a/arch/sh/include/asm/rwsem.h b/arch/sh/include/asm/rwsem.h
deleted file mode 100644
index f6c951c..0000000
--- a/arch/sh/include/asm/rwsem.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * include/asm-sh/rwsem.h: R/W semaphores for SH using the stuff
- * in lib/rwsem.c.
- */
-
-#ifndef _ASM_SH_RWSEM_H
-#define _ASM_SH_RWSEM_H
-
-#ifndef _LINUX_RWSEM_H
-#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
-#endif
-
-#ifdef __KERNEL__
-
-#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)
-
-/*
- * lock for reading
- */
-static inline void __down_read(struct rw_semaphore *sem)
-{
- if (atomic_inc_return((atomic_t *)(&sem->count)) <= 0)
- rwsem_down_read_failed(sem);
-}
-
-static inline int __down_read_trylock(struct rw_semaphore *sem)
-{
- int 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(struct rw_semaphore *sem)
-{
- int tmp;
-
- tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
- (atomic_t *)(&sem->count));
- if (tmp != RWSEM_ACTIVE_WRITE_BIAS)
- rwsem_down_write_failed(sem);
-}
-
-static inline int __down_write_trylock(struct rw_semaphore *sem)
-{
- int 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)
-{
- int tmp;
-
- tmp = atomic_dec_return((atomic_t *)(&sem->count));
- if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
- rwsem_wake(sem);
-}
-
-/*
- * unlock after writing
- */
-static inline void __up_write(struct rw_semaphore *sem)
-{
- if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
- (atomic_t *)(&sem->count)) < 0)
- rwsem_wake(sem);
-}
-
-/*
- * implement atomic add functionality
- */
-static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
-{
- atomic_add(delta, (atomic_t *)(&sem->count));
-}
-
-/*
- * downgrade write lock to read lock
- */
-static inline void __downgrade_write(struct rw_semaphore *sem)
-{
- int tmp;
-
- tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
- if (tmp < 0)
- rwsem_downgrade_wake(sem);
-}
-
-/*
- * implement exchange and add functionality
- */
-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
-{
- return atomic_add_return(delta, (atomic_t *)(&sem->count));
-}
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_SH_RWSEM_H */

Subject: [tip:locking/rwsem] locking/rwsem: Introduce basis for down_write_killable()

Commit-ID: d47996082f52baa0ca8b48d26b3cbef5ede70a73
Gitweb: http://git.kernel.org/tip/d47996082f52baa0ca8b48d26b3cbef5ede70a73
Author: Michal Hocko <[email protected]>
AuthorDate: Thu, 7 Apr 2016 17:12:26 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Wed, 13 Apr 2016 10:42:20 +0200

locking/rwsem: Introduce basis for down_write_killable()

Introduce a generic implementation necessary for down_write_killable().

This is a trivial extension of the already existing down_write() call
which can be interrupted by SIGKILL. This patch doesn't provide
down_write_killable() yet because arches have to provide the necessary
pieces before.

rwsem_down_write_failed() which is a generic slow path for the
write lock is extended to take a task state and renamed to
__rwsem_down_write_failed_common(). The return value is either a valid
semaphore pointer or ERR_PTR(-EINTR).

rwsem_down_write_failed_killable() is exported as a new way to wait for
the lock and be killable.

For rwsem-spinlock implementation the current __down_write() it updated
in a similar way as __rwsem_down_write_failed_common() except it doesn't
need new exports just visible __down_write_killable().

Architectures which are not using the generic rwsem implementation are
supposed to provide their __down_write_killable() implementation and
use rwsem_down_write_failed_killable() for the slow path.

Signed-off-by: Michal Hocko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Chris Zankel <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Signed-off-by: Davidlohr Bueso <[email protected]>
Cc: Signed-off-by: Jason Low <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
include/asm-generic/rwsem.h | 12 ++++++++++++
include/linux/rwsem-spinlock.h | 1 +
include/linux/rwsem.h | 2 ++
kernel/locking/rwsem-spinlock.c | 22 ++++++++++++++++++++--
kernel/locking/rwsem-xadd.c | 31 +++++++++++++++++++++++++------
5 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/include/asm-generic/rwsem.h b/include/asm-generic/rwsem.h
index b8d8a6c..3fc94a0 100644
--- a/include/asm-generic/rwsem.h
+++ b/include/asm-generic/rwsem.h
@@ -63,6 +63,18 @@ static inline void __down_write(struct rw_semaphore *sem)
rwsem_down_write_failed(sem);
}

+static inline int __down_write_killable(struct rw_semaphore *sem)
+{
+ long tmp;
+
+ tmp = atomic_long_add_return_acquire(RWSEM_ACTIVE_WRITE_BIAS,
+ (atomic_long_t *)&sem->count);
+ if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
+ if (IS_ERR(rwsem_down_write_failed_killable(sem)))
+ return -EINTR;
+ return 0;
+}
+
static inline int __down_write_trylock(struct rw_semaphore *sem)
{
long tmp;
diff --git a/include/linux/rwsem-spinlock.h b/include/linux/rwsem-spinlock.h
index a733a54..ae0528b 100644
--- a/include/linux/rwsem-spinlock.h
+++ b/include/linux/rwsem-spinlock.h
@@ -34,6 +34,7 @@ struct rw_semaphore {
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 __must_check __down_write_killable(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);
diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
index 8f498cd..7d7ae02 100644
--- a/include/linux/rwsem.h
+++ b/include/linux/rwsem.h
@@ -14,6 +14,7 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/atomic.h>
+#include <linux/err.h>
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
#include <linux/osq_lock.h>
#endif
@@ -43,6 +44,7 @@ struct rw_semaphore {

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_down_write_failed_killable(struct rw_semaphore *sem);
extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);

diff --git a/kernel/locking/rwsem-spinlock.c b/kernel/locking/rwsem-spinlock.c
index bab2610..1591f6b 100644
--- a/kernel/locking/rwsem-spinlock.c
+++ b/kernel/locking/rwsem-spinlock.c
@@ -191,11 +191,12 @@ int __down_read_trylock(struct rw_semaphore *sem)
/*
* get a write lock on the semaphore
*/
-void __sched __down_write(struct rw_semaphore *sem)
+int __sched __down_write_common(struct rw_semaphore *sem, int state)
{
struct rwsem_waiter waiter;
struct task_struct *tsk;
unsigned long flags;
+ int ret = 0;

raw_spin_lock_irqsave(&sem->wait_lock, flags);

@@ -215,16 +216,33 @@ void __sched __down_write(struct rw_semaphore *sem)
*/
if (sem->count == 0)
break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (signal_pending_state(state, current)) {
+ ret = -EINTR;
+ goto out;
+ }
+ set_task_state(tsk, state);
raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
schedule();
raw_spin_lock_irqsave(&sem->wait_lock, flags);
}
/* got the lock */
sem->count = -1;
+out:
list_del(&waiter.list);

raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
+
+ return ret;
+}
+
+void __sched __down_write(struct rw_semaphore *sem)
+{
+ __down_write_common(sem, TASK_UNINTERRUPTIBLE);
+}
+
+int __sched __down_write_killable(struct rw_semaphore *sem)
+{
+ return __down_write_common(sem, TASK_KILLABLE);
}

/*
diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c
index a4d4de0..df4dcb8 100644
--- a/kernel/locking/rwsem-xadd.c
+++ b/kernel/locking/rwsem-xadd.c
@@ -433,12 +433,13 @@ static inline bool rwsem_has_spinner(struct rw_semaphore *sem)
/*
* Wait until we successfully acquire the write lock
*/
-__visible
-struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
+static inline struct rw_semaphore *
+__rwsem_down_write_failed_common(struct rw_semaphore *sem, int state)
{
long count;
bool waiting = true; /* any queued threads before us */
struct rwsem_waiter waiter;
+ struct rw_semaphore *ret = sem;

/* undo write bias from down_write operation, stop active locking */
count = rwsem_atomic_update(-RWSEM_ACTIVE_WRITE_BIAS, sem);
@@ -478,7 +479,7 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)
count = rwsem_atomic_update(RWSEM_WAITING_BIAS, sem);

/* wait until we successfully acquire the lock */
- set_current_state(TASK_UNINTERRUPTIBLE);
+ set_current_state(state);
while (true) {
if (rwsem_try_write_lock(count, sem))
break;
@@ -486,21 +487,39 @@ struct rw_semaphore __sched *rwsem_down_write_failed(struct rw_semaphore *sem)

/* Block until there are no active lockers. */
do {
+ if (signal_pending_state(state, current)) {
+ raw_spin_lock_irq(&sem->wait_lock);
+ ret = ERR_PTR(-EINTR);
+ goto out;
+ }
schedule();
- set_current_state(TASK_UNINTERRUPTIBLE);
+ set_current_state(state);
} while ((count = sem->count) & RWSEM_ACTIVE_MASK);

raw_spin_lock_irq(&sem->wait_lock);
}
+out:
__set_current_state(TASK_RUNNING);
-
list_del(&waiter.list);
raw_spin_unlock_irq(&sem->wait_lock);

- return sem;
+ return ret;
+}
+
+__visible struct rw_semaphore * __sched
+rwsem_down_write_failed(struct rw_semaphore *sem)
+{
+ return __rwsem_down_write_failed_common(sem, TASK_UNINTERRUPTIBLE);
}
EXPORT_SYMBOL(rwsem_down_write_failed);

+__visible struct rw_semaphore * __sched
+rwsem_down_write_failed_killable(struct rw_semaphore *sem)
+{
+ return __rwsem_down_write_failed_common(sem, TASK_KILLABLE);
+}
+EXPORT_SYMBOL(rwsem_down_write_failed_killable);
+
/*
* handle waking up a waiter on the semaphore
* - up_read/up_write has decremented the active part of count if we come here

2016-04-13 12:49:56

by Michal Hocko

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On Wed 13-04-16 12:27:31, Ingo Molnar wrote:
>
> * Ingo Molnar <[email protected]> wrote:
>
> > I'm testing your patches today, if they are otherwise OK [...]
>
> got this build failure:
>
> ./arch/x86/include/asm/rwsem.h:106:2: error: ‘asm’ operand has impossible constraints

Hmm, I have no idea why 64b didn't have problem with the asm but 32b
complains. Anyway, the following makes both happy. I have checked the
generated code for 64b and it hasn't changed after the patch. 32b also
seems to be generating a proper code. My gcc asm()-foo is rather weak so
I would feel better if somebody double checked after me.
---
>From d23f4e6994670bf2c5d864f2190f21022b4499b2 Mon Sep 17 00:00:00 2001
From: Michal Hocko <[email protected]>
Date: Wed, 13 Apr 2016 14:21:25 +0200
Subject: [PATCH] x86: __down_read_trylock fix 32b build failure
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Ingo has noticed the following compilation error with CONFIG_X86_32=y
./arch/x86/include/asm/rwsem.h:106:2: error: ‘asm’ operand has impossible constraints

The reason seems to be that 32b doesn't like ret being input and output
argument sharing the same register with sem which is only the input. Fix
this by making ret output only and use %3 (aka sem) for xadd.

ret initialization is not needed now because this is done implicitly
by the asm even for the fast path as both sem and ret share the same
register.

Reported-by: Ingo Molnar <[email protected]>
Signed-off-by: Michal Hocko <[email protected]>
---
arch/x86/include/asm/rwsem.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
index d759c5f70f49..453744c1d347 100644
--- a/arch/x86/include/asm/rwsem.h
+++ b/arch/x86/include/asm/rwsem.h
@@ -102,9 +102,9 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
#define ____down_write(sem, slow_path) \
({ \
long tmp; \
- struct rw_semaphore* ret = sem; \
+ struct rw_semaphore* ret; \
asm volatile("# beginning down_write\n\t" \
- LOCK_PREFIX " xadd %1,(%2)\n\t" \
+ LOCK_PREFIX " xadd %1,(%3)\n\t" \
/* adds 0xffff0001, returns the old value */ \
" test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" \
/* was the active mask 0 before? */\
@@ -112,7 +112,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
" call " slow_path "\n" \
"1:\n" \
"# ending down_write" \
- : "+m" (sem->count), "=d" (tmp), "+a" (ret) \
+ : "+m" (sem->count), "=d" (tmp), "=a" (ret) \
: "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
: "memory", "cc"); \
ret; \
--
2.8.0.rc3

--
Michal Hocko
SUSE Labs

2016-04-17 16:59:31

by Michal Hocko

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On Wed 13-04-16 14:49:43, Michal Hocko wrote:
> On Wed 13-04-16 12:27:31, Ingo Molnar wrote:
> >
> > * Ingo Molnar <[email protected]> wrote:
> >
> > > I'm testing your patches today, if they are otherwise OK [...]
> >
> > got this build failure:
> >
> > ./arch/x86/include/asm/rwsem.h:106:2: error: ‘asm’ operand has impossible constraints
>
> Hmm, I have no idea why 64b didn't have problem with the asm but 32b
> complains. Anyway, the following makes both happy. I have checked the
> generated code for 64b and it hasn't changed after the patch. 32b also
> seems to be generating a proper code. My gcc asm()-foo is rather weak so
> I would feel better if somebody double checked after me.

Peter, Ingo, does the patch makes sense to you?
Thanks!

> ---
> From d23f4e6994670bf2c5d864f2190f21022b4499b2 Mon Sep 17 00:00:00 2001
> From: Michal Hocko <[email protected]>
> Date: Wed, 13 Apr 2016 14:21:25 +0200
> Subject: [PATCH] x86: __down_read_trylock fix 32b build failure
> MIME-Version: 1.0
> Content-Type: text/plain; charset=UTF-8
> Content-Transfer-Encoding: 8bit
>
> Ingo has noticed the following compilation error with CONFIG_X86_32=y
> ./arch/x86/include/asm/rwsem.h:106:2: error: ‘asm’ operand has impossible constraints
>
> The reason seems to be that 32b doesn't like ret being input and output
> argument sharing the same register with sem which is only the input. Fix
> this by making ret output only and use %3 (aka sem) for xadd.
>
> ret initialization is not needed now because this is done implicitly
> by the asm even for the fast path as both sem and ret share the same
> register.
>
> Reported-by: Ingo Molnar <[email protected]>
> Signed-off-by: Michal Hocko <[email protected]>
> ---
> arch/x86/include/asm/rwsem.h | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
> index d759c5f70f49..453744c1d347 100644
> --- a/arch/x86/include/asm/rwsem.h
> +++ b/arch/x86/include/asm/rwsem.h
> @@ -102,9 +102,9 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
> #define ____down_write(sem, slow_path) \
> ({ \
> long tmp; \
> - struct rw_semaphore* ret = sem; \
> + struct rw_semaphore* ret; \
> asm volatile("# beginning down_write\n\t" \
> - LOCK_PREFIX " xadd %1,(%2)\n\t" \
> + LOCK_PREFIX " xadd %1,(%3)\n\t" \
> /* adds 0xffff0001, returns the old value */ \
> " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" \
> /* was the active mask 0 before? */\
> @@ -112,7 +112,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
> " call " slow_path "\n" \
> "1:\n" \
> "# ending down_write" \
> - : "+m" (sem->count), "=d" (tmp), "+a" (ret) \
> + : "+m" (sem->count), "=d" (tmp), "=a" (ret) \
> : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
> : "memory", "cc"); \
> ret; \
> --
> 2.8.0.rc3
>
> --
> Michal Hocko
> SUSE Labs

--
Michal Hocko
SUSE Labs

2016-04-20 13:40:41

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On Wed, Apr 13, 2016 at 02:49:43PM +0200, Michal Hocko wrote:
> On Wed 13-04-16 12:27:31, Ingo Molnar wrote:
> >
> > * Ingo Molnar <[email protected]> wrote:
> >
> > > I'm testing your patches today, if they are otherwise OK [...]
> >
> > got this build failure:
> >
> > ./arch/x86/include/asm/rwsem.h:106:2: error: ‘asm’ operand has impossible constraints
>
> Hmm, I have no idea why 64b didn't have problem with the asm but 32b
> complains. Anyway, the following makes both happy. I have checked the
> generated code for 64b and it hasn't changed after the patch. 32b also
> seems to be generating a proper code. My gcc asm()-foo is rather weak so
> I would feel better if somebody double checked after me.

I completely blow at this gcc-asm constraints thing too :/

In any case, Ingo will you look after the rest of these patches, or do
you want me to pick up the remaining bits?

2016-04-20 18:05:21

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On April 20, 2016 6:40:19 AM PDT, Peter Zijlstra <[email protected]> wrote:
>On Wed, Apr 13, 2016 at 02:49:43PM +0200, Michal Hocko wrote:
>> On Wed 13-04-16 12:27:31, Ingo Molnar wrote:
>> >
>> > * Ingo Molnar <[email protected]> wrote:
>> >
>> > > I'm testing your patches today, if they are otherwise OK [...]
>> >
>> > got this build failure:
>> >
>> > ./arch/x86/include/asm/rwsem.h:106:2: error: ‘asm’ operand has
>impossible constraints
>>
>> Hmm, I have no idea why 64b didn't have problem with the asm but 32b
>> complains. Anyway, the following makes both happy. I have checked the
>> generated code for 64b and it hasn't changed after the patch. 32b
>also
>> seems to be generating a proper code. My gcc asm()-foo is rather weak
>so
>> I would feel better if somebody double checked after me.
>
>I completely blow at this gcc-asm constraints thing too :/
>
>In any case, Ingo will you look after the rest of these patches, or do
>you want me to pick up the remaining bits?

The reason it breaks is because the same register can't be an input-output register and a separate input. However, the input side of the input-output is probably undefined, and so gcc may not notice.
--
Sent from my Android device with K-9 Mail. Please excuse brevity and formatting.

2016-04-20 20:45:25

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On Wed, Apr 20, 2016 at 11:04:05AM -0700, H. Peter Anvin wrote:
> The reason it breaks is because the same register can't be an
> input-output register and a separate input. However, the input side of
> the input-output is probably undefined, and so gcc may not notice.

So Michal and I talked about this a while ago. Why do we need the '"a"
(sem)' input dependency if '"+a" (ret)' already supplies the same thing?

There's also that "=d" (tmp) thing which we don't really need as an
output, right?

I.e., can we simplify like this?

---
#define ____down_write(sem, slow_path) \
({ \
long tmp = RWSEM_ACTIVE_WRITE_BIAS; \
struct rw_semaphore* ret = sem; \
\
asm volatile("# beginning down_write\n\t" \
LOCK_PREFIX " xadd %[tmp],(%[ret])\n\t" \
/* adds 0xffff0001, returns the old value */ \
" test " __ASM_SEL(%w[tmp],%k[tmp]) "," __ASM_SEL(%w[tmp],%k[tmp]) "\n\t" \
/* was the active mask 0 before? */\
" jz 1f\n" \
" call " slow_path "\n" \
"1:\n" \
"# ending down_write" \
: "+m" (sem->count), [ret] "+a" (ret) \
: [tmp] "d" (tmp) \
: "memory", "cc"); \
ret; \
})

--
Regards/Gruss,
Boris.

ECO tip #101: Trim your mails when you reply.

2016-04-20 20:58:34

by Michal Hocko

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On Wed 20-04-16 22:45:01, Borislav Petkov wrote:
> On Wed, Apr 20, 2016 at 11:04:05AM -0700, H. Peter Anvin wrote:
> > The reason it breaks is because the same register can't be an
> > input-output register and a separate input. However, the input side of
> > the input-output is probably undefined, and so gcc may not notice.
>
> So Michal and I talked about this a while ago. Why do we need the '"a"
> (sem)' input dependency if '"+a" (ret)' already supplies the same thing?
>
> There's also that "=d" (tmp) thing which we don't really need as an
> output, right?
>
> I.e., can we simplify like this?

I am for any simplification, my gcc-asm-foo is just too weak and I
wanted my change to be as minimal as possible. So if you feel you can
clean up this I would more than welcome that. Maybe a follow up patch
would be a better approach so that we can check that the generated code
hasn't changed.

Thanks!
--
Michal Hocko
SUSE Labs

2016-04-20 21:09:14

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On 04/20/2016 01:45 PM, Borislav Petkov wrote:
> On Wed, Apr 20, 2016 at 11:04:05AM -0700, H. Peter Anvin wrote:
>> The reason it breaks is because the same register can't be an
>> input-output register and a separate input. However, the input side of
>> the input-output is probably undefined, and so gcc may not notice.
>
> So Michal and I talked about this a while ago. Why do we need the '"a"
> (sem)' input dependency if '"+a" (ret)' already supplies the same thing?
>

Setting ret to sem doesn't make any sense. Just use "=a" and "a".

-hpa


2016-04-20 21:37:03

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On Wed, Apr 20, 2016 at 02:06:33PM -0700, H. Peter Anvin wrote:
> Setting ret to sem doesn't make any sense. Just use "=a" and "a".

Yeah, that's what Michal's patch ontop does.

And to answer my own question: we need the "a" (sem) input for the fast
path.

I guess we can still move "1" (RWSEM_ACTIVE_WRITE_BIAS) before the asm():

long tmp = RWSEM_ACTIVE_WRITE_BIAS;

One thing I'm still not clear on is why we need the output tmp operand:
"=d" (tmp) ?

--
Regards/Gruss,
Boris.

ECO tip #101: Trim your mails when you reply.

2016-04-20 22:30:31

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On April 20, 2016 2:36:37 PM PDT, Borislav Petkov <[email protected]> wrote:
>On Wed, Apr 20, 2016 at 02:06:33PM -0700, H. Peter Anvin wrote:
>> Setting ret to sem doesn't make any sense. Just use "=a" and "a".
>
>Yeah, that's what Michal's patch ontop does.
>
>And to answer my own question: we need the "a" (sem) input for the fast
>path.
>
>I guess we can still move "1" (RWSEM_ACTIVE_WRITE_BIAS) before the
>asm():
>
> long tmp = RWSEM_ACTIVE_WRITE_BIAS;
>
>One thing I'm still not clear on is why we need the output tmp operand:
>"=d" (tmp) ?

Since it is a fixed register we could just mark edx clobbered, but with more flexible register constraints it can permit gcc to allocate a temp resister for us.
--
Sent from my Android device with K-9 Mail. Please excuse brevity and formatting.

2016-04-21 11:35:40

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On Wed, Apr 20, 2016 at 03:29:30PM -0700, H. Peter Anvin wrote:
> Since it is a fixed register we could just mark edx clobbered, but
> with more flexible register constraints it can permit gcc to allocate
> a temp resister for us. --

Right.

I'll try to hack up a cleanup ontop once the dust here settles and Ingo
pushes out the pile.

Thanks.

--
Regards/Gruss,
Boris.

ECO tip #101: Trim your mails when you reply.

2016-04-21 13:09:19

by Michal Hocko

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On Thu 21-04-16 13:35:16, Borislav Petkov wrote:
> On Wed, Apr 20, 2016 at 03:29:30PM -0700, H. Peter Anvin wrote:
> > Since it is a fixed register we could just mark edx clobbered, but
> > with more flexible register constraints it can permit gcc to allocate
> > a temp resister for us. --
>
> Right.
>
> I'll try to hack up a cleanup ontop once the dust here settles and Ingo
> pushes out the pile.

Thanks Boris! This is highly appreciated.
--
Michal Hocko
SUSE Labs

2016-04-21 13:22:18

by Borislav Petkov

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable

On Thu, Apr 21, 2016 at 09:09:11AM -0400, Michal Hocko wrote:
> Thanks Boris! This is highly appreciated.

I know ;-)

--
Regards/Gruss,
Boris.

ECO tip #101: Trim your mails when you reply.

2016-04-22 06:54:02

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 10/11] x86, rwsem: provide __down_write_killable


* Peter Zijlstra <[email protected]> wrote:

> On Wed, Apr 13, 2016 at 02:49:43PM +0200, Michal Hocko wrote:
> > On Wed 13-04-16 12:27:31, Ingo Molnar wrote:
> > >
> > > * Ingo Molnar <[email protected]> wrote:
> > >
> > > > I'm testing your patches today, if they are otherwise OK [...]
> > >
> > > got this build failure:
> > >
> > > ./arch/x86/include/asm/rwsem.h:106:2: error: ‘asm’ operand has impossible constraints
> >
> > Hmm, I have no idea why 64b didn't have problem with the asm but 32b
> > complains. Anyway, the following makes both happy. I have checked the
> > generated code for 64b and it hasn't changed after the patch. 32b also
> > seems to be generating a proper code. My gcc asm()-foo is rather weak so
> > I would feel better if somebody double checked after me.
>
> I completely blow at this gcc-asm constraints thing too :/
>
> In any case, Ingo will you look after the rest of these patches, or do
> you want me to pick up the remaining bits?

Yeah, it's on my list!

Thanks,

Ingo

Subject: [tip:locking/rwsem] locking/rwsem, alpha: Provide __down_write_killable()

Commit-ID: 7deb5eebc1e61b15c5c7f1ef19f216b20d7f7d00
Gitweb: http://git.kernel.org/tip/7deb5eebc1e61b15c5c7f1ef19f216b20d7f7d00
Author: Michal Hocko <[email protected]>
AuthorDate: Thu, 7 Apr 2016 17:12:27 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Wed, 13 Apr 2016 10:42:21 +0200

locking/rwsem, alpha: Provide __down_write_killable()

Introduce ___down_write() for the fast path and reuse it for __down_write()
resp. __down_write_killable() each using the respective generic slow path
(rwsem_down_write_failed() resp. rwsem_down_write_failed_killable()).

Signed-off-by: Michal Hocko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Chris Zankel <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Signed-off-by: Davidlohr Bueso <[email protected]>
Cc: Signed-off-by: Jason Low <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
arch/alpha/include/asm/rwsem.h | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/arch/alpha/include/asm/rwsem.h b/arch/alpha/include/asm/rwsem.h
index a83bbea..0131a70 100644
--- a/arch/alpha/include/asm/rwsem.h
+++ b/arch/alpha/include/asm/rwsem.h
@@ -63,7 +63,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
return res >= 0 ? 1 : 0;
}

-static inline void __down_write(struct rw_semaphore *sem)
+static inline long ___down_write(struct rw_semaphore *sem)
{
long oldcount;
#ifndef CONFIG_SMP
@@ -83,10 +83,24 @@ static inline void __down_write(struct rw_semaphore *sem)
:"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
:"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory");
#endif
- if (unlikely(oldcount))
+ return oldcount;
+}
+
+static inline void __down_write(struct rw_semaphore *sem)
+{
+ if (unlikely(___down_write(sem)))
rwsem_down_write_failed(sem);
}

+static inline int __down_write_killable(struct rw_semaphore *sem)
+{
+ if (unlikely(___down_write(sem)))
+ if (IS_ERR(rwsem_down_write_failed_killable(sem)))
+ return -EINTR;
+
+ return 0;
+}
+
/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/

Subject: [tip:locking/rwsem] locking/rwsem, ia64: Provide __down_write_killable()

Commit-ID: a02137eb5177e7afc8dfa52a2888c1f2f4840739
Gitweb: http://git.kernel.org/tip/a02137eb5177e7afc8dfa52a2888c1f2f4840739
Author: Michal Hocko <[email protected]>
AuthorDate: Thu, 7 Apr 2016 17:12:28 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Wed, 13 Apr 2016 10:42:21 +0200

locking/rwsem, ia64: Provide __down_write_killable()

Introduce ___down_write() for the fast path and reuse it for __down_write()
resp. __down_write_killable() each using the respective generic slow path
(rwsem_down_write_failed() resp. rwsem_down_write_failed_killable()).

Signed-off-by: Michal Hocko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Chris Zankel <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Signed-off-by: Davidlohr Bueso <[email protected]>
Cc: Signed-off-by: Jason Low <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
arch/ia64/include/asm/rwsem.h | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/arch/ia64/include/asm/rwsem.h b/arch/ia64/include/asm/rwsem.h
index ce11247..8b23e07 100644
--- a/arch/ia64/include/asm/rwsem.h
+++ b/arch/ia64/include/asm/rwsem.h
@@ -49,8 +49,8 @@ __down_read (struct rw_semaphore *sem)
/*
* lock for writing
*/
-static inline void
-__down_write (struct rw_semaphore *sem)
+static inline long
+___down_write (struct rw_semaphore *sem)
{
long old, new;

@@ -59,10 +59,26 @@ __down_write (struct rw_semaphore *sem)
new = old + RWSEM_ACTIVE_WRITE_BIAS;
} while (cmpxchg_acq(&sem->count, old, new) != old);

- if (old != 0)
+ return old;
+}
+
+static inline void
+__down_write (struct rw_semaphore *sem)
+{
+ if (___down_write(sem))
rwsem_down_write_failed(sem);
}

+static inline int
+__down_write_killable (struct rw_semaphore *sem)
+{
+ if (___down_write(sem))
+ if (IS_ERR(rwsem_down_write_failed_killable(sem)))
+ return -EINTR;
+
+ return 0;
+}
+
/*
* unlock after reading
*/

Subject: [tip:locking/rwsem] locking/rwsem, s390: Provide __down_write_killable()

Commit-ID: 4edab14ec66fae5b3c7c4969295facf70365f39d
Gitweb: http://git.kernel.org/tip/4edab14ec66fae5b3c7c4969295facf70365f39d
Author: Michal Hocko <[email protected]>
AuthorDate: Thu, 7 Apr 2016 17:12:29 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Wed, 13 Apr 2016 10:42:22 +0200

locking/rwsem, s390: Provide __down_write_killable()

Introduce ___down_write() for the fast path and reuse it for __down_write()
resp. __down_write_killable() each using the respective generic slow path
(rwsem_down_write_failed() resp. rwsem_down_write_failed_killable()).

Signed-off-by: Michal Hocko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Chris Zankel <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Signed-off-by: Davidlohr Bueso <[email protected]>
Cc: Signed-off-by: Jason Low <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
arch/s390/include/asm/rwsem.h | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/arch/s390/include/asm/rwsem.h b/arch/s390/include/asm/rwsem.h
index 555d23b..c75e447 100644
--- a/arch/s390/include/asm/rwsem.h
+++ b/arch/s390/include/asm/rwsem.h
@@ -90,7 +90,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
-static inline void __down_write(struct rw_semaphore *sem)
+static inline long ___down_write(struct rw_semaphore *sem)
{
signed long old, new, tmp;

@@ -104,10 +104,25 @@ static inline void __down_write(struct rw_semaphore *sem)
: "=&d" (old), "=&d" (new), "=Q" (sem->count)
: "Q" (sem->count), "m" (tmp)
: "cc", "memory");
- if (old != 0)
+
+ return old;
+}
+
+static inline void __down_write(struct rw_semaphore *sem)
+{
+ if (___down_write(sem))
rwsem_down_write_failed(sem);
}

+static inline int __down_write_killable(struct rw_semaphore *sem)
+{
+ if (___down_write(sem))
+ if (IS_ERR(rwsem_down_write_failed_killable(sem)))
+ return -EINTR;
+
+ return 0;
+}
+
/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/

Subject: [tip:locking/rwsem] locking/rwsem: Provide down_write_killable()

Commit-ID: 916633a403702549d37ea353e63a68e5b0dc27ad
Gitweb: http://git.kernel.org/tip/916633a403702549d37ea353e63a68e5b0dc27ad
Author: Michal Hocko <[email protected]>
AuthorDate: Thu, 7 Apr 2016 17:12:31 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Fri, 22 Apr 2016 08:58:33 +0200

locking/rwsem: Provide down_write_killable()

Now that all the architectures implement the necessary glue code
we can introduce down_write_killable(). The only difference wrt. regular
down_write() is that the slow path waits in TASK_KILLABLE state and the
interruption by the fatal signal is reported as -EINTR to the caller.

Signed-off-by: Michal Hocko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Chris Zankel <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Signed-off-by: Davidlohr Bueso <[email protected]>
Cc: Signed-off-by: Jason Low <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
arch/x86/include/asm/rwsem.h | 6 +++---
include/linux/lockdep.h | 15 +++++++++++++++
include/linux/rwsem.h | 1 +
kernel/locking/rwsem.c | 19 +++++++++++++++++++
4 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
index d759c5f..453744c 100644
--- a/arch/x86/include/asm/rwsem.h
+++ b/arch/x86/include/asm/rwsem.h
@@ -102,9 +102,9 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
#define ____down_write(sem, slow_path) \
({ \
long tmp; \
- struct rw_semaphore* ret = sem; \
+ struct rw_semaphore* ret; \
asm volatile("# beginning down_write\n\t" \
- LOCK_PREFIX " xadd %1,(%2)\n\t" \
+ LOCK_PREFIX " xadd %1,(%3)\n\t" \
/* adds 0xffff0001, returns the old value */ \
" test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" \
/* was the active mask 0 before? */\
@@ -112,7 +112,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
" call " slow_path "\n" \
"1:\n" \
"# ending down_write" \
- : "+m" (sem->count), "=d" (tmp), "+a" (ret) \
+ : "+m" (sem->count), "=d" (tmp), "=a" (ret) \
: "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
: "memory", "cc"); \
ret; \
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index d026b19..accfe56 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -444,6 +444,18 @@ do { \
lock_acquired(&(_lock)->dep_map, _RET_IP_); \
} while (0)

+#define LOCK_CONTENDED_RETURN(_lock, try, lock) \
+({ \
+ int ____err = 0; \
+ if (!try(_lock)) { \
+ lock_contended(&(_lock)->dep_map, _RET_IP_); \
+ ____err = lock(_lock); \
+ } \
+ if (!____err) \
+ lock_acquired(&(_lock)->dep_map, _RET_IP_); \
+ ____err; \
+})
+
#else /* CONFIG_LOCK_STAT */

#define lock_contended(lockdep_map, ip) do {} while (0)
@@ -452,6 +464,9 @@ do { \
#define LOCK_CONTENDED(_lock, try, lock) \
lock(_lock)

+#define LOCK_CONTENDED_RETURN(_lock, try, lock) \
+ lock(_lock)
+
#endif /* CONFIG_LOCK_STAT */

#ifdef CONFIG_LOCKDEP
diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
index 7d7ae02..d1c12d1 100644
--- a/include/linux/rwsem.h
+++ b/include/linux/rwsem.h
@@ -118,6 +118,7 @@ extern int down_read_trylock(struct rw_semaphore *sem);
* lock for writing
*/
extern void down_write(struct rw_semaphore *sem);
+extern int __must_check down_write_killable(struct rw_semaphore *sem);

/*
* trylock for writing -- returns 1 if successful, 0 if contention
diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c
index 205be0c..c817216 100644
--- a/kernel/locking/rwsem.c
+++ b/kernel/locking/rwsem.c
@@ -55,6 +55,25 @@ void __sched down_write(struct rw_semaphore *sem)
EXPORT_SYMBOL(down_write);

/*
+ * lock for writing
+ */
+int __sched down_write_killable(struct rw_semaphore *sem)
+{
+ might_sleep();
+ rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
+
+ if (LOCK_CONTENDED_RETURN(sem, __down_write_trylock, __down_write_killable)) {
+ rwsem_release(&sem->dep_map, 1, _RET_IP_);
+ return -EINTR;
+ }
+
+ rwsem_set_owner(sem);
+ return 0;
+}
+
+EXPORT_SYMBOL(down_write_killable);
+
+/*
* trylock for writing -- returns 1 if successful, 0 if contention
*/
int down_write_trylock(struct rw_semaphore *sem)

Subject: [tip:locking/rwsem] locking/rwsem, x86: Provide __down_write_killable()

Commit-ID: 664b4e24c6145830885e854195376351b0eb3eee
Gitweb: http://git.kernel.org/tip/664b4e24c6145830885e854195376351b0eb3eee
Author: Michal Hocko <[email protected]>
AuthorDate: Thu, 7 Apr 2016 17:12:30 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Wed, 13 Apr 2016 10:42:22 +0200

locking/rwsem, x86: Provide __down_write_killable()

which uses the same fast path as __down_write() except it falls back to
call_rwsem_down_write_failed_killable() slow path and return -EINTR if
killed. To prevent from code duplication extract the skeleton of
__down_write() into a helper macro which just takes the semaphore
and the slow path function to be called.

Signed-off-by: Michal Hocko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Chris Zankel <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Signed-off-by: Davidlohr Bueso <[email protected]>
Cc: Signed-off-by: Jason Low <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
arch/x86/include/asm/rwsem.h | 41 ++++++++++++++++++++++++++++-------------
arch/x86/lib/rwsem.S | 8 ++++++++
2 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
index 4a8292a..d759c5f 100644
--- a/arch/x86/include/asm/rwsem.h
+++ b/arch/x86/include/asm/rwsem.h
@@ -99,21 +99,36 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
+#define ____down_write(sem, slow_path) \
+({ \
+ long tmp; \
+ struct rw_semaphore* ret = sem; \
+ asm volatile("# beginning down_write\n\t" \
+ LOCK_PREFIX " xadd %1,(%2)\n\t" \
+ /* adds 0xffff0001, returns the old value */ \
+ " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" \
+ /* was the active mask 0 before? */\
+ " jz 1f\n" \
+ " call " slow_path "\n" \
+ "1:\n" \
+ "# ending down_write" \
+ : "+m" (sem->count), "=d" (tmp), "+a" (ret) \
+ : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
+ : "memory", "cc"); \
+ ret; \
+})
+
static inline void __down_write(struct rw_semaphore *sem)
{
- long tmp;
- asm volatile("# beginning down_write\n\t"
- LOCK_PREFIX " xadd %1,(%2)\n\t"
- /* adds 0xffff0001, returns the old value */
- " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t"
- /* was the active mask 0 before? */
- " jz 1f\n"
- " call call_rwsem_down_write_failed\n"
- "1:\n"
- "# ending down_write"
- : "+m" (sem->count), "=d" (tmp)
- : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS)
- : "memory", "cc");
+ ____down_write(sem, "call_rwsem_down_write_failed");
+}
+
+static inline int __down_write_killable(struct rw_semaphore *sem)
+{
+ if (IS_ERR(____down_write(sem, "call_rwsem_down_write_failed_killable")))
+ return -EINTR;
+
+ return 0;
}

/*
diff --git a/arch/x86/lib/rwsem.S b/arch/x86/lib/rwsem.S
index be110ef..4534a7e 100644
--- a/arch/x86/lib/rwsem.S
+++ b/arch/x86/lib/rwsem.S
@@ -106,6 +106,14 @@ ENTRY(call_rwsem_down_write_failed)
ret
ENDPROC(call_rwsem_down_write_failed)

+ENTRY(call_rwsem_down_write_failed_killable)
+ save_common_regs
+ movq %rax,%rdi
+ call rwsem_down_write_failed_killable
+ restore_common_regs
+ ret
+ENDPROC(call_rwsem_down_write_failed_killable)
+
ENTRY(call_rwsem_wake)
FRAME_BEGIN
/* do nothing if still outstanding active readers */

Subject: [tip:locking/rwsem] locking/rwsem, x86: Add frame annotation for call_rwsem_down_write_failed_killable()

Commit-ID: 00fb16e26ac8559e69c3bb14284f4a548d28ee0d
Gitweb: http://git.kernel.org/tip/00fb16e26ac8559e69c3bb14284f4a548d28ee0d
Author: Michal Hocko <[email protected]>
AuthorDate: Wed, 13 Apr 2016 11:57:12 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Fri, 22 Apr 2016 08:58:41 +0200

locking/rwsem, x86: Add frame annotation for call_rwsem_down_write_failed_killable()

3387a535ce62 ("x86/asm: Create stack frames in rwsem functions") has
added FRAME_{BEGIN,END} annotations to rwsem asm stubs. The patch
which has added call_rwsem_down_write_failed_killable() was based on an
older tree so it didn't know about annotations. Let's add them.

This addresses the following objtool warning:

arch/x86/lib/rwsem.o: warning: objtool: call_rwsem_down_write_failed_killable()+0xe: call without frame pointer save/setup

Reported-by: Ingo Molnar <[email protected]>
Signed-off-by: Michal Hocko <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
arch/x86/lib/rwsem.S | 2 ++
1 file changed, 2 insertions(+)

diff --git a/arch/x86/lib/rwsem.S b/arch/x86/lib/rwsem.S
index 4534a7e..a37462a 100644
--- a/arch/x86/lib/rwsem.S
+++ b/arch/x86/lib/rwsem.S
@@ -107,10 +107,12 @@ ENTRY(call_rwsem_down_write_failed)
ENDPROC(call_rwsem_down_write_failed)

ENTRY(call_rwsem_down_write_failed_killable)
+ FRAME_BEGIN
save_common_regs
movq %rax,%rdi
call rwsem_down_write_failed_killable
restore_common_regs
+ FRAME_END
ret
ENDPROC(call_rwsem_down_write_failed_killable)


2016-04-27 12:02:29

by Borislav Petkov

[permalink] [raw]
Subject: [PATCH] x86/locking/rwsem: Cleanup ____down_write()

On Wed, Apr 20, 2016 at 03:29:30PM -0700, H. Peter Anvin wrote:
> Since it is a fixed register we could just mark edx clobbered, but
> with more flexible register constraints it can permit gcc to allocate
> a temp resister for us.

How about the following?

It boots fine in kvm and the asm changes are only trivial gcc comments
differences:

---
From: Borislav Petkov <[email protected]>
Date: Wed, 27 Apr 2016 13:47:32 +0200
Subject: [PATCH] x86/locking/rwsem: Cleanup ____down_write()

Move the RWSEM_ACTIVE_WRITE_BIAS out of the inline asm to reduce the
number of arguments. Also, make it an input argument only (why it was an
output operand, I still don't know...).

For better readability, use symbolic names for the arguments and move
the linebreak backspace to 80 cols.

Resulting asm differs only in the temporary gcc variable names and
locations:

--- before 2016-04-27 13:39:05.320778458 +0200
+++ after 2016-04-27 13:52:37.336778994 +0200
@@ -11,8 +11,8 @@ down_write_killable:
.LBB84:
.LBB85:
.LBB86:
- .loc 2 128 0
- movabsq $-4294967295, %rdx #, tmp
+ .loc 2 130 0
+ movabsq $-4294967295, %rdx #, tmp94
movq %rdi, %rax # sem, sem
.LBE86:
.LBE85:
@@ -23,17 +23,17 @@ down_write_killable:
.LBB89:
.LBB88:
.LBB87:
- .loc 2 128 0
+ .loc 2 130 0
#APP
-# 128 "./arch/x86/include/asm/rwsem.h" 1
+# 130 "./arch/x86/include/asm/rwsem.h" 1
# beginning down_write
.pushsection .smp_locks,"a"
.balign 4
.long 671f - .
.popsection
671:
- lock; xadd %rdx,(%rax) # tmp, sem
- test %edx , %edx # tmp
+ lock; xadd %rdx,(%rax) # tmp94, sem
+ test %edx , %edx # tmp94
jz 1f
call call_rwsem_down_write_failed_killable
1:

Signed-off-by: Borislav Petkov <[email protected]>
---
arch/x86/include/asm/rwsem.h | 36 +++++++++++++++++++-----------------
1 file changed, 19 insertions(+), 17 deletions(-)

diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
index 453744c1d347..d2f8d10a6d97 100644
--- a/arch/x86/include/asm/rwsem.h
+++ b/arch/x86/include/asm/rwsem.h
@@ -99,23 +99,25 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
-#define ____down_write(sem, slow_path) \
-({ \
- long tmp; \
- struct rw_semaphore* ret; \
- asm volatile("# beginning down_write\n\t" \
- LOCK_PREFIX " xadd %1,(%3)\n\t" \
- /* adds 0xffff0001, returns the old value */ \
- " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" \
- /* was the active mask 0 before? */\
- " jz 1f\n" \
- " call " slow_path "\n" \
- "1:\n" \
- "# ending down_write" \
- : "+m" (sem->count), "=d" (tmp), "=a" (ret) \
- : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
- : "memory", "cc"); \
- ret; \
+#define ____down_write(sem, slow_path) \
+({ \
+ long tmp = RWSEM_ACTIVE_WRITE_BIAS; \
+ struct rw_semaphore* ret; \
+ \
+ asm volatile("# beginning down_write\n\t" \
+ LOCK_PREFIX " xadd %[tmp],(%[sem])\n\t" \
+ /* adds 0xffff0001, returns the old value */ \
+ " test " __ASM_SEL(%w[tmp],%k[tmp]) "," \
+ __ASM_SEL(%w[tmp],%k[tmp]) "\n\t" \
+ /* was the active mask 0 before? */ \
+ " jz 1f\n" \
+ " call " slow_path "\n" \
+ "1:\n" \
+ "# ending down_write" \
+ : "+m" (sem->count), "=a" (ret) \
+ : [sem] "a" (sem), [tmp] "r" (tmp) \
+ : "memory", "cc"); \
+ ret; \
})

static inline void __down_write(struct rw_semaphore *sem)
--
2.7.3


--
Regards/Gruss,
Boris.

ECO tip #101: Trim your mails when you reply.

Subject: [tip:locking/rwsem] locking/rwsem, x86: Clean up ____down_write()

Commit-ID: 71c01930b42e5dd65d4820dea116bcbe95a0b768
Gitweb: http://git.kernel.org/tip/71c01930b42e5dd65d4820dea116bcbe95a0b768
Author: Borislav Petkov <[email protected]>
AuthorDate: Wed, 27 Apr 2016 13:47:32 +0200
Committer: Ingo Molnar <[email protected]>
CommitDate: Thu, 28 Apr 2016 10:42:56 +0200

locking/rwsem, x86: Clean up ____down_write()

Move the RWSEM_ACTIVE_WRITE_BIAS out of the inline asm to reduce the
number of arguments. Also, make it an input argument only (why it was an
output operand, I still don't know...).

For better readability, use symbolic names for the arguments and move
the linebreak backspace to 80 cols.

Resulting asm differs only in the temporary GCC variable names and
locations:

-- before 2016-04-27 13:39:05.320778458 +0200
++ after 2016-04-27 13:52:37.336778994 +0200
@@ -11,8 +11,8 @@ down_write_killable:
.LBB84:
.LBB85:
.LBB86:
- .loc 2 128 0
- movabsq $-4294967295, %rdx #, tmp
+ .loc 2 130 0
+ movabsq $-4294967295, %rdx #, tmp94
movq %rdi, %rax # sem, sem
.LBE86:
.LBE85:
@@ -23,17 +23,17 @@ down_write_killable:
.LBB89:
.LBB88:
.LBB87:
- .loc 2 128 0
+ .loc 2 130 0
#APP
-# 128 "./arch/x86/include/asm/rwsem.h" 1
+# 130 "./arch/x86/include/asm/rwsem.h" 1
# beginning down_write
.pushsection .smp_locks,"a"
.balign 4
.long 671f - .
.popsection
671:
- lock; xadd %rdx,(%rax) # tmp, sem
- test %edx , %edx # tmp
+ lock; xadd %rdx,(%rax) # tmp94, sem
+ test %edx , %edx # tmp94
jz 1f
call call_rwsem_down_write_failed_killable
1:

Signed-off-by: Borislav Petkov <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Chris Zankel <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Josh Poimboeuf <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Max Filippov <[email protected]>
Cc: Michal Hocko <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
---
arch/x86/include/asm/rwsem.h | 36 +++++++++++++++++++-----------------
1 file changed, 19 insertions(+), 17 deletions(-)

diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
index 453744c..d2f8d10 100644
--- a/arch/x86/include/asm/rwsem.h
+++ b/arch/x86/include/asm/rwsem.h
@@ -99,23 +99,25 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
/*
* lock for writing
*/
-#define ____down_write(sem, slow_path) \
-({ \
- long tmp; \
- struct rw_semaphore* ret; \
- asm volatile("# beginning down_write\n\t" \
- LOCK_PREFIX " xadd %1,(%3)\n\t" \
- /* adds 0xffff0001, returns the old value */ \
- " test " __ASM_SEL(%w1,%k1) "," __ASM_SEL(%w1,%k1) "\n\t" \
- /* was the active mask 0 before? */\
- " jz 1f\n" \
- " call " slow_path "\n" \
- "1:\n" \
- "# ending down_write" \
- : "+m" (sem->count), "=d" (tmp), "=a" (ret) \
- : "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
- : "memory", "cc"); \
- ret; \
+#define ____down_write(sem, slow_path) \
+({ \
+ long tmp = RWSEM_ACTIVE_WRITE_BIAS; \
+ struct rw_semaphore* ret; \
+ \
+ asm volatile("# beginning down_write\n\t" \
+ LOCK_PREFIX " xadd %[tmp],(%[sem])\n\t" \
+ /* adds 0xffff0001, returns the old value */ \
+ " test " __ASM_SEL(%w[tmp],%k[tmp]) "," \
+ __ASM_SEL(%w[tmp],%k[tmp]) "\n\t" \
+ /* was the active mask 0 before? */ \
+ " jz 1f\n" \
+ " call " slow_path "\n" \
+ "1:\n" \
+ "# ending down_write" \
+ : "+m" (sem->count), "=a" (ret) \
+ : [sem] "a" (sem), [tmp] "r" (tmp) \
+ : "memory", "cc"); \
+ ret; \
})

static inline void __down_write(struct rw_semaphore *sem)