diff options
-rw-r--r-- | fs/Makefile | 1 | ||||
-rw-r--r-- | fs/exec.c | 11 | ||||
-rw-r--r-- | fs/signalfd.c | 349 | ||||
-rw-r--r-- | include/linux/Kbuild | 1 | ||||
-rw-r--r-- | include/linux/init_task.h | 1 | ||||
-rw-r--r-- | include/linux/sched.h | 1 | ||||
-rw-r--r-- | include/linux/signal.h | 1 | ||||
-rw-r--r-- | include/linux/signalfd.h | 97 | ||||
-rw-r--r-- | include/linux/syscalls.h | 1 | ||||
-rw-r--r-- | init/Kconfig | 10 | ||||
-rw-r--r-- | kernel/exit.c | 9 | ||||
-rw-r--r-- | kernel/fork.c | 8 | ||||
-rw-r--r-- | kernel/signal.c | 22 | ||||
-rw-r--r-- | kernel/sys_ni.c | 3 |
14 files changed, 508 insertions, 7 deletions
diff --git a/fs/Makefile b/fs/Makefile index b5cd46a88cb0..cd8a57aeac04 100644 --- a/fs/Makefile +++ b/fs/Makefile | |||
@@ -23,6 +23,7 @@ obj-$(CONFIG_INOTIFY) += inotify.o | |||
23 | obj-$(CONFIG_INOTIFY_USER) += inotify_user.o | 23 | obj-$(CONFIG_INOTIFY_USER) += inotify_user.o |
24 | obj-$(CONFIG_EPOLL) += eventpoll.o | 24 | obj-$(CONFIG_EPOLL) += eventpoll.o |
25 | obj-$(CONFIG_ANON_INODES) += anon_inodes.o | 25 | obj-$(CONFIG_ANON_INODES) += anon_inodes.o |
26 | obj-$(CONFIG_SIGNALFD) += signalfd.o | ||
26 | obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o | 27 | obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o |
27 | 28 | ||
28 | nfsd-$(CONFIG_NFSD) := nfsctl.o | 29 | nfsd-$(CONFIG_NFSD) := nfsctl.o |
@@ -50,6 +50,7 @@ | |||
50 | #include <linux/tsacct_kern.h> | 50 | #include <linux/tsacct_kern.h> |
51 | #include <linux/cn_proc.h> | 51 | #include <linux/cn_proc.h> |
52 | #include <linux/audit.h> | 52 | #include <linux/audit.h> |
53 | #include <linux/signalfd.h> | ||
53 | 54 | ||
54 | #include <asm/uaccess.h> | 55 | #include <asm/uaccess.h> |
55 | #include <asm/mmu_context.h> | 56 | #include <asm/mmu_context.h> |
@@ -582,6 +583,13 @@ static int de_thread(struct task_struct *tsk) | |||
582 | int count; | 583 | int count; |
583 | 584 | ||
584 | /* | 585 | /* |
586 | * Tell all the sighand listeners that this sighand has | ||
587 | * been detached. The signalfd_detach() function grabs the | ||
588 | * sighand lock, if signal listeners are present on the sighand. | ||
589 | */ | ||
590 | signalfd_detach(tsk); | ||
591 | |||
592 | /* | ||
585 | * If we don't share sighandlers, then we aren't sharing anything | 593 | * If we don't share sighandlers, then we aren't sharing anything |
586 | * and we can just re-use it all. | 594 | * and we can just re-use it all. |
587 | */ | 595 | */ |
@@ -757,8 +765,7 @@ no_thread_group: | |||
757 | spin_unlock(&oldsighand->siglock); | 765 | spin_unlock(&oldsighand->siglock); |
758 | write_unlock_irq(&tasklist_lock); | 766 | write_unlock_irq(&tasklist_lock); |
759 | 767 | ||
760 | if (atomic_dec_and_test(&oldsighand->count)) | 768 | __cleanup_sighand(oldsighand); |
761 | kmem_cache_free(sighand_cachep, oldsighand); | ||
762 | } | 769 | } |
763 | 770 | ||
764 | BUG_ON(!thread_group_leader(tsk)); | 771 | BUG_ON(!thread_group_leader(tsk)); |
diff --git a/fs/signalfd.c b/fs/signalfd.c new file mode 100644 index 000000000000..7cfeab412b45 --- /dev/null +++ b/fs/signalfd.c | |||
@@ -0,0 +1,349 @@ | |||
1 | /* | ||
2 | * fs/signalfd.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Linus Torvalds | ||
5 | * | ||
6 | * Mon Mar 5, 2007: Davide Libenzi <davidel@xmailserver.org> | ||
7 | * Changed ->read() to return a siginfo strcture instead of signal number. | ||
8 | * Fixed locking in ->poll(). | ||
9 | * Added sighand-detach notification. | ||
10 | * Added fd re-use in sys_signalfd() syscall. | ||
11 | * Now using anonymous inode source. | ||
12 | * Thanks to Oleg Nesterov for useful code review and suggestions. | ||
13 | * More comments and suggestions from Arnd Bergmann. | ||
14 | */ | ||
15 | |||
16 | #include <linux/file.h> | ||
17 | #include <linux/poll.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/fs.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/signal.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/anon_inodes.h> | ||
25 | #include <linux/signalfd.h> | ||
26 | |||
27 | struct signalfd_ctx { | ||
28 | struct list_head lnk; | ||
29 | wait_queue_head_t wqh; | ||
30 | sigset_t sigmask; | ||
31 | struct task_struct *tsk; | ||
32 | }; | ||
33 | |||
34 | struct signalfd_lockctx { | ||
35 | struct task_struct *tsk; | ||
36 | unsigned long flags; | ||
37 | }; | ||
38 | |||
39 | /* | ||
40 | * Tries to acquire the sighand lock. We do not increment the sighand | ||
41 | * use count, and we do not even pin the task struct, so we need to | ||
42 | * do it inside an RCU read lock, and we must be prepared for the | ||
43 | * ctx->tsk going to NULL (in signalfd_deliver()), and for the sighand | ||
44 | * being detached. We return 0 if the sighand has been detached, or | ||
45 | * 1 if we were able to pin the sighand lock. | ||
46 | */ | ||
47 | static int signalfd_lock(struct signalfd_ctx *ctx, struct signalfd_lockctx *lk) | ||
48 | { | ||
49 | struct sighand_struct *sighand = NULL; | ||
50 | |||
51 | rcu_read_lock(); | ||
52 | lk->tsk = rcu_dereference(ctx->tsk); | ||
53 | if (likely(lk->tsk != NULL)) | ||
54 | sighand = lock_task_sighand(lk->tsk, &lk->flags); | ||
55 | rcu_read_unlock(); | ||
56 | |||
57 | if (sighand && !ctx->tsk) { | ||
58 | unlock_task_sighand(lk->tsk, &lk->flags); | ||
59 | sighand = NULL; | ||
60 | } | ||
61 | |||
62 | return sighand != NULL; | ||
63 | } | ||
64 | |||
65 | static void signalfd_unlock(struct signalfd_lockctx *lk) | ||
66 | { | ||
67 | unlock_task_sighand(lk->tsk, &lk->flags); | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * This must be called with the sighand lock held. | ||
72 | */ | ||
73 | void signalfd_deliver(struct task_struct *tsk, int sig) | ||
74 | { | ||
75 | struct sighand_struct *sighand = tsk->sighand; | ||
76 | struct signalfd_ctx *ctx, *tmp; | ||
77 | |||
78 | BUG_ON(!sig); | ||
79 | list_for_each_entry_safe(ctx, tmp, &sighand->signalfd_list, lnk) { | ||
80 | /* | ||
81 | * We use a negative signal value as a way to broadcast that the | ||
82 | * sighand has been orphaned, so that we can notify all the | ||
83 | * listeners about this. Remember the ctx->sigmask is inverted, | ||
84 | * so if the user is interested in a signal, that corresponding | ||
85 | * bit will be zero. | ||
86 | */ | ||
87 | if (sig < 0) { | ||
88 | if (ctx->tsk == tsk) { | ||
89 | ctx->tsk = NULL; | ||
90 | list_del_init(&ctx->lnk); | ||
91 | wake_up(&ctx->wqh); | ||
92 | } | ||
93 | } else { | ||
94 | if (!sigismember(&ctx->sigmask, sig)) | ||
95 | wake_up(&ctx->wqh); | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | static void signalfd_cleanup(struct signalfd_ctx *ctx) | ||
101 | { | ||
102 | struct signalfd_lockctx lk; | ||
103 | |||
104 | /* | ||
105 | * This is tricky. If the sighand is gone, we do not need to remove | ||
106 | * context from the list, the list itself won't be there anymore. | ||
107 | */ | ||
108 | if (signalfd_lock(ctx, &lk)) { | ||
109 | list_del(&ctx->lnk); | ||
110 | signalfd_unlock(&lk); | ||
111 | } | ||
112 | kfree(ctx); | ||
113 | } | ||
114 | |||
115 | static int signalfd_release(struct inode *inode, struct file *file) | ||
116 | { | ||
117 | signalfd_cleanup(file->private_data); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static unsigned int signalfd_poll(struct file *file, poll_table *wait) | ||
122 | { | ||
123 | struct signalfd_ctx *ctx = file->private_data; | ||
124 | unsigned int events = 0; | ||
125 | struct signalfd_lockctx lk; | ||
126 | |||
127 | poll_wait(file, &ctx->wqh, wait); | ||
128 | |||
129 | /* | ||
130 | * Let the caller get a POLLIN in this case, ala socket recv() when | ||
131 | * the peer disconnects. | ||
132 | */ | ||
133 | if (signalfd_lock(ctx, &lk)) { | ||
134 | if (next_signal(&lk.tsk->pending, &ctx->sigmask) > 0 || | ||
135 | next_signal(&lk.tsk->signal->shared_pending, | ||
136 | &ctx->sigmask) > 0) | ||
137 | events |= POLLIN; | ||
138 | signalfd_unlock(&lk); | ||
139 | } else | ||
140 | events |= POLLIN; | ||
141 | |||
142 | return events; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Copied from copy_siginfo_to_user() in kernel/signal.c | ||
147 | */ | ||
148 | static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, | ||
149 | siginfo_t const *kinfo) | ||
150 | { | ||
151 | long err; | ||
152 | |||
153 | BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128); | ||
154 | |||
155 | /* | ||
156 | * Unused memebers should be zero ... | ||
157 | */ | ||
158 | err = __clear_user(uinfo, sizeof(*uinfo)); | ||
159 | |||
160 | /* | ||
161 | * If you change siginfo_t structure, please be sure | ||
162 | * this code is fixed accordingly. | ||
163 | */ | ||
164 | err |= __put_user(kinfo->si_signo, &uinfo->signo); | ||
165 | err |= __put_user(kinfo->si_errno, &uinfo->err); | ||
166 | err |= __put_user((short)kinfo->si_code, &uinfo->code); | ||
167 | switch (kinfo->si_code & __SI_MASK) { | ||
168 | case __SI_KILL: | ||
169 | err |= __put_user(kinfo->si_pid, &uinfo->pid); | ||
170 | err |= __put_user(kinfo->si_uid, &uinfo->uid); | ||
171 | break; | ||
172 | case __SI_TIMER: | ||
173 | err |= __put_user(kinfo->si_tid, &uinfo->tid); | ||
174 | err |= __put_user(kinfo->si_overrun, &uinfo->overrun); | ||
175 | err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr); | ||
176 | break; | ||
177 | case __SI_POLL: | ||
178 | err |= __put_user(kinfo->si_band, &uinfo->band); | ||
179 | err |= __put_user(kinfo->si_fd, &uinfo->fd); | ||
180 | break; | ||
181 | case __SI_FAULT: | ||
182 | err |= __put_user((long)kinfo->si_addr, &uinfo->addr); | ||
183 | #ifdef __ARCH_SI_TRAPNO | ||
184 | err |= __put_user(kinfo->si_trapno, &uinfo->trapno); | ||
185 | #endif | ||
186 | break; | ||
187 | case __SI_CHLD: | ||
188 | err |= __put_user(kinfo->si_pid, &uinfo->pid); | ||
189 | err |= __put_user(kinfo->si_uid, &uinfo->uid); | ||
190 | err |= __put_user(kinfo->si_status, &uinfo->status); | ||
191 | err |= __put_user(kinfo->si_utime, &uinfo->utime); | ||
192 | err |= __put_user(kinfo->si_stime, &uinfo->stime); | ||
193 | break; | ||
194 | case __SI_RT: /* This is not generated by the kernel as of now. */ | ||
195 | case __SI_MESGQ: /* But this is */ | ||
196 | err |= __put_user(kinfo->si_pid, &uinfo->pid); | ||
197 | err |= __put_user(kinfo->si_uid, &uinfo->uid); | ||
198 | err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr); | ||
199 | break; | ||
200 | default: /* this is just in case for now ... */ | ||
201 | err |= __put_user(kinfo->si_pid, &uinfo->pid); | ||
202 | err |= __put_user(kinfo->si_uid, &uinfo->uid); | ||
203 | break; | ||
204 | } | ||
205 | |||
206 | return err ? -EFAULT: sizeof(*uinfo); | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * Returns either the size of a "struct signalfd_siginfo", or zero if the | ||
211 | * sighand we are attached to, has been orphaned. The "count" parameter | ||
212 | * must be at least the size of a "struct signalfd_siginfo". | ||
213 | */ | ||
214 | static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count, | ||
215 | loff_t *ppos) | ||
216 | { | ||
217 | struct signalfd_ctx *ctx = file->private_data; | ||
218 | ssize_t res = 0; | ||
219 | int locked, signo; | ||
220 | siginfo_t info; | ||
221 | struct signalfd_lockctx lk; | ||
222 | DECLARE_WAITQUEUE(wait, current); | ||
223 | |||
224 | if (count < sizeof(struct signalfd_siginfo)) | ||
225 | return -EINVAL; | ||
226 | locked = signalfd_lock(ctx, &lk); | ||
227 | if (!locked) | ||
228 | return 0; | ||
229 | res = -EAGAIN; | ||
230 | signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info); | ||
231 | if (signo == 0 && !(file->f_flags & O_NONBLOCK)) { | ||
232 | add_wait_queue(&ctx->wqh, &wait); | ||
233 | for (;;) { | ||
234 | set_current_state(TASK_INTERRUPTIBLE); | ||
235 | signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info); | ||
236 | if (signo != 0) | ||
237 | break; | ||
238 | if (signal_pending(current)) { | ||
239 | res = -ERESTARTSYS; | ||
240 | break; | ||
241 | } | ||
242 | signalfd_unlock(&lk); | ||
243 | schedule(); | ||
244 | locked = signalfd_lock(ctx, &lk); | ||
245 | if (unlikely(!locked)) { | ||
246 | /* | ||
247 | * Let the caller read zero byte, ala socket | ||
248 | * recv() when the peer disconnect. This test | ||
249 | * must be done before doing a dequeue_signal(), | ||
250 | * because if the sighand has been orphaned, | ||
251 | * the dequeue_signal() call is going to crash. | ||
252 | */ | ||
253 | res = 0; | ||
254 | break; | ||
255 | } | ||
256 | } | ||
257 | remove_wait_queue(&ctx->wqh, &wait); | ||
258 | __set_current_state(TASK_RUNNING); | ||
259 | } | ||
260 | if (likely(locked)) | ||
261 | signalfd_unlock(&lk); | ||
262 | if (likely(signo)) | ||
263 | res = signalfd_copyinfo((struct signalfd_siginfo __user *) buf, | ||
264 | &info); | ||
265 | |||
266 | return res; | ||
267 | } | ||
268 | |||
269 | static const struct file_operations signalfd_fops = { | ||
270 | .release = signalfd_release, | ||
271 | .poll = signalfd_poll, | ||
272 | .read = signalfd_read, | ||
273 | }; | ||
274 | |||
275 | /* | ||
276 | * Create a file descriptor that is associated with our signal | ||
277 | * state. We can pass it around to others if we want to, but | ||
278 | * it will always be _our_ signal state. | ||
279 | */ | ||
280 | asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask) | ||
281 | { | ||
282 | int error; | ||
283 | sigset_t sigmask; | ||
284 | struct signalfd_ctx *ctx; | ||
285 | struct sighand_struct *sighand; | ||
286 | struct file *file; | ||
287 | struct inode *inode; | ||
288 | struct signalfd_lockctx lk; | ||
289 | |||
290 | if (sizemask != sizeof(sigset_t) || | ||
291 | copy_from_user(&sigmask, user_mask, sizeof(sigmask))) | ||
292 | return error = -EINVAL; | ||
293 | sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); | ||
294 | signotset(&sigmask); | ||
295 | |||
296 | if (ufd == -1) { | ||
297 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | ||
298 | if (!ctx) | ||
299 | return -ENOMEM; | ||
300 | |||
301 | init_waitqueue_head(&ctx->wqh); | ||
302 | ctx->sigmask = sigmask; | ||
303 | ctx->tsk = current; | ||
304 | |||
305 | sighand = current->sighand; | ||
306 | /* | ||
307 | * Add this fd to the list of signal listeners. | ||
308 | */ | ||
309 | spin_lock_irq(&sighand->siglock); | ||
310 | list_add_tail(&ctx->lnk, &sighand->signalfd_list); | ||
311 | spin_unlock_irq(&sighand->siglock); | ||
312 | |||
313 | /* | ||
314 | * When we call this, the initialization must be complete, since | ||
315 | * anon_inode_getfd() will install the fd. | ||
316 | */ | ||
317 | error = anon_inode_getfd(&ufd, &inode, &file, "[signalfd]", | ||
318 | &signalfd_fops, ctx); | ||
319 | if (error) | ||
320 | goto err_fdalloc; | ||
321 | } else { | ||
322 | file = fget(ufd); | ||
323 | if (!file) | ||
324 | return -EBADF; | ||
325 | ctx = file->private_data; | ||
326 | if (file->f_op != &signalfd_fops) { | ||
327 | fput(file); | ||
328 | return -EINVAL; | ||
329 | } | ||
330 | /* | ||
331 | * We need to be prepared of the fact that the sighand this fd | ||
332 | * is attached to, has been detched. In that case signalfd_lock() | ||
333 | * will return 0, and we'll just skip setting the new mask. | ||
334 | */ | ||
335 | if (signalfd_lock(ctx, &lk)) { | ||
336 | ctx->sigmask = sigmask; | ||
337 | signalfd_unlock(&lk); | ||
338 | } | ||
339 | wake_up(&ctx->wqh); | ||
340 | fput(file); | ||
341 | } | ||
342 | |||
343 | return ufd; | ||
344 | |||
345 | err_fdalloc: | ||
346 | signalfd_cleanup(ctx); | ||
347 | return error; | ||
348 | } | ||
349 | |||
diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 645b3b528150..bcd01f269f60 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild | |||
@@ -190,6 +190,7 @@ unifdef-y += errno.h | |||
190 | unifdef-y += errqueue.h | 190 | unifdef-y += errqueue.h |
191 | unifdef-y += ethtool.h | 191 | unifdef-y += ethtool.h |
192 | unifdef-y += eventpoll.h | 192 | unifdef-y += eventpoll.h |
193 | unifdef-y += signalfd.h | ||
193 | unifdef-y += ext2_fs.h | 194 | unifdef-y += ext2_fs.h |
194 | unifdef-y += ext3_fs.h | 195 | unifdef-y += ext3_fs.h |
195 | unifdef-y += fb.h | 196 | unifdef-y += fb.h |
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 66e2f0a70814..276ccaa2670c 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
@@ -84,6 +84,7 @@ extern struct nsproxy init_nsproxy; | |||
84 | .count = ATOMIC_INIT(1), \ | 84 | .count = ATOMIC_INIT(1), \ |
85 | .action = { { { .sa_handler = NULL, } }, }, \ | 85 | .action = { { { .sa_handler = NULL, } }, }, \ |
86 | .siglock = __SPIN_LOCK_UNLOCKED(sighand.siglock), \ | 86 | .siglock = __SPIN_LOCK_UNLOCKED(sighand.siglock), \ |
87 | .signalfd_list = LIST_HEAD_INIT(sighand.signalfd_list), \ | ||
87 | } | 88 | } |
88 | 89 | ||
89 | extern struct group_info init_groups; | 90 | extern struct group_info init_groups; |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 75f44379b7e9..97c0c7da58ef 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -391,6 +391,7 @@ struct sighand_struct { | |||
391 | atomic_t count; | 391 | atomic_t count; |
392 | struct k_sigaction action[_NSIG]; | 392 | struct k_sigaction action[_NSIG]; |
393 | spinlock_t siglock; | 393 | spinlock_t siglock; |
394 | struct list_head signalfd_list; | ||
394 | }; | 395 | }; |
395 | 396 | ||
396 | struct pacct_struct { | 397 | struct pacct_struct { |
diff --git a/include/linux/signal.h b/include/linux/signal.h index 3fa0fab4a04b..9a5eac508e5e 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h | |||
@@ -233,6 +233,7 @@ static inline int valid_signal(unsigned long sig) | |||
233 | return sig <= _NSIG ? 1 : 0; | 233 | return sig <= _NSIG ? 1 : 0; |
234 | } | 234 | } |
235 | 235 | ||
236 | extern int next_signal(struct sigpending *pending, sigset_t *mask); | ||
236 | extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p); | 237 | extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p); |
237 | extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *); | 238 | extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *); |
238 | extern long do_sigpending(void __user *, unsigned long); | 239 | extern long do_sigpending(void __user *, unsigned long); |
diff --git a/include/linux/signalfd.h b/include/linux/signalfd.h new file mode 100644 index 000000000000..510429495690 --- /dev/null +++ b/include/linux/signalfd.h | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * include/linux/signalfd.h | ||
3 | * | ||
4 | * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org> | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #ifndef _LINUX_SIGNALFD_H | ||
9 | #define _LINUX_SIGNALFD_H | ||
10 | |||
11 | |||
12 | struct signalfd_siginfo { | ||
13 | __u32 signo; | ||
14 | __s32 err; | ||
15 | __s32 code; | ||
16 | __u32 pid; | ||
17 | __u32 uid; | ||
18 | __s32 fd; | ||
19 | __u32 tid; | ||
20 | __u32 band; | ||
21 | __u32 overrun; | ||
22 | __u32 trapno; | ||
23 | __s32 status; | ||
24 | __s32 svint; | ||
25 | __u64 svptr; | ||
26 | __u64 utime; | ||
27 | __u64 stime; | ||
28 | __u64 addr; | ||
29 | |||
30 | /* | ||
31 | * Pad strcture to 128 bytes. Remember to update the | ||
32 | * pad size when you add new memebers. We use a fixed | ||
33 | * size structure to avoid compatibility problems with | ||
34 | * future versions, and we leave extra space for additional | ||
35 | * members. We use fixed size members because this strcture | ||
36 | * comes out of a read(2) and we really don't want to have | ||
37 | * a compat on read(2). | ||
38 | */ | ||
39 | __u8 __pad[48]; | ||
40 | }; | ||
41 | |||
42 | |||
43 | #ifdef __KERNEL__ | ||
44 | |||
45 | #ifdef CONFIG_SIGNALFD | ||
46 | |||
47 | /* | ||
48 | * Deliver the signal to listening signalfd. This must be called | ||
49 | * with the sighand lock held. Same are the following that end up | ||
50 | * calling signalfd_deliver(). | ||
51 | */ | ||
52 | void signalfd_deliver(struct task_struct *tsk, int sig); | ||
53 | |||
54 | /* | ||
55 | * No need to fall inside signalfd_deliver() if no signal listeners | ||
56 | * are available. | ||
57 | */ | ||
58 | static inline void signalfd_notify(struct task_struct *tsk, int sig) | ||
59 | { | ||
60 | if (unlikely(!list_empty(&tsk->sighand->signalfd_list))) | ||
61 | signalfd_deliver(tsk, sig); | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * The signal -1 is used to notify the signalfd that the sighand | ||
66 | * is on its way to be detached. | ||
67 | */ | ||
68 | static inline void signalfd_detach_locked(struct task_struct *tsk) | ||
69 | { | ||
70 | if (unlikely(!list_empty(&tsk->sighand->signalfd_list))) | ||
71 | signalfd_deliver(tsk, -1); | ||
72 | } | ||
73 | |||
74 | static inline void signalfd_detach(struct task_struct *tsk) | ||
75 | { | ||
76 | struct sighand_struct *sighand = tsk->sighand; | ||
77 | |||
78 | if (unlikely(!list_empty(&sighand->signalfd_list))) { | ||
79 | spin_lock_irq(&sighand->siglock); | ||
80 | signalfd_deliver(tsk, -1); | ||
81 | spin_unlock_irq(&sighand->siglock); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | #else /* CONFIG_SIGNALFD */ | ||
86 | |||
87 | #define signalfd_deliver(t, s) do { } while (0) | ||
88 | #define signalfd_notify(t, s) do { } while (0) | ||
89 | #define signalfd_detach_locked(t) do { } while (0) | ||
90 | #define signalfd_detach(t) do { } while (0) | ||
91 | |||
92 | #endif /* CONFIG_SIGNALFD */ | ||
93 | |||
94 | #endif /* __KERNEL__ */ | ||
95 | |||
96 | #endif /* _LINUX_SIGNALFD_H */ | ||
97 | |||
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 3139f4412297..e049f14a75b7 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -604,6 +604,7 @@ asmlinkage long sys_get_robust_list(int pid, | |||
604 | asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, | 604 | asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, |
605 | size_t len); | 605 | size_t len); |
606 | asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); | 606 | asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); |
607 | asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask); | ||
607 | 608 | ||
608 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]); | 609 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]); |
609 | 610 | ||
diff --git a/init/Kconfig b/init/Kconfig index a80bd8326bc6..db707204b751 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -492,6 +492,16 @@ config EPOLL | |||
492 | Disabling this option will cause the kernel to be built without | 492 | Disabling this option will cause the kernel to be built without |
493 | support for epoll family of system calls. | 493 | support for epoll family of system calls. |
494 | 494 | ||
495 | config SIGNALFD | ||
496 | bool "Enable signalfd() system call" if EMBEDDED | ||
497 | depends on ANON_INODES | ||
498 | default y | ||
499 | help | ||
500 | Enable the signalfd() system call that allows to receive signals | ||
501 | on a file descriptor. | ||
502 | |||
503 | If unsure, say Y. | ||
504 | |||
495 | config SHMEM | 505 | config SHMEM |
496 | bool "Use full shmem filesystem" if EMBEDDED | 506 | bool "Use full shmem filesystem" if EMBEDDED |
497 | default y | 507 | default y |
diff --git a/kernel/exit.c b/kernel/exit.c index e93691e9b325..c6d14b8008dd 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/pid_namespace.h> | 24 | #include <linux/pid_namespace.h> |
25 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
26 | #include <linux/profile.h> | 26 | #include <linux/profile.h> |
27 | #include <linux/signalfd.h> | ||
27 | #include <linux/mount.h> | 28 | #include <linux/mount.h> |
28 | #include <linux/proc_fs.h> | 29 | #include <linux/proc_fs.h> |
29 | #include <linux/kthread.h> | 30 | #include <linux/kthread.h> |
@@ -83,6 +84,14 @@ static void __exit_signal(struct task_struct *tsk) | |||
83 | sighand = rcu_dereference(tsk->sighand); | 84 | sighand = rcu_dereference(tsk->sighand); |
84 | spin_lock(&sighand->siglock); | 85 | spin_lock(&sighand->siglock); |
85 | 86 | ||
87 | /* | ||
88 | * Notify that this sighand has been detached. This must | ||
89 | * be called with the tsk->sighand lock held. Also, this | ||
90 | * access tsk->sighand internally, so it must be called | ||
91 | * before tsk->sighand is reset. | ||
92 | */ | ||
93 | signalfd_detach_locked(tsk); | ||
94 | |||
86 | posix_cpu_timers_exit(tsk); | 95 | posix_cpu_timers_exit(tsk); |
87 | if (atomic_dec_and_test(&sig->count)) | 96 | if (atomic_dec_and_test(&sig->count)) |
88 | posix_cpu_timers_exit_group(tsk); | 97 | posix_cpu_timers_exit_group(tsk); |
diff --git a/kernel/fork.c b/kernel/fork.c index 083bf8953ce8..49530e40ea8b 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1422,12 +1422,15 @@ long do_fork(unsigned long clone_flags, | |||
1422 | #define ARCH_MIN_MMSTRUCT_ALIGN 0 | 1422 | #define ARCH_MIN_MMSTRUCT_ALIGN 0 |
1423 | #endif | 1423 | #endif |
1424 | 1424 | ||
1425 | static void sighand_ctor(void *data, struct kmem_cache *cachep, unsigned long flags) | 1425 | static void sighand_ctor(void *data, struct kmem_cache *cachep, |
1426 | unsigned long flags) | ||
1426 | { | 1427 | { |
1427 | struct sighand_struct *sighand = data; | 1428 | struct sighand_struct *sighand = data; |
1428 | 1429 | ||
1429 | if (flags & SLAB_CTOR_CONSTRUCTOR) | 1430 | if (flags & SLAB_CTOR_CONSTRUCTOR) { |
1430 | spin_lock_init(&sighand->siglock); | 1431 | spin_lock_init(&sighand->siglock); |
1432 | INIT_LIST_HEAD(&sighand->signalfd_list); | ||
1433 | } | ||
1431 | } | 1434 | } |
1432 | 1435 | ||
1433 | void __init proc_caches_init(void) | 1436 | void __init proc_caches_init(void) |
@@ -1453,7 +1456,6 @@ void __init proc_caches_init(void) | |||
1453 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); | 1456 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
1454 | } | 1457 | } |
1455 | 1458 | ||
1456 | |||
1457 | /* | 1459 | /* |
1458 | * Check constraints on flags passed to the unshare system call and | 1460 | * Check constraints on flags passed to the unshare system call and |
1459 | * force unsharing of additional process context as appropriate. | 1461 | * force unsharing of additional process context as appropriate. |
diff --git a/kernel/signal.c b/kernel/signal.c index 2ac3a668d9dd..34b7d6abce8f 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/syscalls.h> | 21 | #include <linux/syscalls.h> |
22 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
23 | #include <linux/signal.h> | 23 | #include <linux/signal.h> |
24 | #include <linux/signalfd.h> | ||
24 | #include <linux/capability.h> | 25 | #include <linux/capability.h> |
25 | #include <linux/freezer.h> | 26 | #include <linux/freezer.h> |
26 | #include <linux/pid_namespace.h> | 27 | #include <linux/pid_namespace.h> |
@@ -113,8 +114,7 @@ void recalc_sigpending(void) | |||
113 | 114 | ||
114 | /* Given the mask, find the first available signal that should be serviced. */ | 115 | /* Given the mask, find the first available signal that should be serviced. */ |
115 | 116 | ||
116 | static int | 117 | int next_signal(struct sigpending *pending, sigset_t *mask) |
117 | next_signal(struct sigpending *pending, sigset_t *mask) | ||
118 | { | 118 | { |
119 | unsigned long i, *s, *m, x; | 119 | unsigned long i, *s, *m, x; |
120 | int sig = 0; | 120 | int sig = 0; |
@@ -630,6 +630,12 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t, | |||
630 | int ret = 0; | 630 | int ret = 0; |
631 | 631 | ||
632 | /* | 632 | /* |
633 | * Deliver the signal to listening signalfds. This must be called | ||
634 | * with the sighand lock held. | ||
635 | */ | ||
636 | signalfd_notify(t, sig); | ||
637 | |||
638 | /* | ||
633 | * fast-pathed signals for kernel-internal things like SIGSTOP | 639 | * fast-pathed signals for kernel-internal things like SIGSTOP |
634 | * or SIGKILL. | 640 | * or SIGKILL. |
635 | */ | 641 | */ |
@@ -1280,6 +1286,11 @@ int send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) | |||
1280 | ret = 1; | 1286 | ret = 1; |
1281 | goto out; | 1287 | goto out; |
1282 | } | 1288 | } |
1289 | /* | ||
1290 | * Deliver the signal to listening signalfds. This must be called | ||
1291 | * with the sighand lock held. | ||
1292 | */ | ||
1293 | signalfd_notify(p, sig); | ||
1283 | 1294 | ||
1284 | list_add_tail(&q->list, &p->pending.list); | 1295 | list_add_tail(&q->list, &p->pending.list); |
1285 | sigaddset(&p->pending.signal, sig); | 1296 | sigaddset(&p->pending.signal, sig); |
@@ -1323,6 +1334,11 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) | |||
1323 | q->info.si_overrun++; | 1334 | q->info.si_overrun++; |
1324 | goto out; | 1335 | goto out; |
1325 | } | 1336 | } |
1337 | /* | ||
1338 | * Deliver the signal to listening signalfds. This must be called | ||
1339 | * with the sighand lock held. | ||
1340 | */ | ||
1341 | signalfd_notify(p, sig); | ||
1326 | 1342 | ||
1327 | /* | 1343 | /* |
1328 | * Put this signal on the shared-pending queue. | 1344 | * Put this signal on the shared-pending queue. |
@@ -1983,6 +1999,8 @@ int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from) | |||
1983 | /* | 1999 | /* |
1984 | * If you change siginfo_t structure, please be sure | 2000 | * If you change siginfo_t structure, please be sure |
1985 | * this code is fixed accordingly. | 2001 | * this code is fixed accordingly. |
2002 | * Please remember to update the signalfd_copyinfo() function | ||
2003 | * inside fs/signalfd.c too, in case siginfo_t changes. | ||
1986 | * It should never copy any pad contained in the structure | 2004 | * It should never copy any pad contained in the structure |
1987 | * to avoid security leaks, but must copy the generic | 2005 | * to avoid security leaks, but must copy the generic |
1988 | * 3 ints plus the relevant union member. | 2006 | * 3 ints plus the relevant union member. |
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index d7306d0f3dfc..807e9bb8fcdb 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c | |||
@@ -141,3 +141,6 @@ cond_syscall(compat_sys_migrate_pages); | |||
141 | cond_syscall(sys_bdflush); | 141 | cond_syscall(sys_bdflush); |
142 | cond_syscall(sys_ioprio_set); | 142 | cond_syscall(sys_ioprio_set); |
143 | cond_syscall(sys_ioprio_get); | 143 | cond_syscall(sys_ioprio_get); |
144 | |||
145 | /* New file descriptors */ | ||
146 | cond_syscall(sys_signalfd); | ||