Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/709/?format=api
{ "id": 709, "url": "http://patchwork.ozlabs.org/api/patches/709/?format=api", "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/20080920.035602.226564809.davem@davemloft.net/", "project": { "id": 7, "url": "http://patchwork.ozlabs.org/api/projects/7/?format=api", "name": "Linux network development", "link_name": "netdev", "list_id": "netdev.vger.kernel.org", "list_email": "netdev@vger.kernel.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20080920.035602.226564809.davem@davemloft.net>", "list_archive_url": null, "date": "2008-09-20T10:56:02", "name": "[2/2] : softirq: Add support for triggering softirq work on softirqs.", "commit_ref": null, "pull_url": null, "state": "rfc", "archived": true, "hash": "5af9a1c820916d8936c17f7d261e39c984281cb2", "submitter": { "id": 15, "url": "http://patchwork.ozlabs.org/api/people/15/?format=api", "name": "David Miller", "email": "davem@davemloft.net" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/20080920.035602.226564809.davem@davemloft.net/mbox/", "series": [], "comments": "http://patchwork.ozlabs.org/api/patches/709/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/709/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<netdev-owner@vger.kernel.org>", "X-Original-To": "patchwork-incoming@ozlabs.org", "Delivered-To": "patchwork-incoming@ozlabs.org", "Received": [ "from vger.kernel.org (vger.kernel.org [209.132.176.167])\n\tby ozlabs.org (Postfix) with ESMTP id 45A8EDDE41\n\tfor <patchwork-incoming@ozlabs.org>;\n\tSat, 20 Sep 2008 20:56:27 +1000 (EST)", "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1751541AbYITK4Q (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tSat, 20 Sep 2008 06:56:16 -0400", "(majordomo@vger.kernel.org) by vger.kernel.org id S1751499AbYITK4Q\n\t(ORCPT <rfc822; netdev-outgoing>); Sat, 20 Sep 2008 06:56:16 -0400", "from 74-93-104-97-Washington.hfc.comcastbusiness.net\n\t([74.93.104.97]:42899\n\t\"EHLO sunset.davemloft.net\" rhost-flags-OK-FAIL-OK-OK)\n\tby vger.kernel.org with ESMTP id S1751510AbYITK4P (ORCPT\n\t<rfc822;netdev@vger.kernel.org>); Sat, 20 Sep 2008 06:56:15 -0400", "from localhost (localhost [127.0.0.1])\n\tby sunset.davemloft.net (Postfix) with ESMTP id D1583C8C181;\n\tSat, 20 Sep 2008 03:56:02 -0700 (PDT)" ], "Date": "Sat, 20 Sep 2008 03:56:02 -0700 (PDT)", "Message-Id": "<20080920.035602.226564809.davem@davemloft.net>", "To": "akpm@linux-foundation.org", "Cc": "linux-kernel@vger.kernel.org, netdev@vger.kernel.org,\n\tjens.axboe@oracle.com, steffen.klassert@secunet.com", "Subject": "Re: [PATCH 2/2]: softirq: Add support for triggering softirq work\n\ton softirqs.", "From": "David Miller <davem@davemloft.net>", "In-Reply-To": "<20080920004608.a3123052.akpm@linux-foundation.org>", "References": "<20080919.234832.127229997.davem@davemloft.net>\n\t<20080920004608.a3123052.akpm@linux-foundation.org>", "X-Mailer": "Mew version 6.1 on Emacs 22.1 / Mule 5.0 (SAKAKI)", "Mime-Version": "1.0", "Content-Type": "Text/Plain; charset=us-ascii", "Content-Transfer-Encoding": "7bit", "Sender": "netdev-owner@vger.kernel.org", "Precedence": "bulk", "List-ID": "<netdev.vger.kernel.org>", "X-Mailing-List": "netdev@vger.kernel.org" }, "content": "From: Andrew Morton <akpm@linux-foundation.org>\nDate: Sat, 20 Sep 2008 00:46:08 -0700\n\n> Took a little staring to work out what that test is doing. Adding\n> \n> \t/* If the list was previouly empty, trigger a softirq run */\n> \n> would be nice.\n\nOk.\n\n> CONFIG_USE_GENERIC_SMP_HELPERS=y, CONFIG_SMP=n shouldn't be possible,\n> if we care..\n\nSure.\n\n> OK, now what's going on with call_single_data.flags?\n\nI've split flags into \"priv\" and \"flags\" u16's.\n\n> Is locking needed to keep that CPU online after this test?\n\nYou already know :)\n\n> Ah. So it is required that the __send_remote_softirq() caller disable\n> local interrupts. There's my locking. It's worth a mention in the\n> interface description, if not a WARN_ON().\n\nFair enough.\n\n> It's best to provide some documentation for global, exported-to-modules\n> functions please.\n\nI've got your kerneldoc right here buddy boy...\n\n> Could use __local_trigger() here I think, although that wouldn't really\n> improve anything much.\n\nThis is a splice, so we'd need to iterate which would be cumbersome\nand error prone.\n\nHere is the updated patch.\n\nsoftirq: Add support for triggering softirq work on softirqs.\n\nThis is basically a genericization of Jens Axboe's block layer\nremote softirq changes.\n\nSigned-off-by: David S. Miller <davem@davemloft.net>\nSigned-off-by: Jens Axboe <jens.axboe@oracle.com>\n---\n include/linux/interrupt.h | 13 +++++\n include/linux/smp.h | 4 +-\n kernel/softirq.c | 128 +++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 144 insertions(+), 1 deletions(-)", "diff": "diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h\nindex fdd7b90..d8713c7 100644\n--- a/include/linux/interrupt.h\n+++ b/include/linux/interrupt.h\n@@ -11,6 +11,8 @@\n #include <linux/hardirq.h>\n #include <linux/sched.h>\n #include <linux/irqflags.h>\n+#include <linux/smp.h>\n+#include <linux/percpu.h>\n #include <asm/atomic.h>\n #include <asm/ptrace.h>\n #include <asm/system.h>\n@@ -271,7 +273,18 @@ extern void softirq_init(void);\n #define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0)\n extern void raise_softirq_irqoff(unsigned int nr);\n extern void raise_softirq(unsigned int nr);\n+DECLARE_PER_CPU(struct list_head, softirq_work_list[NR_SOFTIRQ]);\n \n+/* Try to send a softirq to a remote cpu. If this cannot be done, the\n+ * work will be queued to the local cpu.\n+ */\n+extern void send_remote_softirq(struct call_single_data *cp, int cpu, int softirq);\n+\n+/* Like send_remote_softirq(), but the caller must disable local cpu interrupts\n+ * and compute the current cpu, passed in as 'this_cpu'.\n+ */\n+extern void __send_remote_softirq(struct call_single_data *cp, int cpu,\n+\t\t\t\t int this_cpu, int softirq);\n \n /* Tasklets --- multithreaded analogue of BHs.\n \ndiff --git a/include/linux/smp.h b/include/linux/smp.h\nindex 66484d4..2e4d58b 100644\n--- a/include/linux/smp.h\n+++ b/include/linux/smp.h\n@@ -7,6 +7,7 @@\n */\n \n #include <linux/errno.h>\n+#include <linux/types.h>\n #include <linux/list.h>\n #include <linux/cpumask.h>\n \n@@ -16,7 +17,8 @@ struct call_single_data {\n \tstruct list_head list;\n \tvoid (*func) (void *info);\n \tvoid *info;\n-\tunsigned int flags;\n+\tu16 flags;\n+\tu16 priv;\n };\n \n #ifdef CONFIG_SMP\ndiff --git a/kernel/softirq.c b/kernel/softirq.c\nindex 27642a2..6c7b226 100644\n--- a/kernel/softirq.c\n+++ b/kernel/softirq.c\n@@ -6,6 +6,8 @@\n *\tDistribute under GPLv2.\n *\n *\tRewritten. Old one was good in 2.2, but in 2.3 it was immoral. --ANK (990903)\n+ *\n+ *\tRemote softirq infrastructure is by Jens Axboe.\n */\n \n #include <linux/module.h>\n@@ -463,17 +465,143 @@ void tasklet_kill(struct tasklet_struct *t)\n \n EXPORT_SYMBOL(tasklet_kill);\n \n+DEFINE_PER_CPU(struct list_head, softirq_work_list[NR_SOFTIRQ]);\n+\n+static void __local_trigger(struct call_single_data *cp, int softirq)\n+{\n+\tstruct list_head *head = &__get_cpu_var(softirq_work_list[softirq]);\n+\n+\tlist_add_tail(&cp->list, head);\n+\n+\t/* Trigger the softirq only if the list was previously empty. */\n+\tif (head->next == &cp->list)\n+\t\traise_softirq_irqoff(softirq);\n+}\n+\n+#ifdef CONFIG_USE_GENERIC_SMP_HELPERS\n+static void remote_softirq_receive(void *data)\n+{\n+\tstruct call_single_data *cp = data;\n+\tunsigned long flags;\n+\tint softirq;\n+\n+\tsoftirq = cp->priv;\n+\n+\tlocal_irq_save(flags);\n+\t__local_trigger(cp, softirq);\n+\tlocal_irq_restore(flags);\n+}\n+\n+static int __try_remote_softirq(struct call_single_data *cp, int cpu, int softirq)\n+{\n+\tif (cpu_online(cpu)) {\n+\t\tcp->func = remote_softirq_receive;\n+\t\tcp->info = cp;\n+\t\tcp->flags = 0;\n+\t\tcp->priv = softirq;\n+\n+\t\t__smp_call_function_single(cpu, cp);\n+\t\treturn 0;\n+\t}\n+\treturn 1;\n+}\n+#else /* CONFIG_USE_GENERIC_SMP_HELPERS */\n+static int __try_remote_softirq(struct call_single_data *cp, int cpu, int softirq)\n+{\n+\treturn 1;\n+}\n+#endif\n+\n+/***\n+ * __send_remote_softirq - try to schedule softirq work on a remote cpu\n+ * @cp: private SMP call function data area\n+ * @cpu: the remote cpu\n+ * @this_cpu: the currently executing cpu\n+ * @softirq: the softirq for the work\n+ *\n+ * Attempt to schedule softirq work on a remote cpu. If this cannot be\n+ * done, the work is instead queued up on the local cpu.\n+ *\n+ * Interrupts must be disabled.\n+ */\n+void __send_remote_softirq(struct call_single_data *cp, int cpu, int this_cpu, int softirq)\n+{\n+\tif (cpu == this_cpu || __try_remote_softirq(cp, cpu, softirq))\n+\t\t__local_trigger(cp, softirq);\n+}\n+EXPORT_SYMBOL(__send_remote_softirq);\n+\n+/***\n+ * send_remote_softirq - try to schedule softirq work on a remote cpu\n+ * @cp: private SMP call function data area\n+ * @cpu: the remote cpu\n+ * @softirq: the softirq for the work\n+ *\n+ * Like __send_remote_softirq except that disabling interrupts and\n+ * computing the current cpu is done for the caller.\n+ */\n+void send_remote_softirq(struct call_single_data *cp, int cpu, int softirq)\n+{\n+\tunsigned long flags;\n+\tint this_cpu;\n+\n+\tlocal_irq_save(flags);\n+\tthis_cpu = smp_processor_id();\n+\t__send_remote_softirq(cp, cpu, this_cpu, softirq);\n+\tlocal_irq_restore(flags);\n+}\n+EXPORT_SYMBOL(send_remote_softirq);\n+\n+static int __cpuinit remote_softirq_cpu_notify(struct notifier_block *self,\n+\t\t\t\t\t unsigned long action, void *hcpu)\n+{\n+\t/*\n+\t * If a CPU goes away, splice its entries to the current CPU\n+\t * and trigger a run of the softirq\n+\t */\n+\tif (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {\n+\t\tint cpu = (unsigned long) hcpu;\n+\t\tint i;\n+\n+\t\tlocal_irq_disable();\n+\t\tfor (i = 0; i < NR_SOFTIRQ; i++) {\n+\t\t\tstruct list_head *head = &per_cpu(softirq_work_list[i], cpu);\n+\t\t\tstruct list_head *local_head;\n+\n+\t\t\tif (list_empty(head))\n+\t\t\t\tcontinue;\n+\n+\t\t\tlocal_head = &__get_cpu_var(softirq_work_list[i]);\n+\t\t\tlist_splice_init(head, local_head);\n+\t\t\traise_softirq_irqoff(i);\n+\t\t}\n+\t\tlocal_irq_enable();\n+\t}\n+\n+\treturn NOTIFY_OK;\n+}\n+\n+static struct notifier_block __cpuinitdata remote_softirq_cpu_notifier = {\n+\t.notifier_call\t= remote_softirq_cpu_notify,\n+};\n+\n void __init softirq_init(void)\n {\n \tint cpu;\n \n \tfor_each_possible_cpu(cpu) {\n+\t\tint i;\n+\n \t\tper_cpu(tasklet_vec, cpu).tail =\n \t\t\t&per_cpu(tasklet_vec, cpu).head;\n \t\tper_cpu(tasklet_hi_vec, cpu).tail =\n \t\t\t&per_cpu(tasklet_hi_vec, cpu).head;\n+\t\tfor (i = 0; i < NR_SOFTIRQ; i++)\n+\t\t\tINIT_LIST_HEAD(&per_cpu(softirq_work_list[i], cpu));\n \t}\n \n+\tregister_hotcpu_notifier(&remote_softirq_cpu_notifier);\n+\n \topen_softirq(TASKLET_SOFTIRQ, tasklet_action);\n \topen_softirq(HI_SOFTIRQ, tasklet_hi_action);\n }\n", "prefixes": [ "2/2" ] }