blob: 8afbb5fafca366d0fb3af6b8e88ba327b037febd [file] [log] [blame]
Arvind M8e87d852018-01-29 00:04:29 -08001From d9b50f18d7a153a77a2127bf5db11b3a076cfc30 Mon Sep 17 00:00:00 2001
Allen Martin685e0f82016-07-26 19:34:29 -07002From: Thomas Gleixner <tglx@linutronix.de>
3Date: Fri, 3 Jul 2009 08:44:56 -0500
Arvind M10268e72017-12-04 22:18:06 -08004Subject: [PATCH 013/366] signals: Allow rt tasks to cache one sigqueue struct
Allen Martin685e0f82016-07-26 19:34:29 -07005
6To avoid allocation allow rt tasks to cache one sigqueue struct in
7task struct.
8
9Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Allen Martin685e0f82016-07-26 19:34:29 -070010---
11 include/linux/sched.h | 1 +
12 include/linux/signal.h | 1 +
13 kernel/exit.c | 2 +-
14 kernel/fork.c | 1 +
15 kernel/signal.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++---
16 5 files changed, 69 insertions(+), 5 deletions(-)
17
18diff --git a/include/linux/sched.h b/include/linux/sched.h
Arvind M10268e72017-12-04 22:18:06 -080019index faadab9..114cbfa 100644
Allen Martin685e0f82016-07-26 19:34:29 -070020--- a/include/linux/sched.h
21+++ b/include/linux/sched.h
Allen Martinfc468d82016-11-15 17:57:52 -080022@@ -1580,6 +1580,7 @@ struct task_struct {
Allen Martin685e0f82016-07-26 19:34:29 -070023 /* signal handlers */
24 struct signal_struct *signal;
25 struct sighand_struct *sighand;
26+ struct sigqueue *sigqueue_cache;
27
28 sigset_t blocked, real_blocked;
29 sigset_t saved_sigmask; /* restored if set_restore_sigmask() was used */
30diff --git a/include/linux/signal.h b/include/linux/signal.h
Ishan Mittalb7998262017-01-17 16:11:50 +053031index d80259a..ddd1e68 100644
Allen Martin685e0f82016-07-26 19:34:29 -070032--- a/include/linux/signal.h
33+++ b/include/linux/signal.h
Allen Martinfc468d82016-11-15 17:57:52 -080034@@ -233,6 +233,7 @@ static inline void init_sigpending(struct sigpending *sig)
Allen Martin685e0f82016-07-26 19:34:29 -070035 }
36
37 extern void flush_sigqueue(struct sigpending *queue);
38+extern void flush_task_sigqueue(struct task_struct *tsk);
39
40 /* Test if 'sig' is valid signal. Use this instead of testing _NSIG directly */
41 static inline int valid_signal(unsigned long sig)
42diff --git a/kernel/exit.c b/kernel/exit.c
Ishan Mittalb7998262017-01-17 16:11:50 +053043index ffba5df..e199407 100644
Allen Martin685e0f82016-07-26 19:34:29 -070044--- a/kernel/exit.c
45+++ b/kernel/exit.c
46@@ -144,7 +144,7 @@ static void __exit_signal(struct task_struct *tsk)
47 * Do this under ->siglock, we can race with another thread
48 * doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals.
49 */
50- flush_sigqueue(&tsk->pending);
51+ flush_task_sigqueue(tsk);
52 tsk->sighand = NULL;
53 spin_unlock(&sighand->siglock);
54
55diff --git a/kernel/fork.c b/kernel/fork.c
Arvind M10268e72017-12-04 22:18:06 -080056index f7cb034..81550ca 100644
Allen Martin685e0f82016-07-26 19:34:29 -070057--- a/kernel/fork.c
58+++ b/kernel/fork.c
Arvind M10268e72017-12-04 22:18:06 -080059@@ -1364,6 +1364,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
Allen Martin685e0f82016-07-26 19:34:29 -070060 spin_lock_init(&p->alloc_lock);
61
62 init_sigpending(&p->pending);
63+ p->sigqueue_cache = NULL;
64
65 p->utime = p->stime = p->gtime = 0;
66 p->utimescaled = p->stimescaled = 0;
67diff --git a/kernel/signal.c b/kernel/signal.c
Ishan Mittalb7998262017-01-17 16:11:50 +053068index c1bac41..0e08feb 100644
Allen Martin685e0f82016-07-26 19:34:29 -070069--- a/kernel/signal.c
70+++ b/kernel/signal.c
71@@ -14,6 +14,7 @@
72 #include <linux/export.h>
73 #include <linux/init.h>
74 #include <linux/sched.h>
75+#include <linux/sched/rt.h>
76 #include <linux/fs.h>
77 #include <linux/tty.h>
78 #include <linux/binfmts.h>
79@@ -352,13 +353,30 @@ static bool task_participate_group_stop(struct task_struct *task)
80 return false;
81 }
82
83+static inline struct sigqueue *get_task_cache(struct task_struct *t)
84+{
85+ struct sigqueue *q = t->sigqueue_cache;
86+
87+ if (cmpxchg(&t->sigqueue_cache, q, NULL) != q)
88+ return NULL;
89+ return q;
90+}
91+
92+static inline int put_task_cache(struct task_struct *t, struct sigqueue *q)
93+{
94+ if (cmpxchg(&t->sigqueue_cache, NULL, q) == NULL)
95+ return 0;
96+ return 1;
97+}
98+
99 /*
100 * allocate a new signal queue record
101 * - this may be called without locks if and only if t == current, otherwise an
102 * appropriate lock must be held to stop the target task from exiting
103 */
104 static struct sigqueue *
105-__sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimit)
106+__sigqueue_do_alloc(int sig, struct task_struct *t, gfp_t flags,
107+ int override_rlimit, int fromslab)
108 {
109 struct sigqueue *q = NULL;
110 struct user_struct *user;
111@@ -375,7 +393,10 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi
112 if (override_rlimit ||
113 atomic_read(&user->sigpending) <=
114 task_rlimit(t, RLIMIT_SIGPENDING)) {
115- q = kmem_cache_alloc(sigqueue_cachep, flags);
116+ if (!fromslab)
117+ q = get_task_cache(t);
118+ if (!q)
119+ q = kmem_cache_alloc(sigqueue_cachep, flags);
120 } else {
121 print_dropped_signal(sig);
122 }
123@@ -392,6 +413,13 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi
124 return q;
125 }
126
127+static struct sigqueue *
128+__sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags,
129+ int override_rlimit)
130+{
131+ return __sigqueue_do_alloc(sig, t, flags, override_rlimit, 0);
132+}
133+
134 static void __sigqueue_free(struct sigqueue *q)
135 {
136 if (q->flags & SIGQUEUE_PREALLOC)
137@@ -401,6 +429,21 @@ static void __sigqueue_free(struct sigqueue *q)
138 kmem_cache_free(sigqueue_cachep, q);
139 }
140
141+static void sigqueue_free_current(struct sigqueue *q)
142+{
143+ struct user_struct *up;
144+
145+ if (q->flags & SIGQUEUE_PREALLOC)
146+ return;
147+
148+ up = q->user;
149+ if (rt_prio(current->normal_prio) && !put_task_cache(current, q)) {
150+ atomic_dec(&up->sigpending);
151+ free_uid(up);
152+ } else
153+ __sigqueue_free(q);
154+}
155+
156 void flush_sigqueue(struct sigpending *queue)
157 {
158 struct sigqueue *q;
159@@ -414,6 +457,21 @@ void flush_sigqueue(struct sigpending *queue)
160 }
161
162 /*
163+ * Called from __exit_signal. Flush tsk->pending and
164+ * tsk->sigqueue_cache
165+ */
166+void flush_task_sigqueue(struct task_struct *tsk)
167+{
168+ struct sigqueue *q;
169+
170+ flush_sigqueue(&tsk->pending);
171+
172+ q = get_task_cache(tsk);
173+ if (q)
174+ kmem_cache_free(sigqueue_cachep, q);
175+}
176+
177+/*
178 * Flush all pending signals for this kthread.
179 */
180 void flush_signals(struct task_struct *t)
181@@ -525,7 +583,7 @@ static void collect_signal(int sig, struct sigpending *list, siginfo_t *info)
182 still_pending:
183 list_del_init(&first->list);
184 copy_siginfo(info, &first->info);
185- __sigqueue_free(first);
186+ sigqueue_free_current(first);
187 } else {
188 /*
189 * Ok, it wasn't in the queue. This must be
190@@ -560,6 +618,8 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
191 {
192 int signr;
193
194+ WARN_ON_ONCE(tsk != current);
195+
196 /* We only dequeue private signals from ourselves, we don't let
197 * signalfd steal them
198 */
199@@ -1485,7 +1545,8 @@ EXPORT_SYMBOL(kill_pid);
200 */
201 struct sigqueue *sigqueue_alloc(void)
202 {
203- struct sigqueue *q = __sigqueue_alloc(-1, current, GFP_KERNEL, 0);
204+ /* Preallocated sigqueue objects always from the slabcache ! */
205+ struct sigqueue *q = __sigqueue_do_alloc(-1, current, GFP_KERNEL, 0, 1);
206
207 if (q)
208 q->flags |= SIGQUEUE_PREALLOC;
209--
Arvind M10268e72017-12-04 22:18:06 -08002101.9.1
Allen Martin685e0f82016-07-26 19:34:29 -0700211