six locks: six_lock_waiter()
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 27 Aug 2022 20:22:51 +0000 (16:22 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:41 +0000 (17:09 -0400)
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>
fs/bcachefs/six.c
fs/bcachefs/six.h

index d5e09fae153878491533a637b9ad1403bd3f37fc..82e8d77c3082f2ffb52bfcac00b6b4025b811e84 100644 (file)
@@ -439,10 +439,10 @@ static inline bool six_optimistic_spin(struct six_lock *lock, enum six_lock_type
 
 noinline
 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)
 {
        union six_lock_state old;
-       struct six_lock_waiter wait;
        int ret = 0;
 
        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_);
 
-       wait.task       = current;
-       wait.lock_want  = type;
+       wait->task              = current;
+       wait->lock_want         = type;
 
        raw_spin_lock(&lock->wait_lock);
        if (!(lock->state.waiters & (1 << type)))
                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);
 
        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);
 
        raw_spin_lock(&lock->wait_lock);
-       list_del(&wait.list);
+       list_del(&wait->list);
        raw_spin_unlock(&lock->wait_lock);
 out_before_sleep:
        if (ret && type == SIX_LOCK_write) {
@@ -496,9 +496,10 @@ out_before_sleep:
        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)
+__always_inline __flatten
+static 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)
 {
        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);
 
        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)
                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;
 }
 
+__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
 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);                                    \
                                                                        \
+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)                          \
 {                                                                      \
        __six_unlock_type(lock, SIX_LOCK_##type);                       \
index 0e55845195d97b45df4c6d80f334ff2bbe13511c..ab06773e80947fb12da0d4a2cb8cf977abc909b5 100644 (file)
@@ -156,6 +156,8 @@ do {                                                                        \
 bool six_trylock_##type(struct six_lock *);                            \
 bool six_relock_##type(struct six_lock *, u32);                                \
 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 *);
 
 __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);
 }
 
+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)
 {
        SIX_LOCK_DISPATCH(type, six_unlock, lock);