Commit 0bfb9f42 authored by Kent Overstreet's avatar Kent Overstreet

six locks: six_lock_waiter()

This allows passing in the wait list entry - to be used for a deadlock
cycle detector.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent ebc6f76a
...@@ -439,10 +439,10 @@ static inline bool six_optimistic_spin(struct six_lock *lock, enum six_lock_type ...@@ -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 ...@@ -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 ...@@ -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 @@ static int __six_lock_type_slowpath(struct six_lock *lock, enum six_lock_type ty ...@@ -496,9 +496,10 @@ static int __six_lock_type_slowpath(struct six_lock *lock, enum six_lock_type ty
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, ...@@ -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, ...@@ -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, \ ...@@ -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 { \ ...@@ -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, ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment