Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Tue, 8 Jun 2021 20:37:58 -0400
From: Rich Felker <dalias@...c.org>
To: musl@...ts.openwall.com
Cc: Martin Vajnar <martin.vajnar@...il.com>
Subject: Re: Backwards kernel compatibility

On Wed, Jun 09, 2021 at 12:16:40AM +0200, Martin Vajnar wrote:
> Hi, Rich,
> 
> Ășt 25. 5. 2021 v 0:00 odesĂ­latel Rich Felker <dalias@...c.org> napsal:
> >
> > On Mon, May 24, 2021 at 03:52:44PM +0200, Martin Vajnar wrote:
> > > Hi, Markus,
> > >
> > > sorry for the late reply it was quite busy lately. You're describing
> > > exactly the issue, we are facing in our project. We need to use old kernel
> > > which we have only in binary form and have headers for it. At the same time
> > > we would like to have the latest musl running on it.
> > >
> > > The problem we encounter is that for unsupported (or better said, not
> > > supported yet) syscalls we get performance overhead because of the ENOSYS.
> >
> > Can you give some information on what syscalls these are and if/how
> > you measured the performance overhead as being significant?
> >
> > > We see 2 options to approach this:
> > >
> > >  1. remove the syscalls manually/alter the code to not invoke them (hacky)
> > >  2. during musl compile time (maybe even configure-time), parse the
> > > supplied kernel headers and based on availability of syscalls use defines
> > > to steer the code execution (more universal)
> > >
> > > Would the 2nd case be something that musl community would be interested in,
> > > should we choose to implement it for the project?
> >
> > No, but hopefully there's a third option: identify whatever place the
> > fallback is actual a performance bottleneck and do what we can to
> > mitigate it. If it's really bad, saving the result might be an option,
> > but we've tried to avoid that both for complexity reasons and because
> > it could preclude fixing serious problems (like Y2038 EOL) by
> > live-migrating processes to a newer kernel with new syscalls that
> > avoid the bug. A better approach is just using the "oldest" syscall
> > that can actually do the job, which we already try to do in most
> > places in musl, only relying on the newer one for inputs that require
> > it. However this is not possible for functions that read back a time,
> > since the input is external (e.g. the system clock or the filesystem)
> > and it's not known in advance whether the old syscall could represent
> > the result.
> >
> > It *might* be plausible to memorize the result "new syscall not
> > available" but drop that memory whenever we see a result that
> > indicates a failure due to use of the outdated syscall. We're kinda
> > already doing that with the vdso clock_gettime -- cgt_time32_wrap
> > disables itself if it ever sees a negative value for seconds.
> 
> Since updating the kernel is not an option for me, I prepared patch
> implementing memorizing failed syscall attempt on the time64 variants
> and on statx syscall, so on next attempt it will skip them and use
> fallback directly. Attaching the patch in case someone is solving the
> same issue. Please, let me know, if this approach would be something
> interesting for upstreaming and if so, if there are any changes I
> should make.

It's not acceptable as written for upstream. All of the memorization
is data races, and as noted before, it breaks the usage case of live
migration (CRIU or similar) from a 2038-EOL'd kernel to one with a
future.

If you want to maintain a patch to apply locally, I think it would
make sense to do away with trying to keep indentation "right" so that
the patches are minimal, even if you end up using goto. Also I think
the patch is making some changes you don't need. See below:


> From ceb2371ada673d258328a019691bff014ea3abca Mon Sep 17 00:00:00 2001
> From: Martin Vajnar <martin.vajnar@...il.com>
> Date: Tue, 8 Jun 2021 23:36:11 +0200
> Subject: [PATCH] store fallback paths for kernels without time64/statx
>  syscalls
> 
> ---
>  src/ipc/semtimedop.c                 |  12 ++--
>  src/linux/clock_adjtime.c            | 100 ++++++++++++++-------------
>  src/linux/ppoll.c                    |  16 +++--
>  src/linux/timerfd.c                  |  28 +++++---
>  src/misc/getrusage.c                 |  28 ++++----
>  src/mq/mq_timedreceive.c             |  14 ++--
>  src/mq/mq_timedsend.c                |  14 ++--
>  src/network/recvmmsg.c               |  13 ++--
>  src/select/pselect.c                 |  14 ++--
>  src/select/select.c                  |  16 +++--
>  src/signal/sigtimedwait.c            |  14 ++--
>  src/stat/fstatat.c                   |  10 ++-
>  src/stat/utimensat.c                 |  14 ++--
>  src/thread/__timedwait.c             |  12 ++--
>  src/thread/pthread_mutex_timedlock.c |  12 ++--
>  src/time/clock_gettime.c             |  12 ++--
>  src/time/clock_nanosleep.c           |  14 ++--
>  src/time/clock_settime.c             |  14 ++--
>  18 files changed, 217 insertions(+), 140 deletions(-)
> 
> diff --git a/src/ipc/semtimedop.c b/src/ipc/semtimedop.c
> index 1632e7b0..d9fe404d 100644
> --- a/src/ipc/semtimedop.c
> +++ b/src/ipc/semtimedop.c
> @@ -16,13 +16,17 @@
>  int semtimedop(int id, struct sembuf *buf, size_t n, const struct timespec *ts)
>  {
>  #ifdef SYS_semtimedop_time64
> +	static int use_semtimedop_time64 = 1;
>  	time_t s = ts ? ts->tv_sec : 0;
>  	long ns = ts ? ts->tv_nsec : 0;
>  	int r = -ENOSYS;
> -	if (NO_TIME32 || !IS32BIT(s))
> -		r = __syscall(SYS_semtimedop_time64, id, buf, n,
> -			ts ? ((long long[]){s, ns}) : 0);
> -	if (NO_TIME32 || r!=-ENOSYS) return __syscall_ret(r);
> +	if (use_semtimedop_time64) {
> +		if (NO_TIME32 || !IS32BIT(s))
> +			r = __syscall(SYS_semtimedop_time64, id, buf, n,
> +				ts ? ((long long[]){s, ns}) : 0);
> +		if (NO_TIME32 || r!=-ENOSYS) return __syscall_ret(r);
> +		else use_semtimedop_time64 = 0;
> +	}
>  	ts = ts ? (void *)(long[]){CLAMP(s), ns} : 0;
>  #endif
>  #if defined(SYS_ipc)

No change needed here. The time64 syscall is only made if ts does not
fit in 32 bits.

> diff --git a/src/linux/ppoll.c b/src/linux/ppoll.c
> index e614600a..939f3f1d 100644
> --- a/src/linux/ppoll.c
> +++ b/src/linux/ppoll.c
> @@ -12,13 +12,17 @@ int ppoll(struct pollfd *fds, nfds_t n, const struct timespec *to, const sigset_
>  	time_t s = to ? to->tv_sec : 0;
>  	long ns = to ? to->tv_nsec : 0;
>  #ifdef SYS_ppoll_time64
> +	static int use_ppoll_time64 = 1;
>  	int r = -ENOSYS;
> -	if (SYS_ppoll == SYS_ppoll_time64 || !IS32BIT(s))
> -		r = __syscall_cp(SYS_ppoll_time64, fds, n,
> -			to ? ((long long[]){s, ns}) : 0,
> -			mask, _NSIG/8);
> -	if (SYS_ppoll == SYS_ppoll_time64 || r != -ENOSYS)
> -		return __syscall_ret(r);
> +	if (use_ppoll_time64) {
> +		if (SYS_ppoll == SYS_ppoll_time64 || !IS32BIT(s))
> +			r = __syscall_cp(SYS_ppoll_time64, fds, n,
> +				to ? ((long long[]){s, ns}) : 0,
> +				mask, _NSIG/8);
> +		if (SYS_ppoll == SYS_ppoll_time64 || r != -ENOSYS)
> +			return __syscall_ret(r);
> +		else use_ppoll_time64 = 0;
> +	}
>  	s = CLAMP(s);
>  #endif
>  	return syscall_cp(SYS_ppoll, fds, n,

Same here. As this is a relative timeout, the time64 syscall will
essentially _never_ be used, unless a program spuriously uses a finite
more-than-68-year timeout in place of "forever".

> diff --git a/src/linux/timerfd.c b/src/linux/timerfd.c
> index 5bdfaf16..65bda29b 100644
> --- a/src/linux/timerfd.c
> +++ b/src/linux/timerfd.c
> @@ -14,13 +14,17 @@ int timerfd_settime(int fd, int flags, const struct itimerspec *new, struct itim
>  #ifdef SYS_timerfd_settime64
>  	time_t is = new->it_interval.tv_sec, vs = new->it_value.tv_sec;
>  	long ins = new->it_interval.tv_nsec, vns = new->it_value.tv_nsec;
> +	static int use_timerfd_settime64 = 1;
>  	int r = -ENOSYS;
> -	if (SYS_timerfd_settime == SYS_timerfd_settime64
> -	    || !IS32BIT(is) || !IS32BIT(vs) || (sizeof(time_t)>4 && old))
> -		r = __syscall(SYS_timerfd_settime64, fd, flags,
> -			((long long[]){is, ins, vs, vns}), old);
> -	if (SYS_timerfd_settime == SYS_timerfd_settime64 || r!=-ENOSYS)
> -		return __syscall_ret(r);
> +	if (use_timerfd_settime64) {
> +		if (SYS_timerfd_settime == SYS_timerfd_settime64
> +			|| !IS32BIT(is) || !IS32BIT(vs) || (sizeof(time_t)>4 && old))
> +			r = __syscall(SYS_timerfd_settime64, fd, flags,
> +				((long long[]){is, ins, vs, vns}), old);
> +		if (SYS_timerfd_settime == SYS_timerfd_settime64 || r!=-ENOSYS)
> +			return __syscall_ret(r);
> +		else use_timerfd_settime64 = 0;
> +	}
>  	if (!IS32BIT(is) || !IS32BIT(vs))
>  		return __syscall_ret(-ENOTSUP);
>  	long old32[4];

Same.

> @@ -40,11 +44,15 @@ int timerfd_settime(int fd, int flags, const struct itimerspec *new, struct itim
>  int timerfd_gettime(int fd, struct itimerspec *cur)
>  {
>  #ifdef SYS_timerfd_gettime64
> +	static int use_timerfd_gettime64 = 1;
>  	int r = -ENOSYS;
> -	if (sizeof(time_t) > 4)
> -		r = __syscall(SYS_timerfd_gettime64, fd, cur);
> -	if (SYS_timerfd_gettime == SYS_timerfd_gettime64 || r!=-ENOSYS)
> -		return __syscall_ret(r);
> +	if (use_timerfd_gettime64) {
> +		if (sizeof(time_t) > 4)
> +			r = __syscall(SYS_timerfd_gettime64, fd, cur);
> +		if (SYS_timerfd_gettime == SYS_timerfd_gettime64 || r!=-ENOSYS)
> +			return __syscall_ret(r);
> +		else use_timerfd_gettime64 = 0;
> +	}
>  	long cur32[4];
>  	r = __syscall(SYS_timerfd_gettime, fd, cur32);
>  	if (!r) {

This one is actually needed for your purposes, since it's querying a
time *from* the kernel and there's no a priori way to know if it will
fit in 32 bits.

> diff --git a/src/misc/getrusage.c b/src/misc/getrusage.c
> index 8e03e2e3..47d87981 100644
> --- a/src/misc/getrusage.c
> +++ b/src/misc/getrusage.c
> @@ -7,19 +7,23 @@ int getrusage(int who, struct rusage *ru)
>  {
>  	int r;
>  #ifdef SYS_getrusage_time64
> -	long long kru64[18];
> -	r = __syscall(SYS_getrusage_time64, who, kru64);
> -	if (!r) {
> -		ru->ru_utime = (struct timeval)
> -			{ .tv_sec = kru64[0], .tv_usec = kru64[1] };
> -		ru->ru_stime = (struct timeval)
> -			{ .tv_sec = kru64[2], .tv_usec = kru64[3] };
> -		char *slots = (char *)&ru->ru_maxrss;
> -		for (int i=0; i<14; i++)
> -			*(long *)(slots + i*sizeof(long)) = kru64[4+i];
> +	static int use_getrusage_time64 = 1;
> +	if (use_getrusage_time64) {
> +		long long kru64[18];
> +		r = __syscall(SYS_getrusage_time64, who, kru64);
> +		if (!r) {
> +			ru->ru_utime = (struct timeval)
> +				{ .tv_sec = kru64[0], .tv_usec = kru64[1] };
> +			ru->ru_stime = (struct timeval)
> +				{ .tv_sec = kru64[2], .tv_usec = kru64[3] };
> +			char *slots = (char *)&ru->ru_maxrss;
> +			for (int i=0; i<14; i++)
> +				*(long *)(slots + i*sizeof(long)) = kru64[4+i];
> +		}
> +		if (SYS_getrusage_time64 == SYS_getrusage || r != -ENOSYS)
> +			return __syscall_ret(r);
> +		else use_getrusage_time64 = 0;
>  	}
> -	if (SYS_getrusage_time64 == SYS_getrusage || r != -ENOSYS)
> -		return __syscall_ret(r);
>  #endif
>  	char *dest = (char *)&ru->ru_maxrss - 4*sizeof(long);
>  	r = __syscall(SYS_getrusage, who, dest);

I don't think this time64 syscall even exits on archs with a time32
version, but I may be misremembering.

> diff --git a/src/mq/mq_timedreceive.c b/src/mq/mq_timedreceive.c
> index f41b6642..43c4fef6 100644
> --- a/src/mq/mq_timedreceive.c
> +++ b/src/mq/mq_timedreceive.c
> @@ -8,14 +8,18 @@
>  ssize_t mq_timedreceive(mqd_t mqd, char *restrict msg, size_t len, unsigned *restrict prio, const struct timespec *restrict at)
>  {
>  #ifdef SYS_mq_timedreceive_time64
> +	static int use_mq_timedreceive_time64 = 1;
>  	time_t s = at ? at->tv_sec : 0;
>  	long ns = at ? at->tv_nsec : 0;
>  	long r = -ENOSYS;
> -	if (SYS_mq_timedreceive == SYS_mq_timedreceive_time64 || !IS32BIT(s))
> -		r = __syscall_cp(SYS_mq_timedreceive_time64, mqd, msg, len, prio,
> -			at ? ((long long []){at->tv_sec, at->tv_nsec}) : 0);
> -	if (SYS_mq_timedreceive == SYS_mq_timedreceive_time64 || r != -ENOSYS)
> -		return __syscall_ret(r);
> +	if (use_mq_timedreceive_time64) {
> +		if (SYS_mq_timedreceive == SYS_mq_timedreceive_time64 || !IS32BIT(s))
> +			r = __syscall_cp(SYS_mq_timedreceive_time64, mqd, msg, len, prio,
> +				at ? ((long long []){at->tv_sec, at->tv_nsec}) : 0);
> +		if (SYS_mq_timedreceive == SYS_mq_timedreceive_time64 || r != -ENOSYS)
> +			return __syscall_ret(r);
> +		else use_mq_timedreceive_time64 = 0;
> +	}
>  	return syscall_cp(SYS_mq_timedreceive, mqd, msg, len, prio,
>  		at ? ((long[]){CLAMP(s), ns}) : 0);
>  #else

Also not needed, for above reason.

> diff --git a/src/mq/mq_timedsend.c b/src/mq/mq_timedsend.c
> index 56cfcbb8..77164093 100644
> --- a/src/mq/mq_timedsend.c
> +++ b/src/mq/mq_timedsend.c
> @@ -8,14 +8,18 @@
>  int mq_timedsend(mqd_t mqd, const char *msg, size_t len, unsigned prio, const struct timespec *at)
>  {
>  #ifdef SYS_mq_timedsend_time64
> +	static int use_mq_timedsend_time64 = 1;
>  	time_t s = at ? at->tv_sec : 0;
>  	long ns = at ? at->tv_nsec : 0;
>  	long r = -ENOSYS;
> -	if (SYS_mq_timedsend == SYS_mq_timedsend_time64 || !IS32BIT(s))
> -		r = __syscall_cp(SYS_mq_timedsend_time64, mqd, msg, len, prio,
> -			at ? ((long long []){at->tv_sec, at->tv_nsec}) : 0);
> -	if (SYS_mq_timedsend == SYS_mq_timedsend_time64 || r != -ENOSYS)
> -		return __syscall_ret(r);
> +	if (use_mq_timedsend_time64) {
> +		if (SYS_mq_timedsend == SYS_mq_timedsend_time64 || !IS32BIT(s))
> +			r = __syscall_cp(SYS_mq_timedsend_time64, mqd, msg, len, prio,
> +				at ? ((long long []){at->tv_sec, at->tv_nsec}) : 0);
> +		if (SYS_mq_timedsend == SYS_mq_timedsend_time64 || r != -ENOSYS)
> +			return __syscall_ret(r);
> +		else use_mq_timedsend_time64 = 0;
> +	}
>  	return syscall_cp(SYS_mq_timedsend, mqd, msg, len, prio,
>  		at ? ((long[]){CLAMP(s), ns}) : 0);
>  #else

Same.

> diff --git a/src/network/recvmmsg.c b/src/network/recvmmsg.c
> index 2978e2f6..ea603854 100644
> --- a/src/network/recvmmsg.c
> +++ b/src/network/recvmmsg.c
> @@ -19,12 +19,17 @@ int recvmmsg(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int fla
>  		mh->msg_hdr.__pad1 = mh->msg_hdr.__pad2 = 0;
>  #endif
>  #ifdef SYS_recvmmsg_time64
> +	static int use_recvmmsg_time64 = 1;
>  	time_t s = timeout ? timeout->tv_sec : 0;
>  	long ns = timeout ? timeout->tv_nsec : 0;
> -	int r = __syscall_cp(SYS_recvmmsg_time64, fd, msgvec, vlen, flags,
> -			timeout ? ((long long[]){s, ns}) : 0);
> -	if (SYS_recvmmsg == SYS_recvmmsg_time64 || r!=-ENOSYS)
> -		return __syscall_ret(r);
> +	int r;
> +	if (use_recvmmsg_time64) {
> +		r = __syscall_cp(SYS_recvmmsg_time64, fd, msgvec, vlen, flags,
> +				timeout ? ((long long[]){s, ns}) : 0);
> +		if (SYS_recvmmsg == SYS_recvmmsg_time64 || r!=-ENOSYS)
> +			return __syscall_ret(r);
> +		else use_recvmmsg_time64 = 0;
> +	}
>  	if (vlen > IOV_MAX) vlen = IOV_MAX;
>  	socklen_t csize[vlen];
>  	for (int i=0; i<vlen; i++) csize[i] = msgvec[i].msg_hdr.msg_controllen;

I don't recall why this one doesn't use the old syscall when the time
fits, so as written yoyr patch seems to be needed.

> diff --git a/src/select/pselect.c b/src/select/pselect.c
> index 54cfb291..ef221f14 100644
> --- a/src/select/pselect.c
> +++ b/src/select/pselect.c
> @@ -13,12 +13,16 @@ int pselect(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restric
>  	time_t s = ts ? ts->tv_sec : 0;
>  	long ns = ts ? ts->tv_nsec : 0;
>  #ifdef SYS_pselect6_time64
> +	static int use_pselect6_time64 = 1;
>  	int r = -ENOSYS;
> -	if (SYS_pselect6 == SYS_pselect6_time64 || !IS32BIT(s))
> -		r = __syscall_cp(SYS_pselect6_time64, n, rfds, wfds, efds,
> -			ts ? ((long long[]){s, ns}) : 0, data);
> -	if (SYS_pselect6 == SYS_pselect6_time64 || r!=-ENOSYS)
> -		return __syscall_ret(r);
> +	if (use_pselect6_time64) {
> +		if (SYS_pselect6 == SYS_pselect6_time64 || !IS32BIT(s))
> +			r = __syscall_cp(SYS_pselect6_time64, n, rfds, wfds, efds,
> +				ts ? ((long long[]){s, ns}) : 0, data);
> +		if (SYS_pselect6 == SYS_pselect6_time64 || r!=-ENOSYS)
> +			return __syscall_ret(r);
> +		else use_pselect6_time64 = 0;
> +	}
>  	s = CLAMP(s);
>  #endif
>  	return syscall_cp(SYS_pselect6, n, rfds, wfds, efds,

This shouldn't be needed for same reason as above.

> diff --git a/src/select/select.c b/src/select/select.c
> index 8a786884..810cf450 100644
> --- a/src/select/select.c
> +++ b/src/select/select.c
> @@ -26,13 +26,17 @@ int select(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict
>  	}
>  
>  #ifdef SYS_pselect6_time64
> +	static int use_pselect6_time64 = 1;
>  	int r = -ENOSYS;
> -	if (SYS_pselect6 == SYS_pselect6_time64 || !IS32BIT(s))
> -		r = __syscall_cp(SYS_pselect6_time64, n, rfds, wfds, efds,
> -			tv ? ((long long[]){s, ns}) : 0,
> -			((syscall_arg_t[]){ 0, _NSIG/8 }));
> -	if (SYS_pselect6 == SYS_pselect6_time64 || r!=-ENOSYS)
> -		return __syscall_ret(r);
> +	if (use_pselect6_time64) {
> +		if (SYS_pselect6 == SYS_pselect6_time64 || !IS32BIT(s))
> +			r = __syscall_cp(SYS_pselect6_time64, n, rfds, wfds, efds,
> +				tv ? ((long long[]){s, ns}) : 0,
> +				((syscall_arg_t[]){ 0, _NSIG/8 }));
> +		if (SYS_pselect6 == SYS_pselect6_time64 || r!=-ENOSYS)
> +			return __syscall_ret(r);
> +		else use_pselect6_time64 = 0;
> +	}
>  #endif
>  #ifdef SYS_select
>  	return syscall_cp(SYS_select, n, rfds, wfds, efds,

Same.

> diff --git a/src/signal/sigtimedwait.c b/src/signal/sigtimedwait.c
> index 1287174e..efc786db 100644
> --- a/src/signal/sigtimedwait.c
> +++ b/src/signal/sigtimedwait.c
> @@ -8,14 +8,18 @@
>  static int do_sigtimedwait(const sigset_t *restrict mask, siginfo_t *restrict si, const struct timespec *restrict ts)
>  {
>  #ifdef SYS_rt_sigtimedwait_time64
> +	static int use_rt_sigtimedwait_time64 = 1;
>  	time_t s = ts ? ts->tv_sec : 0;
>  	long ns = ts ? ts->tv_nsec : 0;
>  	int r = -ENOSYS;
> -	if (SYS_rt_sigtimedwait == SYS_rt_sigtimedwait_time64 || !IS32BIT(s))
> -		r = __syscall_cp(SYS_rt_sigtimedwait_time64, mask, si,
> -			ts ? ((long long[]){s, ns}) : 0, _NSIG/8);
> -	if (SYS_rt_sigtimedwait == SYS_rt_sigtimedwait_time64 || r!=-ENOSYS)
> -		return r;
> +	if (use_rt_sigtimedwait_time64) {
> +		if (SYS_rt_sigtimedwait == SYS_rt_sigtimedwait_time64 || !IS32BIT(s))
> +			r = __syscall_cp(SYS_rt_sigtimedwait_time64, mask, si,
> +				ts ? ((long long[]){s, ns}) : 0, _NSIG/8);
> +		if (SYS_rt_sigtimedwait == SYS_rt_sigtimedwait_time64 || r!=-ENOSYS)
> +			return r;
> +		else use_rt_sigtimedwait_time64 = 0;
> +	}
>  	return __syscall_cp(SYS_rt_sigtimedwait, mask, si,
>  		ts ? ((long[]){CLAMP(s), ns}) : 0, _NSIG/8);;
>  #else

Same.

> diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c
> index de165b5c..e8e8c866 100644
> --- a/src/stat/fstatat.c
> +++ b/src/stat/fstatat.c
> @@ -133,10 +133,14 @@ static int fstatat_kstat(int fd, const char *restrict path, struct stat *restric
>  
>  int fstatat(int fd, const char *restrict path, struct stat *restrict st, int flag)
>  {
> +	static int use_statx = 1;
>  	int ret;
> -	if (sizeof((struct kstat){0}.st_atime_sec) < sizeof(time_t)) {
> -		ret = fstatat_statx(fd, path, st, flag);
> -		if (ret!=-ENOSYS) return __syscall_ret(ret);
> +	if (use_statx) {
> +		if (sizeof((struct kstat){0}.st_atime_sec) < sizeof(time_t)) {
> +			ret = fstatat_statx(fd, path, st, flag);
> +			if (ret!=-ENOSYS) return __syscall_ret(ret);
> +			else use_statx = 0;
> +		}
>  	}
>  	ret = fstatat_kstat(fd, path, st, flag);
>  	return __syscall_ret(ret);

Indeed this case is needed because it's a "reading back time" one.

> diff --git a/src/stat/utimensat.c b/src/stat/utimensat.c
> index 730723a9..adde7e4e 100644
> --- a/src/stat/utimensat.c
> +++ b/src/stat/utimensat.c
> @@ -13,6 +13,7 @@ int utimensat(int fd, const char *path, const struct timespec times[2], int flag
>  	if (times && times[0].tv_nsec==UTIME_NOW && times[1].tv_nsec==UTIME_NOW)
>  		times = 0;
>  #ifdef SYS_utimensat_time64
> +	static int use_utimensat_time64 = 1;
>  	r = -ENOSYS;
>  	time_t s0=0, s1=0;
>  	long ns0=0, ns1=0;
> @@ -22,11 +23,14 @@ int utimensat(int fd, const char *path, const struct timespec times[2], int flag
>  		if (!NS_SPECIAL(ns0)) s0 = times[0].tv_sec;
>  		if (!NS_SPECIAL(ns1)) s1 = times[1].tv_sec;
>  	}
> -	if (SYS_utimensat == SYS_utimensat_time64 || !IS32BIT(s0) || !IS32BIT(s1))
> -		r = __syscall(SYS_utimensat_time64, fd, path, times ?
> -			((long long[]){s0, ns0, s1, ns1}) : 0, flags);
> -	if (SYS_utimensat == SYS_utimensat_time64 || r!=-ENOSYS)
> -		return __syscall_ret(r);
> +	if (use_utimensat_time64) {
> +		if (SYS_utimensat == SYS_utimensat_time64 || !IS32BIT(s0) || !IS32BIT(s1))
> +			r = __syscall(SYS_utimensat_time64, fd, path, times ?
> +				((long long[]){s0, ns0, s1, ns1}) : 0, flags);
> +		if (SYS_utimensat == SYS_utimensat_time64 || r!=-ENOSYS)
> +			return __syscall_ret(r);
> +		else use_utimensat_time64 = 0;
> +	}
>  	if (!IS32BIT(s0) || !IS32BIT(s1))
>  		return __syscall_ret(-ENOTSUP);
>  	r = __syscall(SYS_utimensat, fd, path,

Not needed.

> diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c
> index 666093be..2c417837 100644
> --- a/src/thread/__timedwait.c
> +++ b/src/thread/__timedwait.c
> @@ -12,13 +12,17 @@ static int __futex4_cp(volatile void *addr, int op, int val, const struct timesp
>  {
>  	int r;
>  #ifdef SYS_futex_time64
> +	static int use_futex_time64 = 1;
>  	time_t s = to ? to->tv_sec : 0;
>  	long ns = to ? to->tv_nsec : 0;
>  	r = -ENOSYS;
> -	if (SYS_futex == SYS_futex_time64 || !IS32BIT(s))
> -		r = __syscall_cp(SYS_futex_time64, addr, op, val,
> -			to ? ((long long[]){s, ns}) : 0);
> -	if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r;
> +	if (use_futex_time64) {
> +		if (SYS_futex == SYS_futex_time64 || !IS32BIT(s))
> +			r = __syscall_cp(SYS_futex_time64, addr, op, val,
> +				to ? ((long long[]){s, ns}) : 0);
> +		if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r;
> +		else use_futex_time64 = 0;
> +	}
>  	to = to ? (void *)(long[]){CLAMP(s), ns} : 0;
>  #endif
>  	r = __syscall_cp(SYS_futex, addr, op, val, to);

Not needed.

> diff --git a/src/thread/pthread_mutex_timedlock.c b/src/thread/pthread_mutex_timedlock.c
> index 9279fc54..dcf15945 100644
> --- a/src/thread/pthread_mutex_timedlock.c
> +++ b/src/thread/pthread_mutex_timedlock.c
> @@ -6,13 +6,17 @@
>  static int __futex4(volatile void *addr, int op, int val, const struct timespec *to)
>  {
>  #ifdef SYS_futex_time64
> +	static int use_futex_time64 = 1;
>  	time_t s = to ? to->tv_sec : 0;
>  	long ns = to ? to->tv_nsec : 0;
>  	int r = -ENOSYS;
> -	if (SYS_futex == SYS_futex_time64 || !IS32BIT(s))
> -		r = __syscall(SYS_futex_time64, addr, op, val,
> -			to ? ((long long[]){s, ns}) : 0);
> -	if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r;
> +	if (use_futex_time64) {
> +		if (SYS_futex == SYS_futex_time64 || !IS32BIT(s))
> +			r = __syscall(SYS_futex_time64, addr, op, val,
> +				to ? ((long long[]){s, ns}) : 0);
> +		if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r;
> +		else use_futex_time64 = 0;
> +	}
>  	to = to ? (void *)(long[]){CLAMP(s), ns} : 0;
>  #endif
>  	return __syscall(SYS_futex, addr, op, val, to);

Not needed.

> diff --git a/src/time/clock_gettime.c b/src/time/clock_gettime.c
> index 3e1d0975..736fde8b 100644
> --- a/src/time/clock_gettime.c
> +++ b/src/time/clock_gettime.c
> @@ -73,11 +73,15 @@ int __clock_gettime(clockid_t clk, struct timespec *ts)
>  #endif
>  
>  #ifdef SYS_clock_gettime64
> +	static int use_clock_gettime64 = 1;
>  	r = -ENOSYS;
> -	if (sizeof(time_t) > 4)
> -		r = __syscall(SYS_clock_gettime64, clk, ts);
> -	if (SYS_clock_gettime == SYS_clock_gettime64 || r!=-ENOSYS)
> -		return __syscall_ret(r);
> +	if (use_clock_gettime64) {
> +		if (sizeof(time_t) > 4)
> +			r = __syscall(SYS_clock_gettime64, clk, ts);
> +		if (SYS_clock_gettime == SYS_clock_gettime64 || r!=-ENOSYS)
> +			return __syscall_ret(r);
> +		else use_clock_gettime64 = 0;
> +	}
>  	long ts32[2];
>  	r = __syscall(SYS_clock_gettime, clk, ts32);
>  	if (r==-ENOSYS && clk==CLOCK_REALTIME) {

Needed; it's reading back time.

> diff --git a/src/time/clock_nanosleep.c b/src/time/clock_nanosleep.c
> index e195499c..bbb657b6 100644
> --- a/src/time/clock_nanosleep.c
> +++ b/src/time/clock_nanosleep.c
> @@ -9,14 +9,18 @@ int __clock_nanosleep(clockid_t clk, int flags, const struct timespec *req, stru
>  {
>  	if (clk == CLOCK_THREAD_CPUTIME_ID) return EINVAL;
>  #ifdef SYS_clock_nanosleep_time64
> +	static int use_clock_nanosleep_time64 = 1;
>  	time_t s = req->tv_sec;
>  	long ns = req->tv_nsec;
>  	int r = -ENOSYS;
> -	if (SYS_clock_nanosleep == SYS_clock_nanosleep_time64 || !IS32BIT(s))
> -		r = __syscall_cp(SYS_clock_nanosleep_time64, clk, flags,
> -			((long long[]){s, ns}), rem);
> -	if (SYS_clock_nanosleep == SYS_clock_nanosleep_time64 || r!=-ENOSYS)
> -		return -r;
> +	if (use_clock_nanosleep_time64) {
> +		if (SYS_clock_nanosleep == SYS_clock_nanosleep_time64 || !IS32BIT(s))
> +			r = __syscall_cp(SYS_clock_nanosleep_time64, clk, flags,
> +				((long long[]){s, ns}), rem);
> +		if (SYS_clock_nanosleep == SYS_clock_nanosleep_time64 || r!=-ENOSYS)
> +			return -r;
> +		else use_clock_nanosleep_time64 = 0;
> +	}
>  	long long extra = s - CLAMP(s);
>  	long ts32[2] = { CLAMP(s), ns };
>  	if (clk == CLOCK_REALTIME && !flags)

Not needed.

> diff --git a/src/time/clock_settime.c b/src/time/clock_settime.c
> index 1004ed15..aa137fa7 100644
> --- a/src/time/clock_settime.c
> +++ b/src/time/clock_settime.c
> @@ -7,14 +7,18 @@
>  int clock_settime(clockid_t clk, const struct timespec *ts)
>  {
>  #ifdef SYS_clock_settime64
> +	static int use_clock_settime64 = 1;
>  	time_t s = ts->tv_sec;
>  	long ns = ts->tv_nsec;
>  	int r = -ENOSYS;
> -	if (SYS_clock_settime == SYS_clock_settime64 || !IS32BIT(s))
> -		r = __syscall(SYS_clock_settime64, clk,
> -			((long long[]){s, ns}));
> -	if (SYS_clock_settime == SYS_clock_settime64 || r!=-ENOSYS)
> -		return __syscall_ret(r);
> +	if (use_clock_settime64) {
> +		if (SYS_clock_settime == SYS_clock_settime64 || !IS32BIT(s))
> +			r = __syscall(SYS_clock_settime64, clk,
> +				((long long[]){s, ns}));
> +		if (SYS_clock_settime == SYS_clock_settime64 || r!=-ENOSYS)
> +			return __syscall_ret(r);
> +		else use_clock_settime64 = 0;
> +	}
>  	if (!IS32BIT(s))
>  		return __syscall_ret(-ENOTSUP);
>  	return syscall(SYS_clock_settime, clk, ((long[]){s, ns}));
> -- 
> 2.20.1
> 


Not needed.

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.