summaryrefslogtreecommitdiffstats
path: root/kernel/time/hrtimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/time/hrtimer.c')
-rw-r--r--kernel/time/hrtimer.c106
1 files changed, 64 insertions, 42 deletions
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index ac053bb5296e..81da124f1115 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -51,6 +51,7 @@
51#include <linux/sched/debug.h> 51#include <linux/sched/debug.h>
52#include <linux/timer.h> 52#include <linux/timer.h>
53#include <linux/freezer.h> 53#include <linux/freezer.h>
54#include <linux/compat.h>
54 55
55#include <linux/uaccess.h> 56#include <linux/uaccess.h>
56 57
@@ -1439,8 +1440,29 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task)
1439} 1440}
1440EXPORT_SYMBOL_GPL(hrtimer_init_sleeper); 1441EXPORT_SYMBOL_GPL(hrtimer_init_sleeper);
1441 1442
1443int nanosleep_copyout(struct restart_block *restart, struct timespec *ts)
1444{
1445 switch(restart->nanosleep.type) {
1446#ifdef CONFIG_COMPAT
1447 case TT_COMPAT:
1448 if (compat_put_timespec(ts, restart->nanosleep.compat_rmtp))
1449 return -EFAULT;
1450 break;
1451#endif
1452 case TT_NATIVE:
1453 if (copy_to_user(restart->nanosleep.rmtp, ts, sizeof(struct timespec)))
1454 return -EFAULT;
1455 break;
1456 default:
1457 BUG();
1458 }
1459 return -ERESTART_RESTARTBLOCK;
1460}
1461
1442static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode) 1462static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)
1443{ 1463{
1464 struct restart_block *restart;
1465
1444 hrtimer_init_sleeper(t, current); 1466 hrtimer_init_sleeper(t, current);
1445 1467
1446 do { 1468 do {
@@ -1457,53 +1479,38 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
1457 1479
1458 __set_current_state(TASK_RUNNING); 1480 __set_current_state(TASK_RUNNING);
1459 1481
1460 return t->task == NULL; 1482 if (!t->task)
1461}
1462
1463static int update_rmtp(struct hrtimer *timer, struct timespec __user *rmtp)
1464{
1465 struct timespec rmt;
1466 ktime_t rem;
1467
1468 rem = hrtimer_expires_remaining(timer);
1469 if (rem <= 0)
1470 return 0; 1483 return 0;
1471 rmt = ktime_to_timespec(rem);
1472 1484
1473 if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) 1485 restart = &current->restart_block;
1474 return -EFAULT; 1486 if (restart->nanosleep.type != TT_NONE) {
1487 ktime_t rem = hrtimer_expires_remaining(&t->timer);
1488 struct timespec rmt;
1475 1489
1476 return 1; 1490 if (rem <= 0)
1491 return 0;
1492 rmt = ktime_to_timespec(rem);
1493
1494 return nanosleep_copyout(restart, &rmt);
1495 }
1496 return -ERESTART_RESTARTBLOCK;
1477} 1497}
1478 1498
1479long __sched hrtimer_nanosleep_restart(struct restart_block *restart) 1499static long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
1480{ 1500{
1481 struct hrtimer_sleeper t; 1501 struct hrtimer_sleeper t;
1482 struct timespec __user *rmtp; 1502 int ret;
1483 int ret = 0;
1484 1503
1485 hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid, 1504 hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid,
1486 HRTIMER_MODE_ABS); 1505 HRTIMER_MODE_ABS);
1487 hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires); 1506 hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires);
1488 1507
1489 if (do_nanosleep(&t, HRTIMER_MODE_ABS)) 1508 ret = do_nanosleep(&t, HRTIMER_MODE_ABS);
1490 goto out;
1491
1492 rmtp = restart->nanosleep.rmtp;
1493 if (rmtp) {
1494 ret = update_rmtp(&t.timer, rmtp);
1495 if (ret <= 0)
1496 goto out;
1497 }
1498
1499 /* The other values in restart are already filled in */
1500 ret = -ERESTART_RESTARTBLOCK;
1501out:
1502 destroy_hrtimer_on_stack(&t.timer); 1509 destroy_hrtimer_on_stack(&t.timer);
1503 return ret; 1510 return ret;
1504} 1511}
1505 1512
1506long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp, 1513long hrtimer_nanosleep(const struct timespec64 *rqtp,
1507 const enum hrtimer_mode mode, const clockid_t clockid) 1514 const enum hrtimer_mode mode, const clockid_t clockid)
1508{ 1515{
1509 struct restart_block *restart; 1516 struct restart_block *restart;
@@ -1517,7 +1524,8 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp,
1517 1524
1518 hrtimer_init_on_stack(&t.timer, clockid, mode); 1525 hrtimer_init_on_stack(&t.timer, clockid, mode);
1519 hrtimer_set_expires_range_ns(&t.timer, timespec64_to_ktime(*rqtp), slack); 1526 hrtimer_set_expires_range_ns(&t.timer, timespec64_to_ktime(*rqtp), slack);
1520 if (do_nanosleep(&t, mode)) 1527 ret = do_nanosleep(&t, mode);
1528 if (ret != -ERESTART_RESTARTBLOCK)
1521 goto out; 1529 goto out;
1522 1530
1523 /* Absolute timers do not update the rmtp value and restart: */ 1531 /* Absolute timers do not update the rmtp value and restart: */
@@ -1526,19 +1534,10 @@ long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp,
1526 goto out; 1534 goto out;
1527 } 1535 }
1528 1536
1529 if (rmtp) {
1530 ret = update_rmtp(&t.timer, rmtp);
1531 if (ret <= 0)
1532 goto out;
1533 }
1534
1535 restart = &current->restart_block; 1537 restart = &current->restart_block;
1536 restart->fn = hrtimer_nanosleep_restart; 1538 restart->fn = hrtimer_nanosleep_restart;
1537 restart->nanosleep.clockid = t.timer.base->clockid; 1539 restart->nanosleep.clockid = t.timer.base->clockid;
1538 restart->nanosleep.rmtp = rmtp;
1539 restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer); 1540 restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer);
1540
1541 ret = -ERESTART_RESTARTBLOCK;
1542out: 1541out:
1543 destroy_hrtimer_on_stack(&t.timer); 1542 destroy_hrtimer_on_stack(&t.timer);
1544 return ret; 1543 return ret;
@@ -1557,8 +1556,31 @@ SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
1557 if (!timespec64_valid(&tu64)) 1556 if (!timespec64_valid(&tu64))
1558 return -EINVAL; 1557 return -EINVAL;
1559 1558
1560 return hrtimer_nanosleep(&tu64, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC); 1559 current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
1560 current->restart_block.nanosleep.rmtp = rmtp;
1561 return hrtimer_nanosleep(&tu64, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
1562}
1563
1564#ifdef CONFIG_COMPAT
1565
1566COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
1567 struct compat_timespec __user *, rmtp)
1568{
1569 struct timespec64 tu64;
1570 struct timespec tu;
1571
1572 if (compat_get_timespec(&tu, rqtp))
1573 return -EFAULT;
1574
1575 tu64 = timespec_to_timespec64(tu);
1576 if (!timespec64_valid(&tu64))
1577 return -EINVAL;
1578
1579 current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
1580 current->restart_block.nanosleep.compat_rmtp = rmtp;
1581 return hrtimer_nanosleep(&tu64, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
1561} 1582}
1583#endif
1562 1584
1563/* 1585/*
1564 * Functions related to boot-time initialization: 1586 * Functions related to boot-time initialization: