Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3469d261 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'locking-rwsem-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull support for killable rwsems from Ingo Molnar:
 "This, by Michal Hocko, implements down_write_killable().

  The main usecase will be to update mm_sem usage sites to use this new
  API, to allow the mm-reaper introduced in commit aac45363 ("mm,
  oom: introduce oom reaper") to tear down oom victim address spaces
  asynchronously with minimum latencies and without deadlock worries"

[ The vfs will want it too as the inode lock is changed from a mutex to
  a rwsem due to the parallel lookup and readdir updates ]

* 'locking-rwsem-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  locking/rwsem: Fix comment on register clobbering
  locking/rwsem: Fix down_write_killable()
  locking/rwsem, x86: Add frame annotation for call_rwsem_down_write_failed_killable()
  locking/rwsem: Provide down_write_killable()
  locking/rwsem, x86: Provide __down_write_killable()
  locking/rwsem, s390: Provide __down_write_killable()
  locking/rwsem, ia64: Provide __down_write_killable()
  locking/rwsem, alpha: Provide __down_write_killable()
  locking/rwsem: Introduce basis for down_write_killable()
  locking/rwsem, sparc: Drop superfluous arch specific implementation
  locking/rwsem, sh: Drop superfluous arch specific implementation
  locking/rwsem, xtensa: Drop superfluous arch specific implementation
  locking/rwsem: Drop explicit memory barriers
  locking/rwsem: Get rid of __down_write_nested()
parents 1c19b68a 4544ba8c
Loading
Loading
Loading
Loading
+16 −2
Original line number Diff line number Diff line
@@ -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
 */
+19 −3
Original line number Diff line number Diff line
@@ -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
 */
+14 −4
Original line number Diff line number Diff line
@@ -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 long ___down_write(struct rw_semaphore *sem)
{
	signed long old, new, tmp;

@@ -104,13 +104,23 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
		: "=&d" (old), "=&d" (new), "=Q" (sem->count)
		: "Q" (sem->count), "m" (tmp)
		: "cc", "memory");
	if (old != 0)
		rwsem_down_write_failed(sem);

	return old;
}

static inline void __down_write(struct rw_semaphore *sem)
{
	__down_write_nested(sem, 0);
	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;
}

/*
+1 −0
Original line number Diff line number Diff line
@@ -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

arch/sh/include/asm/rwsem.h

deleted100644 → 0
+0 −132
Original line number Diff line number Diff line
/*
 * 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)
		smp_wmb();
	else
		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)) {
			smp_wmb();
			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)
		smp_wmb();
	else
		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);
	smp_wmb();
	return tmp == RWSEM_UNLOCKED_VALUE;
}

/*
 * unlock after reading
 */
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);
}

/*
 * unlock after writing
 */
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);
}

/*
 * 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;

	smp_wmb();
	tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
	if (tmp < 0)
		rwsem_downgrade_wake(sem);
}

static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
{
	__down_write(sem);
}

/*
 * implement exchange and add functionality
 */
static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
{
	smp_mb();
	return atomic_add_return(delta, (atomic_t *)(&sem->count));
}

#endif /* __KERNEL__ */
#endif /* _ASM_SH_RWSEM_H */
Loading