diff options
Diffstat (limited to 'kernel/itimer.c')
| -rw-r--r-- | kernel/itimer.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/kernel/itimer.c b/kernel/itimer.c index 379be2f8c84c..680e6b70c872 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c | |||
| @@ -143,6 +143,60 @@ int it_real_fn(void *data) | |||
| 143 | return HRTIMER_NORESTART; | 143 | return HRTIMER_NORESTART; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | /* | ||
| 147 | * We do not care about correctness. We just sanitize the values so | ||
| 148 | * the ktime_t operations which expect normalized values do not | ||
| 149 | * break. This converts negative values to long timeouts similar to | ||
| 150 | * the code in kernel versions < 2.6.16 | ||
| 151 | * | ||
| 152 | * Print a limited number of warning messages when an invalid timeval | ||
| 153 | * is detected. | ||
| 154 | */ | ||
| 155 | static void fixup_timeval(struct timeval *tv, int interval) | ||
| 156 | { | ||
| 157 | static int warnlimit = 10; | ||
| 158 | unsigned long tmp; | ||
| 159 | |||
| 160 | if (warnlimit > 0) { | ||
| 161 | warnlimit--; | ||
| 162 | printk(KERN_WARNING | ||
| 163 | "setitimer: %s (pid = %d) provided " | ||
| 164 | "invalid timeval %s: tv_sec = %ld tv_usec = %ld\n", | ||
| 165 | current->comm, current->pid, | ||
| 166 | interval ? "it_interval" : "it_value", | ||
| 167 | tv->tv_sec, (long) tv->tv_usec); | ||
| 168 | } | ||
| 169 | |||
| 170 | tmp = tv->tv_usec; | ||
| 171 | if (tmp >= USEC_PER_SEC) { | ||
| 172 | tv->tv_usec = tmp % USEC_PER_SEC; | ||
| 173 | tv->tv_sec += tmp / USEC_PER_SEC; | ||
| 174 | } | ||
| 175 | |||
| 176 | tmp = tv->tv_sec; | ||
| 177 | if (tmp > LONG_MAX) | ||
| 178 | tv->tv_sec = LONG_MAX; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* | ||
| 182 | * Returns true if the timeval is in canonical form | ||
| 183 | */ | ||
| 184 | #define timeval_valid(t) \ | ||
| 185 | (((t)->tv_sec >= 0) && (((unsigned long) (t)->tv_usec) < USEC_PER_SEC)) | ||
| 186 | |||
| 187 | /* | ||
| 188 | * Check for invalid timevals, sanitize them and print a limited | ||
| 189 | * number of warnings. | ||
| 190 | */ | ||
| 191 | static void check_itimerval(struct itimerval *value) { | ||
| 192 | |||
| 193 | if (unlikely(!timeval_valid(&value->it_value))) | ||
| 194 | fixup_timeval(&value->it_value, 0); | ||
| 195 | |||
| 196 | if (unlikely(!timeval_valid(&value->it_interval))) | ||
| 197 | fixup_timeval(&value->it_interval, 1); | ||
| 198 | } | ||
| 199 | |||
| 146 | int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) | 200 | int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) |
| 147 | { | 201 | { |
| 148 | struct task_struct *tsk = current; | 202 | struct task_struct *tsk = current; |
| @@ -150,6 +204,18 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) | |||
| 150 | ktime_t expires; | 204 | ktime_t expires; |
| 151 | cputime_t cval, cinterval, nval, ninterval; | 205 | cputime_t cval, cinterval, nval, ninterval; |
| 152 | 206 | ||
| 207 | /* | ||
| 208 | * Validate the timevals in value. | ||
| 209 | * | ||
| 210 | * Note: Although the spec requires that invalid values shall | ||
| 211 | * return -EINVAL, we just fixup the value and print a limited | ||
| 212 | * number of warnings in order not to break users of this | ||
| 213 | * historical misfeature. | ||
| 214 | * | ||
| 215 | * Scheduled for replacement in March 2007 | ||
| 216 | */ | ||
| 217 | check_itimerval(value); | ||
| 218 | |||
| 153 | switch (which) { | 219 | switch (which) { |
| 154 | case ITIMER_REAL: | 220 | case ITIMER_REAL: |
| 155 | again: | 221 | again: |
| @@ -226,6 +292,43 @@ again: | |||
| 226 | return 0; | 292 | return 0; |
| 227 | } | 293 | } |
| 228 | 294 | ||
| 295 | /** | ||
| 296 | * alarm_setitimer - set alarm in seconds | ||
| 297 | * | ||
| 298 | * @seconds: number of seconds until alarm | ||
| 299 | * 0 disables the alarm | ||
| 300 | * | ||
| 301 | * Returns the remaining time in seconds of a pending timer or 0 when | ||
| 302 | * the timer is not active. | ||
| 303 | * | ||
| 304 | * On 32 bit machines the seconds value is limited to (INT_MAX/2) to avoid | ||
| 305 | * negative timeval settings which would cause immediate expiry. | ||
| 306 | */ | ||
| 307 | unsigned int alarm_setitimer(unsigned int seconds) | ||
| 308 | { | ||
| 309 | struct itimerval it_new, it_old; | ||
| 310 | |||
| 311 | #if BITS_PER_LONG < 64 | ||
| 312 | if (seconds > INT_MAX) | ||
| 313 | seconds = INT_MAX; | ||
| 314 | #endif | ||
| 315 | it_new.it_value.tv_sec = seconds; | ||
| 316 | it_new.it_value.tv_usec = 0; | ||
| 317 | it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0; | ||
| 318 | |||
| 319 | do_setitimer(ITIMER_REAL, &it_new, &it_old); | ||
| 320 | |||
| 321 | /* | ||
| 322 | * We can't return 0 if we have an alarm pending ... And we'd | ||
| 323 | * better return too much than too little anyway | ||
| 324 | */ | ||
| 325 | if ((!it_old.it_value.tv_sec && it_old.it_value.tv_usec) || | ||
| 326 | it_old.it_value.tv_usec >= 500000) | ||
| 327 | it_old.it_value.tv_sec++; | ||
| 328 | |||
| 329 | return it_old.it_value.tv_sec; | ||
| 330 | } | ||
| 331 | |||
| 229 | asmlinkage long sys_setitimer(int which, | 332 | asmlinkage long sys_setitimer(int which, |
| 230 | struct itimerval __user *value, | 333 | struct itimerval __user *value, |
| 231 | struct itimerval __user *ovalue) | 334 | struct itimerval __user *ovalue) |
