diff options
Diffstat (limited to 'kernel/time/posix-timers.c')
-rw-r--r-- | kernel/time/posix-timers.c | 61 |
1 files changed, 50 insertions, 11 deletions
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index d7f2d91acdac..0ec5b7a1d769 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c | |||
@@ -442,7 +442,7 @@ static struct k_itimer * alloc_posix_timer(void) | |||
442 | 442 | ||
443 | static void k_itimer_rcu_free(struct rcu_head *head) | 443 | static void k_itimer_rcu_free(struct rcu_head *head) |
444 | { | 444 | { |
445 | struct k_itimer *tmr = container_of(head, struct k_itimer, it.rcu); | 445 | struct k_itimer *tmr = container_of(head, struct k_itimer, rcu); |
446 | 446 | ||
447 | kmem_cache_free(posix_timers_cache, tmr); | 447 | kmem_cache_free(posix_timers_cache, tmr); |
448 | } | 448 | } |
@@ -459,7 +459,7 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set) | |||
459 | } | 459 | } |
460 | put_pid(tmr->it_pid); | 460 | put_pid(tmr->it_pid); |
461 | sigqueue_free(tmr->sigq); | 461 | sigqueue_free(tmr->sigq); |
462 | call_rcu(&tmr->it.rcu, k_itimer_rcu_free); | 462 | call_rcu(&tmr->rcu, k_itimer_rcu_free); |
463 | } | 463 | } |
464 | 464 | ||
465 | static int common_timer_create(struct k_itimer *new_timer) | 465 | static int common_timer_create(struct k_itimer *new_timer) |
@@ -805,6 +805,35 @@ static int common_hrtimer_try_to_cancel(struct k_itimer *timr) | |||
805 | return hrtimer_try_to_cancel(&timr->it.real.timer); | 805 | return hrtimer_try_to_cancel(&timr->it.real.timer); |
806 | } | 806 | } |
807 | 807 | ||
808 | static void common_timer_wait_running(struct k_itimer *timer) | ||
809 | { | ||
810 | hrtimer_cancel_wait_running(&timer->it.real.timer); | ||
811 | } | ||
812 | |||
813 | /* | ||
814 | * On PREEMPT_RT this prevent priority inversion against softirq kthread in | ||
815 | * case it gets preempted while executing a timer callback. See comments in | ||
816 | * hrtimer_cancel_wait_running. For PREEMPT_RT=n this just results in a | ||
817 | * cpu_relax(). | ||
818 | */ | ||
819 | static struct k_itimer *timer_wait_running(struct k_itimer *timer, | ||
820 | unsigned long *flags) | ||
821 | { | ||
822 | const struct k_clock *kc = READ_ONCE(timer->kclock); | ||
823 | timer_t timer_id = READ_ONCE(timer->it_id); | ||
824 | |||
825 | /* Prevent kfree(timer) after dropping the lock */ | ||
826 | rcu_read_lock(); | ||
827 | unlock_timer(timer, *flags); | ||
828 | |||
829 | if (!WARN_ON_ONCE(!kc->timer_wait_running)) | ||
830 | kc->timer_wait_running(timer); | ||
831 | |||
832 | rcu_read_unlock(); | ||
833 | /* Relock the timer. It might be not longer hashed. */ | ||
834 | return lock_timer(timer_id, flags); | ||
835 | } | ||
836 | |||
808 | /* Set a POSIX.1b interval timer. */ | 837 | /* Set a POSIX.1b interval timer. */ |
809 | int common_timer_set(struct k_itimer *timr, int flags, | 838 | int common_timer_set(struct k_itimer *timr, int flags, |
810 | struct itimerspec64 *new_setting, | 839 | struct itimerspec64 *new_setting, |
@@ -844,13 +873,13 @@ int common_timer_set(struct k_itimer *timr, int flags, | |||
844 | return 0; | 873 | return 0; |
845 | } | 874 | } |
846 | 875 | ||
847 | static int do_timer_settime(timer_t timer_id, int flags, | 876 | static int do_timer_settime(timer_t timer_id, int tmr_flags, |
848 | struct itimerspec64 *new_spec64, | 877 | struct itimerspec64 *new_spec64, |
849 | struct itimerspec64 *old_spec64) | 878 | struct itimerspec64 *old_spec64) |
850 | { | 879 | { |
851 | const struct k_clock *kc; | 880 | const struct k_clock *kc; |
852 | struct k_itimer *timr; | 881 | struct k_itimer *timr; |
853 | unsigned long flag; | 882 | unsigned long flags; |
854 | int error = 0; | 883 | int error = 0; |
855 | 884 | ||
856 | if (!timespec64_valid(&new_spec64->it_interval) || | 885 | if (!timespec64_valid(&new_spec64->it_interval) || |
@@ -859,8 +888,9 @@ static int do_timer_settime(timer_t timer_id, int flags, | |||
859 | 888 | ||
860 | if (old_spec64) | 889 | if (old_spec64) |
861 | memset(old_spec64, 0, sizeof(*old_spec64)); | 890 | memset(old_spec64, 0, sizeof(*old_spec64)); |
891 | |||
892 | timr = lock_timer(timer_id, &flags); | ||
862 | retry: | 893 | retry: |
863 | timr = lock_timer(timer_id, &flag); | ||
864 | if (!timr) | 894 | if (!timr) |
865 | return -EINVAL; | 895 | return -EINVAL; |
866 | 896 | ||
@@ -868,13 +898,16 @@ retry: | |||
868 | if (WARN_ON_ONCE(!kc || !kc->timer_set)) | 898 | if (WARN_ON_ONCE(!kc || !kc->timer_set)) |
869 | error = -EINVAL; | 899 | error = -EINVAL; |
870 | else | 900 | else |
871 | error = kc->timer_set(timr, flags, new_spec64, old_spec64); | 901 | error = kc->timer_set(timr, tmr_flags, new_spec64, old_spec64); |
872 | 902 | ||
873 | unlock_timer(timr, flag); | ||
874 | if (error == TIMER_RETRY) { | 903 | if (error == TIMER_RETRY) { |
875 | old_spec64 = NULL; // We already got the old time... | 904 | // We already got the old time... |
905 | old_spec64 = NULL; | ||
906 | /* Unlocks and relocks the timer if it still exists */ | ||
907 | timr = timer_wait_running(timr, &flags); | ||
876 | goto retry; | 908 | goto retry; |
877 | } | 909 | } |
910 | unlock_timer(timr, flags); | ||
878 | 911 | ||
879 | return error; | 912 | return error; |
880 | } | 913 | } |
@@ -951,13 +984,15 @@ SYSCALL_DEFINE1(timer_delete, timer_t, timer_id) | |||
951 | struct k_itimer *timer; | 984 | struct k_itimer *timer; |
952 | unsigned long flags; | 985 | unsigned long flags; |
953 | 986 | ||
954 | retry_delete: | ||
955 | timer = lock_timer(timer_id, &flags); | 987 | timer = lock_timer(timer_id, &flags); |
988 | |||
989 | retry_delete: | ||
956 | if (!timer) | 990 | if (!timer) |
957 | return -EINVAL; | 991 | return -EINVAL; |
958 | 992 | ||
959 | if (timer_delete_hook(timer) == TIMER_RETRY) { | 993 | if (unlikely(timer_delete_hook(timer) == TIMER_RETRY)) { |
960 | unlock_timer(timer, flags); | 994 | /* Unlocks and relocks the timer if it still exists */ |
995 | timer = timer_wait_running(timer, &flags); | ||
961 | goto retry_delete; | 996 | goto retry_delete; |
962 | } | 997 | } |
963 | 998 | ||
@@ -1238,6 +1273,7 @@ static const struct k_clock clock_realtime = { | |||
1238 | .timer_forward = common_hrtimer_forward, | 1273 | .timer_forward = common_hrtimer_forward, |
1239 | .timer_remaining = common_hrtimer_remaining, | 1274 | .timer_remaining = common_hrtimer_remaining, |
1240 | .timer_try_to_cancel = common_hrtimer_try_to_cancel, | 1275 | .timer_try_to_cancel = common_hrtimer_try_to_cancel, |
1276 | .timer_wait_running = common_timer_wait_running, | ||
1241 | .timer_arm = common_hrtimer_arm, | 1277 | .timer_arm = common_hrtimer_arm, |
1242 | }; | 1278 | }; |
1243 | 1279 | ||
@@ -1253,6 +1289,7 @@ static const struct k_clock clock_monotonic = { | |||
1253 | .timer_forward = common_hrtimer_forward, | 1289 | .timer_forward = common_hrtimer_forward, |
1254 | .timer_remaining = common_hrtimer_remaining, | 1290 | .timer_remaining = common_hrtimer_remaining, |
1255 | .timer_try_to_cancel = common_hrtimer_try_to_cancel, | 1291 | .timer_try_to_cancel = common_hrtimer_try_to_cancel, |
1292 | .timer_wait_running = common_timer_wait_running, | ||
1256 | .timer_arm = common_hrtimer_arm, | 1293 | .timer_arm = common_hrtimer_arm, |
1257 | }; | 1294 | }; |
1258 | 1295 | ||
@@ -1283,6 +1320,7 @@ static const struct k_clock clock_tai = { | |||
1283 | .timer_forward = common_hrtimer_forward, | 1320 | .timer_forward = common_hrtimer_forward, |
1284 | .timer_remaining = common_hrtimer_remaining, | 1321 | .timer_remaining = common_hrtimer_remaining, |
1285 | .timer_try_to_cancel = common_hrtimer_try_to_cancel, | 1322 | .timer_try_to_cancel = common_hrtimer_try_to_cancel, |
1323 | .timer_wait_running = common_timer_wait_running, | ||
1286 | .timer_arm = common_hrtimer_arm, | 1324 | .timer_arm = common_hrtimer_arm, |
1287 | }; | 1325 | }; |
1288 | 1326 | ||
@@ -1298,6 +1336,7 @@ static const struct k_clock clock_boottime = { | |||
1298 | .timer_forward = common_hrtimer_forward, | 1336 | .timer_forward = common_hrtimer_forward, |
1299 | .timer_remaining = common_hrtimer_remaining, | 1337 | .timer_remaining = common_hrtimer_remaining, |
1300 | .timer_try_to_cancel = common_hrtimer_try_to_cancel, | 1338 | .timer_try_to_cancel = common_hrtimer_try_to_cancel, |
1339 | .timer_wait_running = common_timer_wait_running, | ||
1301 | .timer_arm = common_hrtimer_arm, | 1340 | .timer_arm = common_hrtimer_arm, |
1302 | }; | 1341 | }; |
1303 | 1342 | ||