Commit 89dd8eec authored by Andrei Vagin's avatar Andrei Vagin Committed by Thomas Gleixner
Browse files

time: Add do_timens_ktime_to_host() helper



The helper subtracts namespace's clock offset from the given time
and ensures that the result is within [0, KTIME_MAX].

Co-developed-by: default avatarDmitry Safonov <dima@arista.com>
Signed-off-by: default avatarAndrei Vagin <avagin@gmail.com>
Signed-off-by: default avatarDmitry Safonov <dima@arista.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20191112012724.250792-13-dima@arista.com
parent 5a590f35
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -59,6 +59,19 @@ static inline void timens_add_boottime(struct timespec64 *ts)
	*ts = timespec64_add(*ts, ns_offsets->boottime);
}

ktime_t do_timens_ktime_to_host(clockid_t clockid, ktime_t tim,
				struct timens_offsets *offsets);

static inline ktime_t timens_ktime_to_host(clockid_t clockid, ktime_t tim)
{
	struct time_namespace *ns = current->nsproxy->time_ns;

	if (likely(ns == &init_time_ns))
		return tim;

	return do_timens_ktime_to_host(clockid, tim, &ns->offsets);
}

#else
static inline struct time_namespace *get_time_ns(struct time_namespace *ns)
{
@@ -88,6 +101,10 @@ static inline int timens_on_fork(struct nsproxy *nsproxy,

static inline void timens_add_monotonic(struct timespec64 *ts) { }
static inline void timens_add_boottime(struct timespec64 *ts) { }
static inline ktime_t timens_ktime_to_host(clockid_t clockid, ktime_t tim)
{
	return tim;
}
#endif

#endif /* _LINUX_TIMENS_H */
+36 −0
Original line number Diff line number Diff line
@@ -16,6 +16,42 @@
#include <linux/err.h>
#include <linux/mm.h>

ktime_t do_timens_ktime_to_host(clockid_t clockid, ktime_t tim,
				struct timens_offsets *ns_offsets)
{
	ktime_t offset;

	switch (clockid) {
	case CLOCK_MONOTONIC:
		offset = timespec64_to_ktime(ns_offsets->monotonic);
		break;
	case CLOCK_BOOTTIME:
	case CLOCK_BOOTTIME_ALARM:
		offset = timespec64_to_ktime(ns_offsets->boottime);
		break;
	default:
		return tim;
	}

	/*
	 * Check that @tim value is in [offset, KTIME_MAX + offset]
	 * and subtract offset.
	 */
	if (tim < offset) {
		/*
		 * User can specify @tim *absolute* value - if it's lesser than
		 * the time namespace's offset - it's already expired.
		 */
		tim = 0;
	} else {
		tim = ktime_sub(tim, offset);
		if (unlikely(tim > KTIME_MAX))
			tim = KTIME_MAX;
	}

	return tim;
}

static struct ucounts *inc_time_namespaces(struct user_namespace *ns)
{
	return inc_ucount(ns, current_euid(), UCOUNT_TIME_NAMESPACES);