summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-03-25 01:48:22 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2021-03-25 01:50:16 -0400
commit7f4ac232587dd02794081cc4e405e1735f7a8c3e (patch)
treeab8ab4a3d6276e07e15f2c81cae6007f09f36754
parent6e8f25f9a768bfe4323364c2630d1d6b21ec9719 (diff)
fixup! six locks: pcpu mode
-rw-r--r--include/linux/six.h1
-rw-r--r--kernel/locking/six.c32
2 files changed, 31 insertions, 2 deletions
diff --git a/include/linux/six.h b/include/linux/six.h
index 0e6df059341f..477c33eb00d7 100644
--- a/include/linux/six.h
+++ b/include/linux/six.h
@@ -196,6 +196,7 @@ void six_lock_increment(struct six_lock *, enum six_lock_type);
void six_lock_wakeup_all(struct six_lock *);
+void six_lock_pcpu_free_rcu(struct six_lock *);
void six_lock_pcpu_free(struct six_lock *);
void six_lock_pcpu_alloc(struct six_lock *);
diff --git a/kernel/locking/six.c b/kernel/locking/six.c
index 3a83b83df826..fe721891a238 100644
--- a/kernel/locking/six.c
+++ b/kernel/locking/six.c
@@ -8,6 +8,7 @@
#include <linux/sched.h>
#include <linux/sched/rt.h>
#include <linux/six.h>
+#include <linux/slab.h>
#ifdef DEBUG
#define EBUG_ON(cond) BUG_ON(cond)
@@ -563,6 +564,7 @@ static void __six_unlock_type(struct six_lock *lock, enum six_lock_type type)
lock->readers) {
smp_mb(); /* unlock barrier */
this_cpu_dec(*lock->readers);
+ smp_mb(); /* between unlocking and checking for waiters */
state.v = READ_ONCE(lock->state.v);
} else {
EBUG_ON(!(lock->state.v & l[type].held_mask));
@@ -708,6 +710,34 @@ void six_lock_wakeup_all(struct six_lock *lock)
}
EXPORT_SYMBOL_GPL(six_lock_wakeup_all);
+struct free_pcpu_rcu {
+ struct rcu_head rcu;
+ void __percpu *p;
+};
+
+static void free_pcpu_rcu_fn(struct rcu_head *_rcu)
+{
+ struct free_pcpu_rcu *rcu =
+ container_of(_rcu, struct free_pcpu_rcu, rcu);
+
+ free_percpu(rcu->p);
+ kfree(rcu);
+}
+
+void six_lock_pcpu_free_rcu(struct six_lock *lock)
+{
+ struct free_pcpu_rcu *rcu = kzalloc(sizeof(*rcu), GFP_KERNEL);
+
+ if (!rcu)
+ return;
+
+ rcu->p = lock->readers;
+ lock->readers = NULL;
+
+ call_rcu(&rcu->rcu, free_pcpu_rcu_fn);
+}
+EXPORT_SYMBOL_GPL(six_lock_pcpu_free_rcu);
+
void six_lock_pcpu_free(struct six_lock *lock)
{
BUG_ON(lock->readers && pcpu_read_count(lock));
@@ -720,8 +750,6 @@ EXPORT_SYMBOL_GPL(six_lock_pcpu_free);
void six_lock_pcpu_alloc(struct six_lock *lock)
{
- BUG_ON(lock->readers && pcpu_read_count(lock));
- BUG_ON(lock->state.read_lock);
#ifdef __KERNEL__
if (!lock->readers)
lock->readers = alloc_percpu(unsigned);