Do not use struct l_timespec without conversion. While here move

args->timeout handling before acquiring the futex key at FUTEX_WAIT path.

Differential Revision:	https://reviews.freebsd.org/D1520
Reviewed by:	trasz
This commit is contained in:
Dmitry Chagin 2015-05-24 17:29:18 +00:00
parent 7e947ccc81
commit 680982281b
4 changed files with 54 additions and 48 deletions

View File

@ -65,6 +65,7 @@ __KERNEL_RCSID(1, "$NetBSD: linux_futex.c,v 1.7 2006/07/24 19:01:49 manu Exp $")
#include <compat/linux/linux_dtrace.h>
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_futex.h>
#include <compat/linux/linux_timer.h>
#include <compat/linux/linux_util.h>
/* DTrace init */
@ -669,7 +670,8 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
struct linux_pemuldata *pem;
struct waiting_proc *wp;
struct futex *f, *f2;
struct l_timespec timeout;
struct l_timespec ltimeout;
struct timespec timeout;
struct timeval utv, ctv;
int timeout_hz;
int error;
@ -713,6 +715,38 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
LINUX_CTR3(sys_futex, "WAIT uaddr %p val 0x%x bitset 0x%x",
args->uaddr, args->val, args->val3);
if (args->timeout != NULL) {
error = copyin(args->timeout, &ltimeout, sizeof(ltimeout));
if (error) {
LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error,
error);
LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
return (error);
}
error = linux_to_native_timespec(&timeout, &ltimeout);
if (error)
return (error);
TIMESPEC_TO_TIMEVAL(&utv, &timeout);
error = itimerfix(&utv);
if (error) {
LIN_SDT_PROBE1(futex, linux_sys_futex, itimerfix_error,
error);
LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
return (error);
}
if (clockrt) {
microtime(&ctv);
timevalsub(&utv, &ctv);
} else if (args->op == LINUX_FUTEX_WAIT_BITSET) {
microuptime(&ctv);
timevalsub(&utv, &ctv);
}
if (utv.tv_sec < 0)
timevalclear(&utv);
timeout_hz = tvtohz(&utv);
} else
timeout_hz = 0;
error = futex_get(args->uaddr, &wp, &f,
flags | FUTEX_CREATE_WP);
if (error) {
@ -745,37 +779,6 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
return (EWOULDBLOCK);
}
if (args->timeout != NULL) {
error = copyin(args->timeout, &timeout, sizeof(timeout));
if (error) {
LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error,
error);
LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
futex_put(f, wp);
return (error);
}
TIMESPEC_TO_TIMEVAL(&utv, &timeout);
error = itimerfix(&utv);
if (error) {
LIN_SDT_PROBE1(futex, linux_sys_futex, itimerfix_error,
error);
LIN_SDT_PROBE1(futex, linux_sys_futex, return, error);
futex_put(f, wp);
return (error);
}
if (clockrt) {
microtime(&ctv);
timevalsub(&utv, &ctv);
} else if (args->op == LINUX_FUTEX_WAIT_BITSET) {
microuptime(&ctv);
timevalsub(&utv, &ctv);
}
if (utv.tv_sec < 0)
timevalclear(&utv);
timeout_hz = tvtohz(&utv);
} else
timeout_hz = 0;
error = futex_wait(f, wp, timeout_hz, args->val3);
break;

View File

@ -88,6 +88,7 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_file.h>
#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_signal.h>
#include <compat/linux/linux_timer.h>
#include <compat/linux/linux_util.h>
#include <compat/linux/linux_sysproto.h>
#include <compat/linux/linux_emul.h>
@ -2168,8 +2169,9 @@ linux_pselect6(struct thread *td, struct linux_pselect6_args *args)
error = copyin(args->tsp, &lts, sizeof(lts));
if (error != 0)
return (error);
uts.tv_sec = lts.tv_sec;
uts.tv_nsec = lts.tv_nsec;
error = linux_to_native_timespec(&uts, &lts);
if (error != 0)
return (error);
TIMESPEC_TO_TIMEVAL(&utv, &uts);
if (itimerfix(&utv))
@ -2201,8 +2203,8 @@ linux_pselect6(struct thread *td, struct linux_pselect6_args *args)
timevalclear(&utv);
TIMEVAL_TO_TIMESPEC(&utv, &uts);
lts.tv_sec = uts.tv_sec;
lts.tv_nsec = uts.tv_nsec;
native_to_linux_timespec(&lts, &uts);
error = copyout(&lts, args->tsp, sizeof(lts));
}
@ -2234,8 +2236,9 @@ linux_ppoll(struct thread *td, struct linux_ppoll_args *args)
error = copyin(args->tsp, &lts, sizeof(lts));
if (error)
return (error);
uts.tv_sec = lts.tv_sec;
uts.tv_nsec = lts.tv_nsec;
error = linux_to_native_timespec(&uts, &lts);
if (error != 0)
return (error);
nanotime(&ts0);
tsp = &uts;
@ -2254,8 +2257,7 @@ linux_ppoll(struct thread *td, struct linux_ppoll_args *args)
} else
timespecclear(&uts);
lts.tv_sec = uts.tv_sec;
lts.tv_nsec = uts.tv_nsec;
native_to_linux_timespec(&lts, &uts);
error = copyout(&lts, args->tsp, sizeof(lts));
}
@ -2343,8 +2345,7 @@ linux_sched_rr_get_interval(struct thread *td,
PROC_UNLOCK(tdt->td_proc);
if (error != 0)
return (error);
lts.tv_sec = ts.tv_sec;
lts.tv_nsec = ts.tv_nsec;
native_to_linux_timespec(&lts, &ts);
return (copyout(&lts, uap->interval, sizeof(lts)));
}

View File

@ -119,13 +119,10 @@ LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_flags, "int");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_clockid, "int");
LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, return, "int");
static void native_to_linux_timespec(struct l_timespec *,
struct timespec *);
static int linux_to_native_timespec(struct timespec *,
struct l_timespec *);
static int linux_to_native_clockid(clockid_t *, clockid_t);
static void
void
native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp)
{
@ -137,7 +134,7 @@ native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp)
LIN_SDT_PROBE0(time, native_to_linux_timespec, return);
}
static int
int
linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp)
{

View File

@ -111,4 +111,9 @@ struct l_itimerspec {
struct l_timespec it_value;
};
void native_to_linux_timespec(struct l_timespec *,
struct timespec *);
int linux_to_native_timespec(struct timespec *,
struct l_timespec *);
#endif /* _LINUX_TIMER_H */