lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 23 Jan 2018 15:59:32 +0800
From:   <lianglihao@...wei.com>
To:     <paulmck@...ux.vnet.ibm.com>
CC:     <guohanjun@...wei.com>, <heng.z@...wei.com>, <hb.chen@...wei.com>,
        <lihao.liang@...il.com>, <linux-kernel@...r.kernel.org>
Subject: [PATCH RFC 07/16] prcu: Implement call_prcu() API

From: Lihao Liang <lianglihao@...wei.com>

This is PRCU's counterpart of RCU's call_rcu() API.

Reviewed-by: Heng Zhang <heng.z@...wei.com>
Signed-off-by: Lihao Liang <lianglihao@...wei.com>
---
 include/linux/prcu.h | 25 ++++++++++++++++++++
 init/main.c          |  2 ++
 kernel/rcu/prcu.c    | 67 +++++++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 91 insertions(+), 3 deletions(-)

diff --git a/include/linux/prcu.h b/include/linux/prcu.h
index 653b4633..e5e09c9b 100644
--- a/include/linux/prcu.h
+++ b/include/linux/prcu.h
@@ -2,15 +2,36 @@
 #define __LINUX_PRCU_H
 
 #include <linux/atomic.h>
+#include <linux/types.h>
 #include <linux/mutex.h>
 #include <linux/wait.h>
 
 #define CONFIG_PRCU
 
+struct prcu_version_head {
+	unsigned long long version;
+	struct prcu_version_head *next;
+};
+
+/* Simple unsegmented callback list for PRCU. */
+struct prcu_cblist {
+	struct rcu_head *head;
+	struct rcu_head **tail;
+	struct prcu_version_head *version_head;
+	struct prcu_version_head **version_tail;
+	long len;
+};
+
+#define PRCU_CBLIST_INITIALIZER(n) { \
+	.head = NULL, .tail = &n.head, \
+	.version_head = NULL, .version_tail = &n.version_head, \
+}
+
 struct prcu_local_struct {
 	unsigned int locked;
 	unsigned int online;
 	unsigned long long version;
+	struct prcu_cblist cblist;
 };
 
 struct prcu_struct {
@@ -24,6 +45,8 @@ struct prcu_struct {
 void prcu_read_lock(void);
 void prcu_read_unlock(void);
 void synchronize_prcu(void);
+void call_prcu(struct rcu_head *head, rcu_callback_t func);
+void prcu_init(void);
 void prcu_note_context_switch(void);
 
 #else /* #ifdef CONFIG_PRCU */
@@ -31,6 +54,8 @@ void prcu_note_context_switch(void);
 #define prcu_read_lock() do {} while (0)
 #define prcu_read_unlock() do {} while (0)
 #define synchronize_prcu() do {} while (0)
+#define call_prcu() do {} while (0)
+#define prcu_init() do {} while (0)
 #define prcu_note_context_switch() do {} while (0)
 
 #endif /* #ifdef CONFIG_PRCU */
diff --git a/init/main.c b/init/main.c
index f8665104..4925964e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -38,6 +38,7 @@
 #include <linux/smp.h>
 #include <linux/profile.h>
 #include <linux/rcupdate.h>
+#include <linux/prcu.h>
 #include <linux/moduleparam.h>
 #include <linux/kallsyms.h>
 #include <linux/writeback.h>
@@ -574,6 +575,7 @@ asmlinkage __visible void __init start_kernel(void)
 	workqueue_init_early();
 
 	rcu_init();
+	prcu_init();
 
 	/* Trace events are available after this */
 	trace_init();
diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c
index a00b9420..f198285c 100644
--- a/kernel/rcu/prcu.c
+++ b/kernel/rcu/prcu.c
@@ -1,11 +1,12 @@
 #include <linux/smp.h>
-#include <linux/prcu.h>
 #include <linux/percpu.h>
-#include <linux/compiler.h>
+#include <linux/prcu.h>
 #include <linux/sched.h>
-
+#include <linux/slab.h>
 #include <asm/barrier.h>
 
+#include "rcu.h"
+
 DEFINE_PER_CPU_SHARED_ALIGNED(struct prcu_local_struct, prcu_local);
 
 struct prcu_struct global_prcu = {
@@ -16,6 +17,16 @@ struct prcu_struct global_prcu = {
 };
 struct prcu_struct *prcu = &global_prcu;
 
+/* Initialize simple callback list. */
+static void prcu_cblist_init(struct prcu_cblist *rclp)
+{
+	rclp->head = NULL;
+	rclp->tail = &rclp->head;
+	rclp->version_head = NULL;
+	rclp->version_tail = &rclp->version_head;
+	rclp->len = 0;
+}
+
 static inline void prcu_report(struct prcu_local_struct *local)
 {
 	unsigned long long global_version;
@@ -123,3 +134,53 @@ void prcu_note_context_switch(void)
 	prcu_report(local);
 	put_cpu_ptr(&prcu_local);
 }
+
+void call_prcu(struct rcu_head *head, rcu_callback_t func)
+{
+	unsigned long flags;
+	struct prcu_local_struct *local;
+	struct prcu_cblist *rclp;
+	struct prcu_version_head *vhp;
+
+	debug_rcu_head_queue(head);
+
+	/* Use GFP_ATOMIC with IRQs disabled */
+	vhp = kmalloc(sizeof(struct prcu_version_head), GFP_ATOMIC);
+	if (!vhp)
+		return;
+
+	head->func = func;
+	head->next = NULL;
+	vhp->next = NULL;
+
+	local_irq_save(flags);
+	local = this_cpu_ptr(&prcu_local);
+	vhp->version = local->version;
+	rclp = &local->cblist;
+	rclp->len++;
+	*rclp->tail = head;
+	rclp->tail = &head->next;
+	*rclp->version_tail = vhp;
+	rclp->version_tail = &vhp->next;
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(call_prcu);
+
+void prcu_init_local_struct(int cpu)
+{
+	struct prcu_local_struct *local;
+
+	local = per_cpu_ptr(&prcu_local, cpu);
+	local->locked = 0;
+	local->online = 0;
+	local->version = 0;
+	prcu_cblist_init(&local->cblist);
+}
+
+void __init prcu_init(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu)
+		prcu_init_local_struct(cpu);
+}
-- 
2.14.1.729.g59c0ea183

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ