All of lore.kernel.org
 help / color / mirror / Atom feed
From: Oleg Nesterov <oleg@redhat.com>
To: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Mimi Zohar <zohar@linux.vnet.ibm.com>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	". James Morris" <jmorris@namei.org>,
	linux-security-module@vger.kernel.org,
	linux-kernel <linux-kernel@vger.kernel.org>,
	David Howells <dhowells@redhat.com>
Subject: [PATCH 1/4] task_work: use the single-linked list to shrink sizeof(task_work)
Date: Wed, 27 Jun 2012 20:37:42 +0200	[thread overview]
Message-ID: <20120627183742.GB23086@redhat.com> (raw)
In-Reply-To: <20120627183721.GA23086@redhat.com>

Change struct task_work to have a single forward pointer. The pending
task_work's create the circular list, and task->last_twork points to
the last element. This way we can access head/tail in O(1).

Suggested-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 include/linux/sched.h     |    3 +-
 include/linux/task_work.h |    5 +--
 include/linux/tracehook.h |    4 +-
 kernel/fork.c             |    2 +-
 kernel/task_work.c        |   62 +++++++++++++++++++++++++-------------------
 5 files changed, 42 insertions(+), 34 deletions(-)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4059c0f..5486299 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -101,6 +101,7 @@ struct bio_list;
 struct fs_struct;
 struct perf_event_context;
 struct blk_plug;
+struct task_work;
 
 /*
  * List of flags we want to share for kernel threads,
@@ -1405,7 +1406,7 @@ struct task_struct {
 	int (*notifier)(void *priv);
 	void *notifier_data;
 	sigset_t *notifier_mask;
-	struct hlist_head task_works;
+	struct task_work *last_twork;
 
 	struct audit_context *audit_context;
 #ifdef CONFIG_AUDITSYSCALL
diff --git a/include/linux/task_work.h b/include/linux/task_work.h
index 294d5d5..03640fb 100644
--- a/include/linux/task_work.h
+++ b/include/linux/task_work.h
@@ -1,14 +1,13 @@
 #ifndef _LINUX_TASK_WORK_H
 #define _LINUX_TASK_WORK_H
 
-#include <linux/list.h>
 #include <linux/sched.h>
 
 struct task_work;
 typedef void (*task_work_func_t)(struct task_work *);
 
 struct task_work {
-	struct hlist_node hlist;
+	struct task_work *next;
 	task_work_func_t func;
 	void *data;
 };
@@ -26,7 +25,7 @@ void task_work_run(void);
 
 static inline void exit_task_work(struct task_struct *task)
 {
-	if (unlikely(!hlist_empty(&task->task_works)))
+	if (unlikely(task->last_twork))
 		task_work_run();
 }
 
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
index 6a4d82b..89e88fe 100644
--- a/include/linux/tracehook.h
+++ b/include/linux/tracehook.h
@@ -189,10 +189,10 @@ static inline void tracehook_notify_resume(struct pt_regs *regs)
 	/*
 	 * The caller just cleared TIF_NOTIFY_RESUME. This barrier
 	 * pairs with task_work_add()->set_notify_resume() after
-	 * hlist_add_head(task->task_works);
+	 * addition to task->last_twork list.
 	 */
 	smp_mb__after_clear_bit();
-	if (unlikely(!hlist_empty(&current->task_works)))
+	if (unlikely(current->last_twork))
 		task_work_run();
 }
 
diff --git a/kernel/fork.c b/kernel/fork.c
index ab5211b..075000b 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1415,7 +1415,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	 */
 	p->group_leader = p;
 	INIT_LIST_HEAD(&p->thread_group);
-	INIT_HLIST_HEAD(&p->task_works);
+	p->last_twork = NULL;
 
 	/* Now that the task is set up, run cgroup callbacks if
 	 * necessary. We need to run them before the task is visible
diff --git a/kernel/task_work.c b/kernel/task_work.c
index 82d1c79..a0a3133 100644
--- a/kernel/task_work.c
+++ b/kernel/task_work.c
@@ -2,10 +2,15 @@
 #include <linux/task_work.h>
 #include <linux/tracehook.h>
 
+/*
+ * task->last_twork points to the last node in the circular single-linked list.
+ */
+
 int
 task_work_add(struct task_struct *task, struct task_work *twork, bool notify)
 {
 	unsigned long flags;
+	struct task_work *last;
 	int err = -ESRCH;
 
 #ifndef TIF_NOTIFY_RESUME
@@ -19,7 +24,10 @@ task_work_add(struct task_struct *task, struct task_work *twork, bool notify)
 	 */
 	raw_spin_lock_irqsave(&task->pi_lock, flags);
 	if (likely(!(task->flags & PF_EXITING))) {
-		hlist_add_head(&twork->hlist, &task->task_works);
+		last = task->last_twork ?: twork;
+		task->last_twork = twork;
+		twork->next = last->next;
+		last->next = twork;
 		err = 0;
 	}
 	raw_spin_unlock_irqrestore(&task->pi_lock, flags);
@@ -34,15 +42,26 @@ struct task_work *
 task_work_cancel(struct task_struct *task, task_work_func_t func)
 {
 	unsigned long flags;
-	struct task_work *twork;
-	struct hlist_node *pos;
+	struct task_work *last, *prev, *twork;
 
 	raw_spin_lock_irqsave(&task->pi_lock, flags);
-	hlist_for_each_entry(twork, pos, &task->task_works, hlist) {
-		if (twork->func == func) {
-			hlist_del(&twork->hlist);
+	last = task->last_twork;
+	if (last) {
+		twork = last;
+		do {
+			prev = twork;
+			twork = twork->next;
+			if (twork->func != func)
+				continue;
+
+			prev->next = twork->next;
+			if (twork == last) {
+				if (prev == twork)
+					prev = NULL;
+				task->last_twork = prev;
+			}
 			goto found;
-		}
+		} while (twork != last);
 	}
 	twork = NULL;
  found:
@@ -54,31 +73,20 @@ task_work_cancel(struct task_struct *task, task_work_func_t func)
 void task_work_run(void)
 {
 	struct task_struct *task = current;
-	struct hlist_head task_works;
-	struct hlist_node *pos;
+	struct task_work *last, *next, *twork;
 
 	raw_spin_lock_irq(&task->pi_lock);
-	hlist_move_list(&task->task_works, &task_works);
+	last = task->last_twork;
+	task->last_twork = NULL;
 	raw_spin_unlock_irq(&task->pi_lock);
 
-	if (unlikely(hlist_empty(&task_works)))
+	if (unlikely(!last))
 		return;
-	/*
-	 * We use hlist to save the space in task_struct, but we want fifo.
-	 * Find the last entry, the list should be short, then process them
-	 * in reverse order.
-	 */
-	for (pos = task_works.first; pos->next; pos = pos->next)
-		;
 
-	for (;;) {
-		struct hlist_node **pprev = pos->pprev;
-		struct task_work *twork = container_of(pos, struct task_work,
-							hlist);
+	next = last->next;
+	do {
+		twork = next;
+		next = twork->next;
 		twork->func(twork);
-
-		if (pprev == &task_works.first)
-			break;
-		pos = container_of(pprev, struct hlist_node, next);
-	}
+	} while (twork != last);
 }
-- 
1.5.5.1



  reply	other threads:[~2012-06-27 18:40 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-06-22 12:44 deferring __fput() Mimi Zohar
2012-06-23  9:20 ` Al Viro
2012-06-23 19:45   ` Al Viro
2012-06-23 20:38     ` Oleg Nesterov
2012-06-23 21:01       ` Al Viro
2012-06-23 21:11         ` Al Viro
2012-06-24  4:16         ` Al Viro
2012-06-24 10:09           ` Al Viro
2012-06-24 16:54             ` Oleg Nesterov
2012-06-24 15:33           ` Oleg Nesterov
2012-06-25  6:03             ` Al Viro
2012-06-25 15:18               ` Oleg Nesterov
2012-06-27 18:37                 ` [PATCH 0/4] Was: " Oleg Nesterov
2012-06-27 18:37                   ` Oleg Nesterov [this message]
2012-06-27 18:37                   ` [PATCH 2/4] task_work: don't rely on PF_EXITING Oleg Nesterov
2012-06-27 18:38                   ` [PATCH 3/4] task_work: deal with task_work callbacks adding more work Oleg Nesterov
2012-06-27 18:38                   ` [PATCH 4/4] task_work: kill task_work->data Oleg Nesterov
2012-06-27 19:05                     ` Oleg Nesterov
2012-06-28  4:38                   ` [PATCH 0/4] Was: deferring __fput() Al Viro
2012-06-28 16:22                     ` Oleg Nesterov
2012-06-28 16:45                       ` Oleg Nesterov
2012-06-30  6:24                         ` Al Viro
2012-06-30 17:41                           ` Oleg Nesterov
2012-06-29  5:30                     ` Mimi Zohar
2012-06-29  8:33                       ` Al Viro
2012-06-29 13:02                         ` Mimi Zohar
2012-06-29 17:41                           ` Al Viro
2012-06-29 21:38                             ` Mimi Zohar
2012-06-29 23:56                               ` Mimi Zohar
2012-06-30  5:02                                 ` Al Viro
2012-07-01 19:50                                   ` Mimi Zohar
2012-07-01 20:57                                     ` Al Viro
2012-07-02  1:46                                       ` Mimi Zohar
2012-07-02  3:43                                         ` Al Viro
2012-07-02  5:11                                           ` Al Viro
2012-07-02 11:49                                             ` Mimi Zohar
2012-07-02 12:02                                               ` Al Viro
2012-07-02 13:01                                                 ` Mimi Zohar
2012-07-02 13:33                                                   ` Al Viro
2012-07-02 14:50                                                     ` Mimi Zohar
2012-08-21 13:05                                                       ` [PATCH] task_work: add a scheduling point in task_work_run() Eric Dumazet
2012-08-21 20:37                                                         ` Mimi Zohar
2012-08-21 21:32                                                           ` Eric Dumazet
2012-08-22  3:13                                                             ` Mimi Zohar
2012-08-22  5:27                                                         ` Michael Wang
2012-08-22  5:38                                                           ` Al Viro
2012-06-23 20:57     ` deferring __fput() Al Viro
2012-06-23 21:33       ` Al Viro
2012-06-24 15:20       ` Oleg Nesterov
2012-06-24 18:11         ` Oleg Nesterov
2012-06-25 12:03       ` Peter Zijlstra
2012-06-25 12:14         ` Al Viro
2012-06-25 13:19           ` Peter Zijlstra
2012-06-25 13:53             ` Al Viro

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120627183742.GB23086@redhat.com \
    --to=oleg@redhat.com \
    --cc=dhowells@redhat.com \
    --cc=jmorris@namei.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=viro@ZenIV.linux.org.uk \
    --cc=zohar@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.