diff options
Diffstat (limited to 'kernel/time/hrtimer.c')
-rw-r--r-- | kernel/time/hrtimer.c | 106 |
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 | } |
1440 | EXPORT_SYMBOL_GPL(hrtimer_init_sleeper); | 1441 | EXPORT_SYMBOL_GPL(hrtimer_init_sleeper); |
1441 | 1442 | ||
1443 | int 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 | |||
1442 | static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode) | 1462 | static 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 | |||
1463 | static 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 = ¤t->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 | ||
1479 | long __sched hrtimer_nanosleep_restart(struct restart_block *restart) | 1499 | static 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; | ||
1501 | out: | ||
1502 | destroy_hrtimer_on_stack(&t.timer); | 1509 | destroy_hrtimer_on_stack(&t.timer); |
1503 | return ret; | 1510 | return ret; |
1504 | } | 1511 | } |
1505 | 1512 | ||
1506 | long hrtimer_nanosleep(struct timespec64 *rqtp, struct timespec __user *rmtp, | 1513 | long 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 = ¤t->restart_block; | 1537 | restart = ¤t->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; | ||
1542 | out: | 1541 | out: |
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 | |||
1566 | COMPAT_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: |