aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/timerfd.c57
-rw-r--r--include/linux/hrtimer.h2
-rw-r--r--include/linux/time.h6
-rw-r--r--include/linux/timerfd.h3
-rw-r--r--kernel/hrtimer.c36
-rw-r--r--kernel/time/timekeeping.c15
6 files changed, 111 insertions, 8 deletions
diff --git a/fs/timerfd.c b/fs/timerfd.c
index 8c4fc1425b3e..7e14c9e7c4ee 100644
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -26,10 +26,12 @@
26struct timerfd_ctx { 26struct timerfd_ctx {
27 struct hrtimer tmr; 27 struct hrtimer tmr;
28 ktime_t tintv; 28 ktime_t tintv;
29 ktime_t moffs;
29 wait_queue_head_t wqh; 30 wait_queue_head_t wqh;
30 u64 ticks; 31 u64 ticks;
31 int expired; 32 int expired;
32 int clockid; 33 int clockid;
34 bool might_cancel;
33}; 35};
34 36
35/* 37/*
@@ -59,24 +61,52 @@ static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
59 return remaining.tv64 < 0 ? ktime_set(0, 0): remaining; 61 return remaining.tv64 < 0 ? ktime_set(0, 0): remaining;
60} 62}
61 63
62static void timerfd_setup(struct timerfd_ctx *ctx, int flags, 64static bool timerfd_canceled(struct timerfd_ctx *ctx)
63 const struct itimerspec *ktmr) 65{
66 ktime_t moffs;
67
68 if (!ctx->might_cancel)
69 return false;
70
71 moffs = ktime_get_monotonic_offset();
72
73 if (moffs.tv64 == ctx->moffs.tv64)
74 return false;
75
76 ctx->moffs = moffs;
77 return true;
78}
79
80static int timerfd_setup(struct timerfd_ctx *ctx, int flags,
81 const struct itimerspec *ktmr)
64{ 82{
65 enum hrtimer_mode htmode; 83 enum hrtimer_mode htmode;
66 ktime_t texp; 84 ktime_t texp;
85 int clockid = ctx->clockid;
67 86
68 htmode = (flags & TFD_TIMER_ABSTIME) ? 87 htmode = (flags & TFD_TIMER_ABSTIME) ?
69 HRTIMER_MODE_ABS: HRTIMER_MODE_REL; 88 HRTIMER_MODE_ABS: HRTIMER_MODE_REL;
70 89
90 ctx->might_cancel = false;
91 if (htmode == HRTIMER_MODE_ABS && ctx->clockid == CLOCK_REALTIME &&
92 (flags & TFD_TIMER_CANCELON_SET)) {
93 clockid = CLOCK_REALTIME_COS;
94 ctx->might_cancel = true;
95 }
96
71 texp = timespec_to_ktime(ktmr->it_value); 97 texp = timespec_to_ktime(ktmr->it_value);
72 ctx->expired = 0; 98 ctx->expired = 0;
73 ctx->ticks = 0; 99 ctx->ticks = 0;
74 ctx->tintv = timespec_to_ktime(ktmr->it_interval); 100 ctx->tintv = timespec_to_ktime(ktmr->it_interval);
75 hrtimer_init(&ctx->tmr, ctx->clockid, htmode); 101 hrtimer_init(&ctx->tmr, clockid, htmode);
76 hrtimer_set_expires(&ctx->tmr, texp); 102 hrtimer_set_expires(&ctx->tmr, texp);
77 ctx->tmr.function = timerfd_tmrproc; 103 ctx->tmr.function = timerfd_tmrproc;
78 if (texp.tv64 != 0) 104 if (texp.tv64 != 0) {
79 hrtimer_start(&ctx->tmr, texp, htmode); 105 hrtimer_start(&ctx->tmr, texp, htmode);
106 if (timerfd_canceled(ctx))
107 return -ECANCELED;
108 }
109 return 0;
80} 110}
81 111
82static int timerfd_release(struct inode *inode, struct file *file) 112static int timerfd_release(struct inode *inode, struct file *file)
@@ -118,8 +148,21 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
118 res = -EAGAIN; 148 res = -EAGAIN;
119 else 149 else
120 res = wait_event_interruptible_locked_irq(ctx->wqh, ctx->ticks); 150 res = wait_event_interruptible_locked_irq(ctx->wqh, ctx->ticks);
151
121 if (ctx->ticks) { 152 if (ctx->ticks) {
122 ticks = ctx->ticks; 153 ticks = ctx->ticks;
154
155 /*
156 * If clock has changed, we do not care about the
157 * ticks and we do not rearm the timer. Userspace must
158 * reevaluate anyway.
159 */
160 if (timerfd_canceled(ctx)) {
161 ticks = 0;
162 ctx->expired = 0;
163 res = -ECANCELED;
164 }
165
123 if (ctx->expired && ctx->tintv.tv64) { 166 if (ctx->expired && ctx->tintv.tv64) {
124 /* 167 /*
125 * If tintv.tv64 != 0, this is a periodic timer that 168 * If tintv.tv64 != 0, this is a periodic timer that
@@ -183,6 +226,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
183 init_waitqueue_head(&ctx->wqh); 226 init_waitqueue_head(&ctx->wqh);
184 ctx->clockid = clockid; 227 ctx->clockid = clockid;
185 hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS); 228 hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);
229 ctx->moffs = ktime_get_monotonic_offset();
186 230
187 ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx, 231 ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
188 O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS)); 232 O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS));
@@ -199,6 +243,7 @@ SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
199 struct file *file; 243 struct file *file;
200 struct timerfd_ctx *ctx; 244 struct timerfd_ctx *ctx;
201 struct itimerspec ktmr, kotmr; 245 struct itimerspec ktmr, kotmr;
246 int ret;
202 247
203 if (copy_from_user(&ktmr, utmr, sizeof(ktmr))) 248 if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
204 return -EFAULT; 249 return -EFAULT;
@@ -240,14 +285,14 @@ SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
240 /* 285 /*
241 * Re-program the timer to the new value ... 286 * Re-program the timer to the new value ...
242 */ 287 */
243 timerfd_setup(ctx, flags, &ktmr); 288 ret = timerfd_setup(ctx, flags, &ktmr);
244 289
245 spin_unlock_irq(&ctx->wqh.lock); 290 spin_unlock_irq(&ctx->wqh.lock);
246 fput(file); 291 fput(file);
247 if (otmr && copy_to_user(otmr, &kotmr, sizeof(kotmr))) 292 if (otmr && copy_to_user(otmr, &kotmr, sizeof(kotmr)))
248 return -EFAULT; 293 return -EFAULT;
249 294
250 return 0; 295 return ret;
251} 296}
252 297
253SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr) 298SYSCALL_DEFINE2(timerfd_gettime, int, ufd, struct itimerspec __user *, otmr)
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 4135c88fe4fa..eda4ccde0730 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -155,6 +155,7 @@ enum hrtimer_base_type {
155 HRTIMER_BASE_REALTIME, 155 HRTIMER_BASE_REALTIME,
156 HRTIMER_BASE_MONOTONIC, 156 HRTIMER_BASE_MONOTONIC,
157 HRTIMER_BASE_BOOTTIME, 157 HRTIMER_BASE_BOOTTIME,
158 HRTIMER_BASE_REALTIME_COS,
158 HRTIMER_MAX_CLOCK_BASES, 159 HRTIMER_MAX_CLOCK_BASES,
159}; 160};
160 161
@@ -310,6 +311,7 @@ extern void hrtimers_resume(void);
310extern ktime_t ktime_get(void); 311extern ktime_t ktime_get(void);
311extern ktime_t ktime_get_real(void); 312extern ktime_t ktime_get_real(void);
312extern ktime_t ktime_get_boottime(void); 313extern ktime_t ktime_get_boottime(void);
314extern ktime_t ktime_get_monotonic_offset(void);
313 315
314DECLARE_PER_CPU(struct tick_device, tick_cpu_device); 316DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
315 317
diff --git a/include/linux/time.h b/include/linux/time.h
index b3061782dec3..a9242773eb24 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -302,6 +302,12 @@ struct itimerval {
302 * The IDs of various hardware clocks: 302 * The IDs of various hardware clocks:
303 */ 303 */
304#define CLOCK_SGI_CYCLE 10 304#define CLOCK_SGI_CYCLE 10
305
306#ifdef __KERNEL__
307/* This clock is not exposed to user space */
308#define CLOCK_REALTIME_COS 15
309#endif
310
305#define MAX_CLOCKS 16 311#define MAX_CLOCKS 16
306#define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC) 312#define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC)
307#define CLOCKS_MONO CLOCK_MONOTONIC 313#define CLOCKS_MONO CLOCK_MONOTONIC
diff --git a/include/linux/timerfd.h b/include/linux/timerfd.h
index 2d0792983f8c..e9571fc8f1a0 100644
--- a/include/linux/timerfd.h
+++ b/include/linux/timerfd.h
@@ -19,6 +19,7 @@
19 * shared O_* flags. 19 * shared O_* flags.
20 */ 20 */
21#define TFD_TIMER_ABSTIME (1 << 0) 21#define TFD_TIMER_ABSTIME (1 << 0)
22#define TFD_TIMER_CANCELON_SET (1 << 1)
22#define TFD_CLOEXEC O_CLOEXEC 23#define TFD_CLOEXEC O_CLOEXEC
23#define TFD_NONBLOCK O_NONBLOCK 24#define TFD_NONBLOCK O_NONBLOCK
24 25
@@ -26,6 +27,6 @@
26/* Flags for timerfd_create. */ 27/* Flags for timerfd_create. */
27#define TFD_CREATE_FLAGS TFD_SHARED_FCNTL_FLAGS 28#define TFD_CREATE_FLAGS TFD_SHARED_FCNTL_FLAGS
28/* Flags for timerfd_settime. */ 29/* Flags for timerfd_settime. */
29#define TFD_SETTIME_FLAGS TFD_TIMER_ABSTIME 30#define TFD_SETTIME_FLAGS (TFD_TIMER_ABSTIME | TFD_TIMER_CANCELON_SET)
30 31
31#endif /* _LINUX_TIMERFD_H */ 32#endif /* _LINUX_TIMERFD_H */
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index c145ed643bca..eabcbd781433 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -78,6 +78,11 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
78 .get_time = &ktime_get_boottime, 78 .get_time = &ktime_get_boottime,
79 .resolution = KTIME_LOW_RES, 79 .resolution = KTIME_LOW_RES,
80 }, 80 },
81 {
82 .index = CLOCK_REALTIME_COS,
83 .get_time = &ktime_get_real,
84 .resolution = KTIME_LOW_RES,
85 },
81 } 86 }
82}; 87};
83 88
@@ -85,6 +90,7 @@ static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
85 [CLOCK_REALTIME] = HRTIMER_BASE_REALTIME, 90 [CLOCK_REALTIME] = HRTIMER_BASE_REALTIME,
86 [CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC, 91 [CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC,
87 [CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME, 92 [CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME,
93 [CLOCK_REALTIME_COS] = HRTIMER_BASE_REALTIME_COS,
88}; 94};
89 95
90static inline int hrtimer_clockid_to_base(clockid_t clock_id) 96static inline int hrtimer_clockid_to_base(clockid_t clock_id)
@@ -110,6 +116,7 @@ static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
110 base->clock_base[HRTIMER_BASE_REALTIME].softirq_time = xtim; 116 base->clock_base[HRTIMER_BASE_REALTIME].softirq_time = xtim;
111 base->clock_base[HRTIMER_BASE_MONOTONIC].softirq_time = mono; 117 base->clock_base[HRTIMER_BASE_MONOTONIC].softirq_time = mono;
112 base->clock_base[HRTIMER_BASE_BOOTTIME].softirq_time = boot; 118 base->clock_base[HRTIMER_BASE_BOOTTIME].softirq_time = boot;
119 base->clock_base[HRTIMER_BASE_REALTIME_COS].softirq_time = xtim;
113} 120}
114 121
115/* 122/*
@@ -479,6 +486,8 @@ static inline void debug_deactivate(struct hrtimer *timer)
479 trace_hrtimer_cancel(timer); 486 trace_hrtimer_cancel(timer);
480} 487}
481 488
489static void hrtimer_expire_cancelable(struct hrtimer_cpu_base *cpu_base);
490
482/* High resolution timer related functions */ 491/* High resolution timer related functions */
483#ifdef CONFIG_HIGH_RES_TIMERS 492#ifdef CONFIG_HIGH_RES_TIMERS
484 493
@@ -715,9 +724,14 @@ static void retrigger_next_event(void *arg)
715 struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases); 724 struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases);
716 struct timespec realtime_offset, xtim, wtm, sleep; 725 struct timespec realtime_offset, xtim, wtm, sleep;
717 726
718 if (!hrtimer_hres_active()) 727 if (!hrtimer_hres_active()) {
728 raw_spin_lock(&base->lock);
729 hrtimer_expire_cancelable(base);
730 raw_spin_unlock(&base->lock);
719 return; 731 return;
732 }
720 733
734 /* Optimized out for !HIGH_RES */
721 get_xtime_and_monotonic_and_sleep_offset(&xtim, &wtm, &sleep); 735 get_xtime_and_monotonic_and_sleep_offset(&xtim, &wtm, &sleep);
722 set_normalized_timespec(&realtime_offset, -wtm.tv_sec, -wtm.tv_nsec); 736 set_normalized_timespec(&realtime_offset, -wtm.tv_sec, -wtm.tv_nsec);
723 737
@@ -727,6 +741,10 @@ static void retrigger_next_event(void *arg)
727 timespec_to_ktime(realtime_offset); 741 timespec_to_ktime(realtime_offset);
728 base->clock_base[HRTIMER_BASE_BOOTTIME].offset = 742 base->clock_base[HRTIMER_BASE_BOOTTIME].offset =
729 timespec_to_ktime(sleep); 743 timespec_to_ktime(sleep);
744 base->clock_base[HRTIMER_BASE_REALTIME_COS].offset =
745 timespec_to_ktime(realtime_offset);
746
747 hrtimer_expire_cancelable(base);
730 748
731 hrtimer_force_reprogram(base, 0); 749 hrtimer_force_reprogram(base, 0);
732 raw_spin_unlock(&base->lock); 750 raw_spin_unlock(&base->lock);
@@ -1222,6 +1240,22 @@ static void __run_hrtimer(struct hrtimer *timer, ktime_t *now)
1222 timer->state &= ~HRTIMER_STATE_CALLBACK; 1240 timer->state &= ~HRTIMER_STATE_CALLBACK;
1223} 1241}
1224 1242
1243static void hrtimer_expire_cancelable(struct hrtimer_cpu_base *cpu_base)
1244{
1245 struct timerqueue_node *node;
1246 struct hrtimer_clock_base *base;
1247 ktime_t now = ktime_get_real();
1248
1249 base = &cpu_base->clock_base[HRTIMER_BASE_REALTIME_COS];
1250
1251 while ((node = timerqueue_getnext(&base->active))) {
1252 struct hrtimer *timer;
1253
1254 timer = container_of(node, struct hrtimer, node);
1255 __run_hrtimer(timer, &now);
1256 }
1257}
1258
1225#ifdef CONFIG_HIGH_RES_TIMERS 1259#ifdef CONFIG_HIGH_RES_TIMERS
1226 1260
1227/* 1261/*
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index a61b8fa2d39a..342408cf68dd 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1099,6 +1099,21 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
1099} 1099}
1100 1100
1101/** 1101/**
1102 * ktime_get_monotonic_offset() - get wall_to_monotonic in ktime_t format
1103 */
1104ktime_t ktime_get_monotonic_offset(void)
1105{
1106 unsigned long seq;
1107 struct timespec wtom;
1108
1109 do {
1110 seq = read_seqbegin(&xtime_lock);
1111 wtom = wall_to_monotonic;
1112 } while (read_seqretry(&xtime_lock, seq));
1113 return timespec_to_ktime(wtom);
1114}
1115
1116/**
1102 * xtime_update() - advances the timekeeping infrastructure 1117 * xtime_update() - advances the timekeeping infrastructure
1103 * @ticks: number of ticks, that have elapsed since the last call. 1118 * @ticks: number of ticks, that have elapsed since the last call.
1104 * 1119 *