mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-16 18:26:42 +00:00
six locks: six_lock_waiter()
This allows passing in the wait list entry - to be used for a deadlock cycle detector. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
ebc6f76a66
commit
0bfb9f42b7
@ -439,10 +439,10 @@ static inline bool six_optimistic_spin(struct six_lock *lock, enum six_lock_type
|
|||||||
|
|
||||||
noinline
|
noinline
|
||||||
static int __six_lock_type_slowpath(struct six_lock *lock, enum six_lock_type type,
|
static int __six_lock_type_slowpath(struct six_lock *lock, enum six_lock_type type,
|
||||||
|
struct six_lock_waiter *wait,
|
||||||
six_lock_should_sleep_fn should_sleep_fn, void *p)
|
six_lock_should_sleep_fn should_sleep_fn, void *p)
|
||||||
{
|
{
|
||||||
union six_lock_state old;
|
union six_lock_state old;
|
||||||
struct six_lock_waiter wait;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (type == SIX_LOCK_write) {
|
if (type == SIX_LOCK_write) {
|
||||||
@ -460,13 +460,13 @@ static int __six_lock_type_slowpath(struct six_lock *lock, enum six_lock_type ty
|
|||||||
|
|
||||||
lock_contended(&lock->dep_map, _RET_IP_);
|
lock_contended(&lock->dep_map, _RET_IP_);
|
||||||
|
|
||||||
wait.task = current;
|
wait->task = current;
|
||||||
wait.lock_want = type;
|
wait->lock_want = type;
|
||||||
|
|
||||||
raw_spin_lock(&lock->wait_lock);
|
raw_spin_lock(&lock->wait_lock);
|
||||||
if (!(lock->state.waiters & (1 << type)))
|
if (!(lock->state.waiters & (1 << type)))
|
||||||
set_bit(waitlist_bitnr(type), (unsigned long *) &lock->state.v);
|
set_bit(waitlist_bitnr(type), (unsigned long *) &lock->state.v);
|
||||||
list_add_tail(&wait.list, &lock->wait_list);
|
list_add_tail(&wait->list, &lock->wait_list);
|
||||||
raw_spin_unlock(&lock->wait_lock);
|
raw_spin_unlock(&lock->wait_lock);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -484,7 +484,7 @@ static int __six_lock_type_slowpath(struct six_lock *lock, enum six_lock_type ty
|
|||||||
__set_current_state(TASK_RUNNING);
|
__set_current_state(TASK_RUNNING);
|
||||||
|
|
||||||
raw_spin_lock(&lock->wait_lock);
|
raw_spin_lock(&lock->wait_lock);
|
||||||
list_del(&wait.list);
|
list_del(&wait->list);
|
||||||
raw_spin_unlock(&lock->wait_lock);
|
raw_spin_unlock(&lock->wait_lock);
|
||||||
out_before_sleep:
|
out_before_sleep:
|
||||||
if (ret && type == SIX_LOCK_write) {
|
if (ret && type == SIX_LOCK_write) {
|
||||||
@ -496,9 +496,10 @@ out_before_sleep:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
__always_inline
|
__always_inline __flatten
|
||||||
static int __six_lock_type(struct six_lock *lock, enum six_lock_type type,
|
static int __six_lock_type_waiter(struct six_lock *lock, enum six_lock_type type,
|
||||||
six_lock_should_sleep_fn should_sleep_fn, void *p)
|
struct six_lock_waiter *wait,
|
||||||
|
six_lock_should_sleep_fn should_sleep_fn, void *p)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -506,7 +507,7 @@ static int __six_lock_type(struct six_lock *lock, enum six_lock_type type,
|
|||||||
six_acquire(&lock->dep_map, 0);
|
six_acquire(&lock->dep_map, 0);
|
||||||
|
|
||||||
ret = do_six_trylock_type(lock, type, true) ? 0
|
ret = do_six_trylock_type(lock, type, true) ? 0
|
||||||
: __six_lock_type_slowpath(lock, type, should_sleep_fn, p);
|
: __six_lock_type_slowpath(lock, type, wait, should_sleep_fn, p);
|
||||||
|
|
||||||
if (ret && type != SIX_LOCK_write)
|
if (ret && type != SIX_LOCK_write)
|
||||||
six_release(&lock->dep_map);
|
six_release(&lock->dep_map);
|
||||||
@ -516,6 +517,15 @@ static int __six_lock_type(struct six_lock *lock, enum six_lock_type type,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__always_inline
|
||||||
|
static int __six_lock_type(struct six_lock *lock, enum six_lock_type type,
|
||||||
|
six_lock_should_sleep_fn should_sleep_fn, void *p)
|
||||||
|
{
|
||||||
|
struct six_lock_waiter wait;
|
||||||
|
|
||||||
|
return __six_lock_type_waiter(lock, type, &wait, should_sleep_fn, p);
|
||||||
|
}
|
||||||
|
|
||||||
__always_inline __flatten
|
__always_inline __flatten
|
||||||
static void __six_unlock_type(struct six_lock *lock, enum six_lock_type type)
|
static void __six_unlock_type(struct six_lock *lock, enum six_lock_type type)
|
||||||
{
|
{
|
||||||
@ -574,6 +584,14 @@ int six_lock_##type(struct six_lock *lock, \
|
|||||||
} \
|
} \
|
||||||
EXPORT_SYMBOL_GPL(six_lock_##type); \
|
EXPORT_SYMBOL_GPL(six_lock_##type); \
|
||||||
\
|
\
|
||||||
|
int six_lock_waiter_##type(struct six_lock *lock, \
|
||||||
|
struct six_lock_waiter *wait, \
|
||||||
|
six_lock_should_sleep_fn should_sleep_fn, void *p)\
|
||||||
|
{ \
|
||||||
|
return __six_lock_type_waiter(lock, SIX_LOCK_##type, wait, should_sleep_fn, p);\
|
||||||
|
} \
|
||||||
|
EXPORT_SYMBOL_GPL(six_lock_waiter_##type); \
|
||||||
|
\
|
||||||
void six_unlock_##type(struct six_lock *lock) \
|
void six_unlock_##type(struct six_lock *lock) \
|
||||||
{ \
|
{ \
|
||||||
__six_unlock_type(lock, SIX_LOCK_##type); \
|
__six_unlock_type(lock, SIX_LOCK_##type); \
|
||||||
|
@ -156,6 +156,8 @@ do { \
|
|||||||
bool six_trylock_##type(struct six_lock *); \
|
bool six_trylock_##type(struct six_lock *); \
|
||||||
bool six_relock_##type(struct six_lock *, u32); \
|
bool six_relock_##type(struct six_lock *, u32); \
|
||||||
int six_lock_##type(struct six_lock *, six_lock_should_sleep_fn, void *);\
|
int six_lock_##type(struct six_lock *, six_lock_should_sleep_fn, void *);\
|
||||||
|
int six_lock_waiter_##type(struct six_lock *, struct six_lock_waiter *, \
|
||||||
|
six_lock_should_sleep_fn, void *); \
|
||||||
void six_unlock_##type(struct six_lock *);
|
void six_unlock_##type(struct six_lock *);
|
||||||
|
|
||||||
__SIX_LOCK(read)
|
__SIX_LOCK(read)
|
||||||
@ -192,6 +194,13 @@ static inline int six_lock_type(struct six_lock *lock, enum six_lock_type type,
|
|||||||
SIX_LOCK_DISPATCH(type, six_lock, lock, should_sleep_fn, p);
|
SIX_LOCK_DISPATCH(type, six_lock, lock, should_sleep_fn, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int six_lock_type_waiter(struct six_lock *lock, enum six_lock_type type,
|
||||||
|
struct six_lock_waiter *wait,
|
||||||
|
six_lock_should_sleep_fn should_sleep_fn, void *p)
|
||||||
|
{
|
||||||
|
SIX_LOCK_DISPATCH(type, six_lock_waiter, lock, wait, should_sleep_fn, p);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void six_unlock_type(struct six_lock *lock, enum six_lock_type type)
|
static inline void six_unlock_type(struct six_lock *lock, enum six_lock_type type)
|
||||||
{
|
{
|
||||||
SIX_LOCK_DISPATCH(type, six_unlock, lock);
|
SIX_LOCK_DISPATCH(type, six_unlock, lock);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user