diff options
author | Toyo Abe <toyoa@mvista.com> | 2006-09-29 05:00:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-29 12:18:15 -0400 |
commit | 1711ef3866b0360e102327389fe4b76c849bbe83 (patch) | |
tree | b74a2cb6167840563d450859a571d6685966b771 | |
parent | 9c4751fd0eab5b8ebbfafb28cbcc8e03b0da5933 (diff) |
[PATCH] posix-timers: Fix clock_nanosleep() doesn't return the remaining time in compatibility mode
The clock_nanosleep() function does not return the time remaining when the
sleep is interrupted by a signal.
This patch creates a new call out, compat_clock_nanosleep_restart(), which
handles returning the remaining time after a sleep is interrupted. This
patch revives clock_nanosleep_restart(). It is now accessed via the new
call out. The compat_clock_nanosleep_restart() is used for compatibility
access.
Since this is implemented in compatibility mode the normal path is
virtually unaffected - no real performance impact.
Signed-off-by: Toyo Abe <toyoa@mvista.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | include/linux/hrtimer.h | 1 | ||||
-rw-r--r-- | include/linux/posix-timers.h | 4 | ||||
-rw-r--r-- | kernel/compat.c | 33 | ||||
-rw-r--r-- | kernel/hrtimer.c | 20 | ||||
-rw-r--r-- | kernel/posix-cpu-timers.c | 17 | ||||
-rw-r--r-- | kernel/posix-timers.c | 21 |
6 files changed, 81 insertions, 15 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 4fc379de6c2f..fca93025ab51 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h | |||
@@ -138,6 +138,7 @@ extern long hrtimer_nanosleep(struct timespec *rqtp, | |||
138 | struct timespec __user *rmtp, | 138 | struct timespec __user *rmtp, |
139 | const enum hrtimer_mode mode, | 139 | const enum hrtimer_mode mode, |
140 | const clockid_t clockid); | 140 | const clockid_t clockid); |
141 | extern long hrtimer_nanosleep_restart(struct restart_block *restart_block); | ||
141 | 142 | ||
142 | extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, | 143 | extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, |
143 | struct task_struct *tsk); | 144 | struct task_struct *tsk); |
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 95572c434bc9..a7dd38f30ade 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h | |||
@@ -72,6 +72,7 @@ struct k_clock { | |||
72 | int (*timer_create) (struct k_itimer *timer); | 72 | int (*timer_create) (struct k_itimer *timer); |
73 | int (*nsleep) (const clockid_t which_clock, int flags, | 73 | int (*nsleep) (const clockid_t which_clock, int flags, |
74 | struct timespec *, struct timespec __user *); | 74 | struct timespec *, struct timespec __user *); |
75 | long (*nsleep_restart) (struct restart_block *restart_block); | ||
75 | int (*timer_set) (struct k_itimer * timr, int flags, | 76 | int (*timer_set) (struct k_itimer * timr, int flags, |
76 | struct itimerspec * new_setting, | 77 | struct itimerspec * new_setting, |
77 | struct itimerspec * old_setting); | 78 | struct itimerspec * old_setting); |
@@ -97,6 +98,7 @@ int posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *ts); | |||
97 | int posix_cpu_timer_create(struct k_itimer *timer); | 98 | int posix_cpu_timer_create(struct k_itimer *timer); |
98 | int posix_cpu_nsleep(const clockid_t which_clock, int flags, | 99 | int posix_cpu_nsleep(const clockid_t which_clock, int flags, |
99 | struct timespec *rqtp, struct timespec __user *rmtp); | 100 | struct timespec *rqtp, struct timespec __user *rmtp); |
101 | long posix_cpu_nsleep_restart(struct restart_block *restart_block); | ||
100 | int posix_cpu_timer_set(struct k_itimer *timer, int flags, | 102 | int posix_cpu_timer_set(struct k_itimer *timer, int flags, |
101 | struct itimerspec *new, struct itimerspec *old); | 103 | struct itimerspec *new, struct itimerspec *old); |
102 | int posix_cpu_timer_del(struct k_itimer *timer); | 104 | int posix_cpu_timer_del(struct k_itimer *timer); |
@@ -111,4 +113,6 @@ void posix_cpu_timers_exit_group(struct task_struct *task); | |||
111 | void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, | 113 | void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, |
112 | cputime_t *newval, cputime_t *oldval); | 114 | cputime_t *newval, cputime_t *oldval); |
113 | 115 | ||
116 | long clock_nanosleep_restart(struct restart_block *restart_block); | ||
117 | |||
114 | #endif | 118 | #endif |
diff --git a/kernel/compat.c b/kernel/compat.c index 126dee9530aa..75573e5d27b0 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/security.h> | 22 | #include <linux/security.h> |
23 | #include <linux/timex.h> | 23 | #include <linux/timex.h> |
24 | #include <linux/migrate.h> | 24 | #include <linux/migrate.h> |
25 | #include <linux/posix-timers.h> | ||
25 | 26 | ||
26 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
27 | 28 | ||
@@ -601,6 +602,30 @@ long compat_sys_clock_getres(clockid_t which_clock, | |||
601 | return err; | 602 | return err; |
602 | } | 603 | } |
603 | 604 | ||
605 | static long compat_clock_nanosleep_restart(struct restart_block *restart) | ||
606 | { | ||
607 | long err; | ||
608 | mm_segment_t oldfs; | ||
609 | struct timespec tu; | ||
610 | struct compat_timespec *rmtp = (struct compat_timespec *)(restart->arg1); | ||
611 | |||
612 | restart->arg1 = (unsigned long) &tu; | ||
613 | oldfs = get_fs(); | ||
614 | set_fs(KERNEL_DS); | ||
615 | err = clock_nanosleep_restart(restart); | ||
616 | set_fs(oldfs); | ||
617 | |||
618 | if ((err == -ERESTART_RESTARTBLOCK) && rmtp && | ||
619 | put_compat_timespec(&tu, rmtp)) | ||
620 | return -EFAULT; | ||
621 | |||
622 | if (err == -ERESTART_RESTARTBLOCK) { | ||
623 | restart->fn = compat_clock_nanosleep_restart; | ||
624 | restart->arg1 = (unsigned long) rmtp; | ||
625 | } | ||
626 | return err; | ||
627 | } | ||
628 | |||
604 | long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, | 629 | long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, |
605 | struct compat_timespec __user *rqtp, | 630 | struct compat_timespec __user *rqtp, |
606 | struct compat_timespec __user *rmtp) | 631 | struct compat_timespec __user *rmtp) |
@@ -608,6 +633,7 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, | |||
608 | long err; | 633 | long err; |
609 | mm_segment_t oldfs; | 634 | mm_segment_t oldfs; |
610 | struct timespec in, out; | 635 | struct timespec in, out; |
636 | struct restart_block *restart; | ||
611 | 637 | ||
612 | if (get_compat_timespec(&in, rqtp)) | 638 | if (get_compat_timespec(&in, rqtp)) |
613 | return -EFAULT; | 639 | return -EFAULT; |
@@ -618,9 +644,16 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, | |||
618 | (struct timespec __user *) &in, | 644 | (struct timespec __user *) &in, |
619 | (struct timespec __user *) &out); | 645 | (struct timespec __user *) &out); |
620 | set_fs(oldfs); | 646 | set_fs(oldfs); |
647 | |||
621 | if ((err == -ERESTART_RESTARTBLOCK) && rmtp && | 648 | if ((err == -ERESTART_RESTARTBLOCK) && rmtp && |
622 | put_compat_timespec(&out, rmtp)) | 649 | put_compat_timespec(&out, rmtp)) |
623 | return -EFAULT; | 650 | return -EFAULT; |
651 | |||
652 | if (err == -ERESTART_RESTARTBLOCK) { | ||
653 | restart = ¤t_thread_info()->restart_block; | ||
654 | restart->fn = compat_clock_nanosleep_restart; | ||
655 | restart->arg1 = (unsigned long) rmtp; | ||
656 | } | ||
624 | return err; | 657 | return err; |
625 | } | 658 | } |
626 | 659 | ||
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 21c38a7e666b..d0ba190dfeb6 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
@@ -693,7 +693,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod | |||
693 | return t->task == NULL; | 693 | return t->task == NULL; |
694 | } | 694 | } |
695 | 695 | ||
696 | static long __sched nanosleep_restart(struct restart_block *restart) | 696 | long __sched hrtimer_nanosleep_restart(struct restart_block *restart) |
697 | { | 697 | { |
698 | struct hrtimer_sleeper t; | 698 | struct hrtimer_sleeper t; |
699 | struct timespec __user *rmtp; | 699 | struct timespec __user *rmtp; |
@@ -702,13 +702,13 @@ static long __sched nanosleep_restart(struct restart_block *restart) | |||
702 | 702 | ||
703 | restart->fn = do_no_restart_syscall; | 703 | restart->fn = do_no_restart_syscall; |
704 | 704 | ||
705 | hrtimer_init(&t.timer, restart->arg3, HRTIMER_ABS); | 705 | hrtimer_init(&t.timer, restart->arg0, HRTIMER_ABS); |
706 | t.timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0; | 706 | t.timer.expires.tv64 = ((u64)restart->arg3 << 32) | (u64) restart->arg2; |
707 | 707 | ||
708 | if (do_nanosleep(&t, HRTIMER_ABS)) | 708 | if (do_nanosleep(&t, HRTIMER_ABS)) |
709 | return 0; | 709 | return 0; |
710 | 710 | ||
711 | rmtp = (struct timespec __user *) restart->arg2; | 711 | rmtp = (struct timespec __user *) restart->arg1; |
712 | if (rmtp) { | 712 | if (rmtp) { |
713 | time = ktime_sub(t.timer.expires, t.timer.base->get_time()); | 713 | time = ktime_sub(t.timer.expires, t.timer.base->get_time()); |
714 | if (time.tv64 <= 0) | 714 | if (time.tv64 <= 0) |
@@ -718,7 +718,7 @@ static long __sched nanosleep_restart(struct restart_block *restart) | |||
718 | return -EFAULT; | 718 | return -EFAULT; |
719 | } | 719 | } |
720 | 720 | ||
721 | restart->fn = nanosleep_restart; | 721 | restart->fn = hrtimer_nanosleep_restart; |
722 | 722 | ||
723 | /* The other values in restart are already filled in */ | 723 | /* The other values in restart are already filled in */ |
724 | return -ERESTART_RESTARTBLOCK; | 724 | return -ERESTART_RESTARTBLOCK; |
@@ -751,11 +751,11 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, | |||
751 | } | 751 | } |
752 | 752 | ||
753 | restart = ¤t_thread_info()->restart_block; | 753 | restart = ¤t_thread_info()->restart_block; |
754 | restart->fn = nanosleep_restart; | 754 | restart->fn = hrtimer_nanosleep_restart; |
755 | restart->arg0 = t.timer.expires.tv64 & 0xFFFFFFFF; | 755 | restart->arg0 = (unsigned long) t.timer.base->index; |
756 | restart->arg1 = t.timer.expires.tv64 >> 32; | 756 | restart->arg1 = (unsigned long) rmtp; |
757 | restart->arg2 = (unsigned long) rmtp; | 757 | restart->arg2 = t.timer.expires.tv64 & 0xFFFFFFFF; |
758 | restart->arg3 = (unsigned long) t.timer.base->index; | 758 | restart->arg3 = t.timer.expires.tv64 >> 32; |
759 | 759 | ||
760 | return -ERESTART_RESTARTBLOCK; | 760 | return -ERESTART_RESTARTBLOCK; |
761 | } | 761 | } |
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index d38d9ec3276c..5667fef89dd1 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c | |||
@@ -1393,8 +1393,6 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx, | |||
1393 | } | 1393 | } |
1394 | } | 1394 | } |
1395 | 1395 | ||
1396 | static long posix_cpu_clock_nanosleep_restart(struct restart_block *); | ||
1397 | |||
1398 | int posix_cpu_nsleep(const clockid_t which_clock, int flags, | 1396 | int posix_cpu_nsleep(const clockid_t which_clock, int flags, |
1399 | struct timespec *rqtp, struct timespec __user *rmtp) | 1397 | struct timespec *rqtp, struct timespec __user *rmtp) |
1400 | { | 1398 | { |
@@ -1471,7 +1469,7 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags, | |||
1471 | copy_to_user(rmtp, &it.it_value, sizeof *rmtp)) | 1469 | copy_to_user(rmtp, &it.it_value, sizeof *rmtp)) |
1472 | return -EFAULT; | 1470 | return -EFAULT; |
1473 | 1471 | ||
1474 | restart_block->fn = posix_cpu_clock_nanosleep_restart; | 1472 | restart_block->fn = posix_cpu_nsleep_restart; |
1475 | /* Caller already set restart_block->arg1 */ | 1473 | /* Caller already set restart_block->arg1 */ |
1476 | restart_block->arg0 = which_clock; | 1474 | restart_block->arg0 = which_clock; |
1477 | restart_block->arg1 = (unsigned long) rmtp; | 1475 | restart_block->arg1 = (unsigned long) rmtp; |
@@ -1484,8 +1482,7 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags, | |||
1484 | return error; | 1482 | return error; |
1485 | } | 1483 | } |
1486 | 1484 | ||
1487 | static long | 1485 | long posix_cpu_nsleep_restart(struct restart_block *restart_block) |
1488 | posix_cpu_clock_nanosleep_restart(struct restart_block *restart_block) | ||
1489 | { | 1486 | { |
1490 | clockid_t which_clock = restart_block->arg0; | 1487 | clockid_t which_clock = restart_block->arg0; |
1491 | struct timespec __user *rmtp; | 1488 | struct timespec __user *rmtp; |
@@ -1524,6 +1521,10 @@ static int process_cpu_nsleep(const clockid_t which_clock, int flags, | |||
1524 | { | 1521 | { |
1525 | return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp); | 1522 | return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp); |
1526 | } | 1523 | } |
1524 | static long process_cpu_nsleep_restart(struct restart_block *restart_block) | ||
1525 | { | ||
1526 | return -EINVAL; | ||
1527 | } | ||
1527 | static int thread_cpu_clock_getres(const clockid_t which_clock, | 1528 | static int thread_cpu_clock_getres(const clockid_t which_clock, |
1528 | struct timespec *tp) | 1529 | struct timespec *tp) |
1529 | { | 1530 | { |
@@ -1544,6 +1545,10 @@ static int thread_cpu_nsleep(const clockid_t which_clock, int flags, | |||
1544 | { | 1545 | { |
1545 | return -EINVAL; | 1546 | return -EINVAL; |
1546 | } | 1547 | } |
1548 | static long thread_cpu_nsleep_restart(struct restart_block *restart_block) | ||
1549 | { | ||
1550 | return -EINVAL; | ||
1551 | } | ||
1547 | 1552 | ||
1548 | static __init int init_posix_cpu_timers(void) | 1553 | static __init int init_posix_cpu_timers(void) |
1549 | { | 1554 | { |
@@ -1553,6 +1558,7 @@ static __init int init_posix_cpu_timers(void) | |||
1553 | .clock_set = do_posix_clock_nosettime, | 1558 | .clock_set = do_posix_clock_nosettime, |
1554 | .timer_create = process_cpu_timer_create, | 1559 | .timer_create = process_cpu_timer_create, |
1555 | .nsleep = process_cpu_nsleep, | 1560 | .nsleep = process_cpu_nsleep, |
1561 | .nsleep_restart = process_cpu_nsleep_restart, | ||
1556 | }; | 1562 | }; |
1557 | struct k_clock thread = { | 1563 | struct k_clock thread = { |
1558 | .clock_getres = thread_cpu_clock_getres, | 1564 | .clock_getres = thread_cpu_clock_getres, |
@@ -1560,6 +1566,7 @@ static __init int init_posix_cpu_timers(void) | |||
1560 | .clock_set = do_posix_clock_nosettime, | 1566 | .clock_set = do_posix_clock_nosettime, |
1561 | .timer_create = thread_cpu_timer_create, | 1567 | .timer_create = thread_cpu_timer_create, |
1562 | .nsleep = thread_cpu_nsleep, | 1568 | .nsleep = thread_cpu_nsleep, |
1569 | .nsleep_restart = thread_cpu_nsleep_restart, | ||
1563 | }; | 1570 | }; |
1564 | 1571 | ||
1565 | register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process); | 1572 | register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process); |
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index ac6dc8744429..e5ebcc1ec3a0 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c | |||
@@ -973,3 +973,24 @@ sys_clock_nanosleep(const clockid_t which_clock, int flags, | |||
973 | return CLOCK_DISPATCH(which_clock, nsleep, | 973 | return CLOCK_DISPATCH(which_clock, nsleep, |
974 | (which_clock, flags, &t, rmtp)); | 974 | (which_clock, flags, &t, rmtp)); |
975 | } | 975 | } |
976 | |||
977 | /* | ||
978 | * nanosleep_restart for monotonic and realtime clocks | ||
979 | */ | ||
980 | static int common_nsleep_restart(struct restart_block *restart_block) | ||
981 | { | ||
982 | return hrtimer_nanosleep_restart(restart_block); | ||
983 | } | ||
984 | |||
985 | /* | ||
986 | * This will restart clock_nanosleep. This is required only by | ||
987 | * compat_clock_nanosleep_restart for now. | ||
988 | */ | ||
989 | long | ||
990 | clock_nanosleep_restart(struct restart_block *restart_block) | ||
991 | { | ||
992 | clockid_t which_clock = restart_block->arg0; | ||
993 | |||
994 | return CLOCK_DISPATCH(which_clock, nsleep_restart, | ||
995 | (restart_block)); | ||
996 | } | ||