mirror of
https://github.com/torvalds/linux.git
synced 2024-11-16 17:12:06 +00:00
84759c6d18
This reverts commit 11b80f459a
.
Bcache needs rw semaphores for cache coherency in writeback mode -
writes have to take a read lock on a per cache device rw sem, and
release it when the bio completes.
But since this is for bios it's naturally not in the context of the
process that originally took the lock.
Signed-off-by: Kent Overstreet <koverstreet@google.com>
CC: Christoph Hellwig <hch@infradead.org>
CC: David Howells <dhowells@redhat.com>
158 lines
2.8 KiB
C
158 lines
2.8 KiB
C
/* kernel/rwsem.c: R/W semaphores, public implementation
|
|
*
|
|
* Written by David Howells (dhowells@redhat.com).
|
|
* Derived from asm-i386/semaphore.h
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/export.h>
|
|
#include <linux/rwsem.h>
|
|
|
|
#include <linux/atomic.h>
|
|
|
|
/*
|
|
* lock for reading
|
|
*/
|
|
void __sched down_read(struct rw_semaphore *sem)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_);
|
|
|
|
LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
|
|
}
|
|
|
|
EXPORT_SYMBOL(down_read);
|
|
|
|
/*
|
|
* trylock for reading -- returns 1 if successful, 0 if contention
|
|
*/
|
|
int down_read_trylock(struct rw_semaphore *sem)
|
|
{
|
|
int ret = __down_read_trylock(sem);
|
|
|
|
if (ret == 1)
|
|
rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_);
|
|
return ret;
|
|
}
|
|
|
|
EXPORT_SYMBOL(down_read_trylock);
|
|
|
|
/*
|
|
* lock for writing
|
|
*/
|
|
void __sched down_write(struct rw_semaphore *sem)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
|
|
|
|
LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
|
|
}
|
|
|
|
EXPORT_SYMBOL(down_write);
|
|
|
|
/*
|
|
* trylock for writing -- returns 1 if successful, 0 if contention
|
|
*/
|
|
int down_write_trylock(struct rw_semaphore *sem)
|
|
{
|
|
int ret = __down_write_trylock(sem);
|
|
|
|
if (ret == 1)
|
|
rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
|
|
return ret;
|
|
}
|
|
|
|
EXPORT_SYMBOL(down_write_trylock);
|
|
|
|
/*
|
|
* release a read lock
|
|
*/
|
|
void up_read(struct rw_semaphore *sem)
|
|
{
|
|
rwsem_release(&sem->dep_map, 1, _RET_IP_);
|
|
|
|
__up_read(sem);
|
|
}
|
|
|
|
EXPORT_SYMBOL(up_read);
|
|
|
|
/*
|
|
* release a write lock
|
|
*/
|
|
void up_write(struct rw_semaphore *sem)
|
|
{
|
|
rwsem_release(&sem->dep_map, 1, _RET_IP_);
|
|
|
|
__up_write(sem);
|
|
}
|
|
|
|
EXPORT_SYMBOL(up_write);
|
|
|
|
/*
|
|
* downgrade write lock to read lock
|
|
*/
|
|
void downgrade_write(struct rw_semaphore *sem)
|
|
{
|
|
/*
|
|
* lockdep: a downgraded write will live on as a write
|
|
* dependency.
|
|
*/
|
|
__downgrade_write(sem);
|
|
}
|
|
|
|
EXPORT_SYMBOL(downgrade_write);
|
|
|
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
|
|
|
void down_read_nested(struct rw_semaphore *sem, int subclass)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_);
|
|
|
|
LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
|
|
}
|
|
|
|
EXPORT_SYMBOL(down_read_nested);
|
|
|
|
void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire_nest(&sem->dep_map, 0, 0, nest, _RET_IP_);
|
|
|
|
LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
|
|
}
|
|
|
|
EXPORT_SYMBOL(_down_write_nest_lock);
|
|
|
|
void down_read_non_owner(struct rw_semaphore *sem)
|
|
{
|
|
might_sleep();
|
|
|
|
__down_read(sem);
|
|
}
|
|
|
|
EXPORT_SYMBOL(down_read_non_owner);
|
|
|
|
void down_write_nested(struct rw_semaphore *sem, int subclass)
|
|
{
|
|
might_sleep();
|
|
rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_);
|
|
|
|
LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
|
|
}
|
|
|
|
EXPORT_SYMBOL(down_write_nested);
|
|
|
|
void up_read_non_owner(struct rw_semaphore *sem)
|
|
{
|
|
__up_read(sem);
|
|
}
|
|
|
|
EXPORT_SYMBOL(up_read_non_owner);
|
|
|
|
#endif
|
|
|
|
|