diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2008-12-01 17:18:13 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-12-12 11:00:07 -0500 |
commit | 27af4245b6ce99e08c6a7c38825383bf51119cc9 (patch) | |
tree | 07ab6b1da26b4d170ccaa700b2207ec1b1aff0db | |
parent | 6c34bc2976b30dc8b56392c020e25bae1f363cab (diff) |
posix-timers: use "struct pid*" instead of "struct task_struct*"
Impact: restructure, clean up code
k_itimer holds the ref to the ->it_process until sys_timer_delete(). This
allows to pin up to RLIMIT_SIGPENDING dead task_struct's. Change the code
to use "struct pid *" instead.
The patch doesn't kill ->it_process, it places ->it_pid into the union.
->it_process is still used by do_cpu_nanosleep() as before. It would be
trivial to change the nanosleep code as well, but since it uses it_process
in a special way I think it is better to keep this field for grep.
The patch bloats the kernel by 104 bytes and it also adds the new pointer,
->it_signal, to k_itimer. It is used by lock_timer() to verify that the
found timer was not created by another process. It is not clear why do we
use the global database (and thus the global idr_lock) for posix timers.
We still need the signal_struct->posix_timers which contains all useable
timers, perhaps it is better to use some form of per-process array
instead.
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | include/linux/posix-timers.h | 6 | ||||
-rw-r--r-- | kernel/posix-timers.c | 43 |
2 files changed, 28 insertions, 21 deletions
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index a7c72135554..4f71bf4e628 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h | |||
@@ -45,7 +45,11 @@ struct k_itimer { | |||
45 | int it_requeue_pending; /* waiting to requeue this timer */ | 45 | int it_requeue_pending; /* waiting to requeue this timer */ |
46 | #define REQUEUE_PENDING 1 | 46 | #define REQUEUE_PENDING 1 |
47 | int it_sigev_notify; /* notify word of sigevent struct */ | 47 | int it_sigev_notify; /* notify word of sigevent struct */ |
48 | struct task_struct *it_process; /* process to send signal to */ | 48 | struct signal_struct *it_signal; |
49 | union { | ||
50 | struct pid *it_pid; /* pid of process to send signal to */ | ||
51 | struct task_struct *it_process; /* for clock_nanosleep */ | ||
52 | }; | ||
49 | struct sigqueue *sigq; /* signal queue entry. */ | 53 | struct sigqueue *sigq; /* signal queue entry. */ |
50 | union { | 54 | union { |
51 | struct { | 55 | struct { |
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index 5e79c662294..42a39afd694 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c | |||
@@ -116,7 +116,7 @@ static DEFINE_SPINLOCK(idr_lock); | |||
116 | * must supply functions here, even if the function just returns | 116 | * must supply functions here, even if the function just returns |
117 | * ENOSYS. The standard POSIX timer management code assumes the | 117 | * ENOSYS. The standard POSIX timer management code assumes the |
118 | * following: 1.) The k_itimer struct (sched.h) is used for the | 118 | * following: 1.) The k_itimer struct (sched.h) is used for the |
119 | * timer. 2.) The list, it_lock, it_clock, it_id and it_process | 119 | * timer. 2.) The list, it_lock, it_clock, it_id and it_pid |
120 | * fields are not modified by timer code. | 120 | * fields are not modified by timer code. |
121 | * | 121 | * |
122 | * At this time all functions EXCEPT clock_nanosleep can be | 122 | * At this time all functions EXCEPT clock_nanosleep can be |
@@ -313,7 +313,8 @@ void do_schedule_next_timer(struct siginfo *info) | |||
313 | 313 | ||
314 | int posix_timer_event(struct k_itimer *timr, int si_private) | 314 | int posix_timer_event(struct k_itimer *timr, int si_private) |
315 | { | 315 | { |
316 | int shared, ret; | 316 | struct task_struct *task; |
317 | int shared, ret = -1; | ||
317 | /* | 318 | /* |
318 | * FIXME: if ->sigq is queued we can race with | 319 | * FIXME: if ->sigq is queued we can race with |
319 | * dequeue_signal()->do_schedule_next_timer(). | 320 | * dequeue_signal()->do_schedule_next_timer(). |
@@ -327,8 +328,13 @@ int posix_timer_event(struct k_itimer *timr, int si_private) | |||
327 | */ | 328 | */ |
328 | timr->sigq->info.si_sys_private = si_private; | 329 | timr->sigq->info.si_sys_private = si_private; |
329 | 330 | ||
330 | shared = !(timr->it_sigev_notify & SIGEV_THREAD_ID); | 331 | rcu_read_lock(); |
331 | ret = send_sigqueue(timr->sigq, timr->it_process, shared); | 332 | task = pid_task(timr->it_pid, PIDTYPE_PID); |
333 | if (task) { | ||
334 | shared = !(timr->it_sigev_notify & SIGEV_THREAD_ID); | ||
335 | ret = send_sigqueue(timr->sigq, task, shared); | ||
336 | } | ||
337 | rcu_read_unlock(); | ||
332 | /* If we failed to send the signal the timer stops. */ | 338 | /* If we failed to send the signal the timer stops. */ |
333 | return ret > 0; | 339 | return ret > 0; |
334 | } | 340 | } |
@@ -405,7 +411,7 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer) | |||
405 | return ret; | 411 | return ret; |
406 | } | 412 | } |
407 | 413 | ||
408 | static struct task_struct * good_sigevent(sigevent_t * event) | 414 | static struct pid *good_sigevent(sigevent_t * event) |
409 | { | 415 | { |
410 | struct task_struct *rtn = current->group_leader; | 416 | struct task_struct *rtn = current->group_leader; |
411 | 417 | ||
@@ -419,7 +425,7 @@ static struct task_struct * good_sigevent(sigevent_t * event) | |||
419 | ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX))) | 425 | ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX))) |
420 | return NULL; | 426 | return NULL; |
421 | 427 | ||
422 | return rtn; | 428 | return task_pid(rtn); |
423 | } | 429 | } |
424 | 430 | ||
425 | void register_posix_clock(const clockid_t clock_id, struct k_clock *new_clock) | 431 | void register_posix_clock(const clockid_t clock_id, struct k_clock *new_clock) |
@@ -471,7 +477,7 @@ sys_timer_create(const clockid_t which_clock, | |||
471 | { | 477 | { |
472 | struct k_itimer *new_timer; | 478 | struct k_itimer *new_timer; |
473 | int error, new_timer_id; | 479 | int error, new_timer_id; |
474 | struct task_struct *process; | 480 | struct pid *it_pid; |
475 | sigevent_t event; | 481 | sigevent_t event; |
476 | int it_id_set = IT_ID_NOT_SET; | 482 | int it_id_set = IT_ID_NOT_SET; |
477 | 483 | ||
@@ -525,11 +531,9 @@ sys_timer_create(const clockid_t which_clock, | |||
525 | goto out; | 531 | goto out; |
526 | } | 532 | } |
527 | rcu_read_lock(); | 533 | rcu_read_lock(); |
528 | process = good_sigevent(&event); | 534 | it_pid = get_pid(good_sigevent(&event)); |
529 | if (process) | ||
530 | get_task_struct(process); | ||
531 | rcu_read_unlock(); | 535 | rcu_read_unlock(); |
532 | if (!process) { | 536 | if (!it_pid) { |
533 | error = -EINVAL; | 537 | error = -EINVAL; |
534 | goto out; | 538 | goto out; |
535 | } | 539 | } |
@@ -537,8 +541,7 @@ sys_timer_create(const clockid_t which_clock, | |||
537 | event.sigev_notify = SIGEV_SIGNAL; | 541 | event.sigev_notify = SIGEV_SIGNAL; |
538 | event.sigev_signo = SIGALRM; | 542 | event.sigev_signo = SIGALRM; |
539 | event.sigev_value.sival_int = new_timer->it_id; | 543 | event.sigev_value.sival_int = new_timer->it_id; |
540 | process = current->group_leader; | 544 | it_pid = get_pid(task_tgid(current)); |
541 | get_task_struct(process); | ||
542 | } | 545 | } |
543 | 546 | ||
544 | new_timer->it_sigev_notify = event.sigev_notify; | 547 | new_timer->it_sigev_notify = event.sigev_notify; |
@@ -548,7 +551,8 @@ sys_timer_create(const clockid_t which_clock, | |||
548 | new_timer->sigq->info.si_code = SI_TIMER; | 551 | new_timer->sigq->info.si_code = SI_TIMER; |
549 | 552 | ||
550 | spin_lock_irq(¤t->sighand->siglock); | 553 | spin_lock_irq(¤t->sighand->siglock); |
551 | new_timer->it_process = process; | 554 | new_timer->it_pid = it_pid; |
555 | new_timer->it_signal = current->signal; | ||
552 | list_add(&new_timer->list, ¤t->signal->posix_timers); | 556 | list_add(&new_timer->list, ¤t->signal->posix_timers); |
553 | spin_unlock_irq(¤t->sighand->siglock); | 557 | spin_unlock_irq(¤t->sighand->siglock); |
554 | 558 | ||
@@ -583,8 +587,7 @@ static struct k_itimer *lock_timer(timer_t timer_id, unsigned long *flags) | |||
583 | timr = idr_find(&posix_timers_id, (int)timer_id); | 587 | timr = idr_find(&posix_timers_id, (int)timer_id); |
584 | if (timr) { | 588 | if (timr) { |
585 | spin_lock(&timr->it_lock); | 589 | spin_lock(&timr->it_lock); |
586 | if (timr->it_process && | 590 | if (timr->it_pid && timr->it_signal == current->signal) { |
587 | same_thread_group(timr->it_process, current)) { | ||
588 | spin_unlock(&idr_lock); | 591 | spin_unlock(&idr_lock); |
589 | return timr; | 592 | return timr; |
590 | } | 593 | } |
@@ -831,8 +834,8 @@ retry_delete: | |||
831 | * This keeps any tasks waiting on the spin lock from thinking | 834 | * This keeps any tasks waiting on the spin lock from thinking |
832 | * they got something (see the lock code above). | 835 | * they got something (see the lock code above). |
833 | */ | 836 | */ |
834 | put_task_struct(timer->it_process); | 837 | put_pid(timer->it_pid); |
835 | timer->it_process = NULL; | 838 | timer->it_pid = NULL; |
836 | 839 | ||
837 | unlock_timer(timer, flags); | 840 | unlock_timer(timer, flags); |
838 | release_posix_timer(timer, IT_ID_SET); | 841 | release_posix_timer(timer, IT_ID_SET); |
@@ -858,8 +861,8 @@ retry_delete: | |||
858 | * This keeps any tasks waiting on the spin lock from thinking | 861 | * This keeps any tasks waiting on the spin lock from thinking |
859 | * they got something (see the lock code above). | 862 | * they got something (see the lock code above). |
860 | */ | 863 | */ |
861 | put_task_struct(timer->it_process); | 864 | put_pid(timer->it_pid); |
862 | timer->it_process = NULL; | 865 | timer->it_pid = NULL; |
863 | 866 | ||
864 | unlock_timer(timer, flags); | 867 | unlock_timer(timer, flags); |
865 | release_posix_timer(timer, IT_ID_SET); | 868 | release_posix_timer(timer, IT_ID_SET); |