Received: by 10.223.176.46 with SMTP id f43csp3878370wra; Tue, 23 Jan 2018 00:12:15 -0800 (PST) X-Google-Smtp-Source: AH8x227lrViZZLXWF9biMYf9SrFy0Yc9QJ5qAI3adQUTQ+dOnTHw6IdBhfwT1GXvc+bEqBszJfIU X-Received: by 10.99.116.88 with SMTP id e24mr8108713pgn.279.1516695135356; Tue, 23 Jan 2018 00:12:15 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516695135; cv=none; d=google.com; s=arc-20160816; b=HaoHi5L4beDxjwNH+GuQE3nZx6C3pIQ6Yi4JSDKVQzavfzcTfVaxIOGbex52hB5Dte QMsq4Ge6o2JwUkrGtQxgfBL/v5P+FT1Lq32mQBRxlCHVz6zDmiXy+4M/6pYez69nJMM+ X1iNt5gbQbqilGdDsgTrfTdBaerAlCB1mXUPQYom/XYJ3Xl4ATSn+UvOxgG5VDnILfCt ODCuFeFOg6nyVk7nfMRgeeE4h7o4jpG4LwM4kAxqOviNdY1S50kQ1NSovBNV/UP1Sh/r jVwBTkZ/8pUTXPxdRgF4vRMarqRwWXYtPlXp51ZysSYF5uAgGwWhLvHzxlgZFeBwOGOw BzFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=Am3DmofRPz2RxIu9lCV2odbVIF9SyggcvIjv5zO+nGA=; b=TyMM1e8w5FlJL8XDw8FvKOYLoWbzcuGBFwvmTAFlpiPruos7suaIdhvL8BzmW01Blz qcPN/E4LOVWmgRBkgQuwDYTgBIN/PuOFXApEfnHx9uAABpDSjwFvncbRdnp6Z5OmCu11 OWFfZYpGu9DjP2+EIOvgRVpoqG1jrAWeCywl4FIp/e+LZZ7xdGpdbvEMD5PXmZ3V1LKR H2AiCyzLFm3N4PZwhljg4XvX1Yxsi3brB5PF3fG/oim8ZGP2NGiv3vpsG8qRF2phxs2F S+0dxnmv6AjMdgOHjOUPVFD1PMPRs4SWqz2XDAwiqTDNaGgHKoT8y935fQ0duYcfvS8W O9WA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 38-v6si4366328pln.64.2018.01.23.00.12.01; Tue, 23 Jan 2018 00:12:15 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751452AbeAWIKJ (ORCPT + 99 others); Tue, 23 Jan 2018 03:10:09 -0500 Received: from szxga05-in.huawei.com ([45.249.212.191]:4717 "EHLO huawei.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751178AbeAWIIw (ORCPT ); Tue, 23 Jan 2018 03:08:52 -0500 Received: from DGGEMS409-HUB.china.huawei.com (unknown [172.30.72.59]) by Forcepoint Email with ESMTP id B181AD3A6EE54; Tue, 23 Jan 2018 16:08:36 +0800 (CST) Received: from huawei.com (10.175.102.37) by DGGEMS409-HUB.china.huawei.com (10.3.19.209) with Microsoft SMTP Server id 14.3.361.1; Tue, 23 Jan 2018 16:08:29 +0800 From: To: CC: , , , , Subject: [PATCH RFC 08/16] prcu: Implement PRCU callback processing Date: Tue, 23 Jan 2018 15:59:33 +0800 Message-ID: <1516694381-20333-9-git-send-email-lianglihao@huawei.com> X-Mailer: git-send-email 1.7.12.4 In-Reply-To: <1516694381-20333-1-git-send-email-lianglihao@huawei.com> References: <1516694381-20333-1-git-send-email-lianglihao@huawei.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.175.102.37] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Lihao Liang Currently, PRCU core processing only consists of callback processing in prcu_process_callbacks(), which is triggered by the scheduling-clock interrupt. Reviewed-by: Heng Zhang Signed-off-by: Lihao Liang --- include/linux/interrupt.h | 3 ++ include/linux/prcu.h | 8 +++++ kernel/rcu/prcu.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++ kernel/rcu/tree.c | 1 + kernel/time/timer.c | 2 ++ 5 files changed, 100 insertions(+) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 0991f973..f05ef62a 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -456,6 +456,9 @@ enum SCHED_SOFTIRQ, HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the numbering. Sigh! */ +#ifdef CONFIG_PRCU + PRCU_SOFTIRQ, +#endif RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ NR_SOFTIRQS diff --git a/include/linux/prcu.h b/include/linux/prcu.h index e5e09c9b..4e7d5d65 100644 --- a/include/linux/prcu.h +++ b/include/linux/prcu.h @@ -31,11 +31,13 @@ struct prcu_local_struct { unsigned int locked; unsigned int online; unsigned long long version; + unsigned long long cb_version; struct prcu_cblist cblist; }; struct prcu_struct { atomic64_t global_version; + atomic64_t cb_version; atomic_t active_ctr; struct mutex mtx; wait_queue_head_t wait_q; @@ -48,6 +50,9 @@ 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); +int prcu_pending(void); +void invoke_prcu_core(void); +void prcu_check_callbacks(void); #else /* #ifdef CONFIG_PRCU */ @@ -57,6 +62,9 @@ void prcu_note_context_switch(void); #define call_prcu() do {} while (0) #define prcu_init() do {} while (0) #define prcu_note_context_switch() do {} while (0) +#define prcu_pending() 0 +#define invoke_prcu_core() do {} while (0) +#define prcu_check_callbacks() do {} while (0) #endif /* #ifdef CONFIG_PRCU */ #endif /* __LINUX_PRCU_H */ diff --git a/kernel/rcu/prcu.c b/kernel/rcu/prcu.c index f198285c..373039c5 100644 --- a/kernel/rcu/prcu.c +++ b/kernel/rcu/prcu.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -11,6 +12,7 @@ DEFINE_PER_CPU_SHARED_ALIGNED(struct prcu_local_struct, prcu_local); struct prcu_struct global_prcu = { .global_version = ATOMIC64_INIT(0), + .cb_version = ATOMIC64_INIT(0), .active_ctr = ATOMIC_INIT(0), .mtx = __MUTEX_INITIALIZER(global_prcu.mtx), .wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(global_prcu.wait_q) @@ -27,6 +29,35 @@ static void prcu_cblist_init(struct prcu_cblist *rclp) rclp->len = 0; } +/* + * Dequeue the oldest rcu_head structure from the specified callback list; + * store the callback grace period version number into the version pointer. + */ +static struct rcu_head *prcu_cblist_dequeue(struct prcu_cblist *rclp) +{ + struct rcu_head *rhp; + struct prcu_version_head *vhp; + + rhp = rclp->head; + if (!rhp) { + WARN_ON(vhp); + WARN_ON(rclp->len); + return NULL; + } + + vhp = rclp->version_head; + rclp->version_head = vhp->next; + rclp->head = rhp->next; + rclp->len--; + + if (!rclp->head) { + rclp->tail = &rclp->head; + rclp->version_tail = &rclp->version_head; + } + + return rhp; +} + static inline void prcu_report(struct prcu_local_struct *local) { unsigned long long global_version; @@ -117,6 +148,7 @@ void synchronize_prcu(void) if (atomic_read(&prcu->active_ctr)) wait_event(prcu->wait_q, !atomic_read(&prcu->active_ctr)); + atomic64_set(&prcu->cb_version, version); mutex_unlock(&prcu->mtx); } EXPORT_SYMBOL(synchronize_prcu); @@ -166,6 +198,58 @@ void call_prcu(struct rcu_head *head, rcu_callback_t func) } EXPORT_SYMBOL(call_prcu); +int prcu_pending(void) +{ + struct prcu_local_struct *local = get_cpu_ptr(&prcu_local); + unsigned long long cb_version = local->cb_version; + struct prcu_cblist *rclp = &local->cblist; + + put_cpu_ptr(&prcu_local); + return cb_version < atomic64_read(&prcu->cb_version) && rclp->head; +} + +void invoke_prcu_core(void) +{ + if (cpu_online(smp_processor_id())) + raise_softirq(PRCU_SOFTIRQ); +} + +void prcu_check_callbacks(void) +{ + if (prcu_pending()) + invoke_prcu_core(); +} + +static __latent_entropy void prcu_process_callbacks(struct softirq_action *unused) +{ + unsigned long flags; + unsigned long long cb_version; + struct prcu_local_struct *local; + struct prcu_cblist *rclp; + struct rcu_head *rhp; + struct prcu_version_head *vhp; + + if (cpu_is_offline(smp_processor_id())) + return; + + cb_version = atomic64_read(&prcu->cb_version); + + /* Disable interrupts to prevent races with call_prcu() */ + local_irq_save(flags); + local = this_cpu_ptr(&prcu_local); + rclp = &local->cblist; + rhp = rclp->head; + vhp = rclp->version_head; + for (; rhp && vhp && vhp->version < cb_version; + rhp = rclp->head, vhp = rclp->version_head) { + rhp = prcu_cblist_dequeue(rclp); + debug_rcu_head_unqueue(rhp); + rhp->func(rhp); + } + local->cb_version = cb_version; + local_irq_restore(flags); +} + void prcu_init_local_struct(int cpu) { struct prcu_local_struct *local; @@ -174,6 +258,7 @@ void prcu_init_local_struct(int cpu) local->locked = 0; local->online = 0; local->version = 0; + local->cb_version = 0; prcu_cblist_init(&local->cblist); } @@ -181,6 +266,7 @@ void __init prcu_init(void) { int cpu; + open_softirq(PRCU_SOFTIRQ, prcu_process_callbacks); for_each_possible_cpu(cpu) prcu_init_local_struct(cpu); } diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index e354e475..46910114 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2852,6 +2852,7 @@ void rcu_check_callbacks(int user) { trace_rcu_utilization(TPS("Start scheduler-tick")); increment_cpu_stall_ticks(); + if (user || rcu_is_cpu_rrupt_from_idle()) { /* diff --git a/kernel/time/timer.c b/kernel/time/timer.c index d3f33020..ed863e63 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -1568,6 +1569,7 @@ void update_process_times(int user_tick) /* Note: this timer irq context must be accounted for as well. */ account_process_tick(p, user_tick); run_local_timers(); + prcu_check_callbacks(); rcu_check_callbacks(user_tick); #ifdef CONFIG_IRQ_WORK if (in_irq()) -- 2.14.1.729.g59c0ea183