Module: xenomai-3 Branch: next Commit: ba9af05589506e2499c7aea8bd875784e472b56a URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=ba9af05589506e2499c7aea8bd875784e472b56a
Author: Philippe Gerum <r...@xenomai.org> Date: Thu Jan 25 16:06:29 2018 +0100 cobalt/rtdm: add sendmmsg(), recvmmsg() syscalls --- include/cobalt/kernel/compat.h | 6 ++ include/cobalt/kernel/rtdm/fd.h | 11 +++ include/cobalt/uapi/syscall.h | 2 + kernel/cobalt/posix/compat.c | 24 ++++++ kernel/cobalt/posix/io.c | 43 ++++++++++ kernel/cobalt/posix/io.h | 8 ++ kernel/cobalt/posix/syscall32.c | 44 ++++++++++ kernel/cobalt/posix/syscall32.h | 9 ++ kernel/cobalt/rtdm/Makefile | 2 +- kernel/cobalt/rtdm/fd.c | 172 +++++++++++++++++++++++++++++++++++++ kernel/cobalt/trace/cobalt-rtdm.h | 28 ++++++ 11 files changed, 348 insertions(+), 1 deletion(-) diff --git a/include/cobalt/kernel/compat.h b/include/cobalt/kernel/compat.h index 43378d9..bb6c754 100644 --- a/include/cobalt/kernel/compat.h +++ b/include/cobalt/kernel/compat.h @@ -139,9 +139,15 @@ int sys32_put_siginfo(void __user *u_si, const struct siginfo *si, int sys32_get_msghdr(struct user_msghdr *msg, const struct compat_msghdr __user *u_cmsg); +int sys32_get_mmsghdr(struct mmsghdr *mmsg, + const struct compat_mmsghdr __user *u_cmmsg); + int sys32_put_msghdr(struct compat_msghdr __user *u_cmsg, const struct user_msghdr *msg); +int sys32_put_mmsghdr(struct compat_mmsghdr __user *u_cmmsg, + const struct mmsghdr *mmsg); + int sys32_get_iovec(struct iovec *iov, const struct compat_iovec __user *ciov, int ciovlen); diff --git a/include/cobalt/kernel/rtdm/fd.h b/include/cobalt/kernel/rtdm/fd.h index e504c0c..58d3c4a 100644 --- a/include/cobalt/kernel/rtdm/fd.h +++ b/include/cobalt/kernel/rtdm/fd.h @@ -367,9 +367,20 @@ int rtdm_fd_close(int ufd, unsigned int magic); ssize_t rtdm_fd_recvmsg(int ufd, struct user_msghdr *msg, int flags); +int __rtdm_fd_recvmmsg(int ufd, void __user *u_msgvec, unsigned int vlen, + unsigned int flags, void __user *u_timeout, + int (*get_mmsg)(struct mmsghdr *mmsg, void __user *u_mmsg), + int (*put_mmsg)(void __user **u_mmsg_p, const struct mmsghdr *mmsg), + int (*get_timespec)(struct timespec *ts, const void __user *u_ts)); + ssize_t rtdm_fd_sendmsg(int ufd, const struct user_msghdr *msg, int flags); +int __rtdm_fd_sendmmsg(int ufd, void __user *u_msgvec, unsigned int vlen, + unsigned int flags, + int (*get_mmsg)(struct mmsghdr *mmsg, void __user *u_mmsg), + int (*put_mmsg)(void __user **u_mmsg_p, const struct mmsghdr *mmsg)); + int rtdm_fd_mmap(int ufd, struct _rtdm_mmap_request *rma, void **u_addrp); diff --git a/include/cobalt/uapi/syscall.h b/include/cobalt/uapi/syscall.h index cd7e820..d246f0b 100644 --- a/include/cobalt/uapi/syscall.h +++ b/include/cobalt/uapi/syscall.h @@ -118,6 +118,8 @@ #define sc_cobalt_serialdbg 95 #define sc_cobalt_extend 96 #define sc_cobalt_ftrace_puts 97 +#define sc_cobalt_recvmmsg 98 +#define sc_cobalt_sendmmsg 99 #define __NR_COBALT_SYSCALLS 128 /* Power of 2 */ diff --git a/kernel/cobalt/posix/compat.c b/kernel/cobalt/posix/compat.c index 962465a..3921510 100644 --- a/kernel/cobalt/posix/compat.c +++ b/kernel/cobalt/posix/compat.c @@ -359,6 +359,18 @@ int sys32_get_msghdr(struct user_msghdr *msg, } EXPORT_SYMBOL_GPL(sys32_get_msghdr); +int sys32_get_mmsghdr(struct mmsghdr *mmsg, + const struct compat_mmsghdr __user *u_cmmsg) +{ + if (u_cmmsg == NULL || + !access_rok(u_cmmsg, sizeof(*u_cmmsg)) || + __xn_get_user(mmsg->msg_len, &u_cmmsg->msg_len)) + return -EFAULT; + + return sys32_get_msghdr(&mmsg->msg_hdr, &u_cmmsg->msg_hdr); +} +EXPORT_SYMBOL_GPL(sys32_get_mmsghdr); + int sys32_put_msghdr(struct compat_msghdr __user *u_cmsg, const struct user_msghdr *msg) { @@ -377,6 +389,18 @@ int sys32_put_msghdr(struct compat_msghdr __user *u_cmsg, } EXPORT_SYMBOL_GPL(sys32_put_msghdr); +int sys32_put_mmsghdr(struct compat_mmsghdr __user *u_cmmsg, + const struct mmsghdr *mmsg) +{ + if (u_cmmsg == NULL || + !access_wok(u_cmmsg, sizeof(*u_cmmsg)) || + __xn_put_user(mmsg->msg_len, &u_cmmsg->msg_len)) + return -EFAULT; + + return sys32_put_msghdr(&u_cmmsg->msg_hdr, &mmsg->msg_hdr); +} +EXPORT_SYMBOL_GPL(sys32_put_mmsghdr); + int sys32_get_iovec(struct iovec *iov, const struct compat_iovec __user *u_ciov, int ciovlen) diff --git a/kernel/cobalt/posix/io.c b/kernel/cobalt/posix/io.c index ece7877..ef4a0fe 100644 --- a/kernel/cobalt/posix/io.c +++ b/kernel/cobalt/posix/io.c @@ -93,6 +93,33 @@ COBALT_SYSCALL(recvmsg, handover, return cobalt_copy_to_user(umsg, &m, sizeof(*umsg)) ?: ret; } +static int get_timespec(struct timespec *ts, + const void __user *u_ts) +{ + return cobalt_copy_from_user(ts, u_ts, sizeof(*ts)); +} + +static int get_mmsg(struct mmsghdr *mmsg, void __user *u_mmsg) +{ + return cobalt_copy_from_user(mmsg, u_mmsg, sizeof(*mmsg)); +} + +static int put_mmsg(void __user **u_mmsg_p, const struct mmsghdr *mmsg) +{ + struct mmsghdr __user **p = (struct mmsghdr **)u_mmsg_p, + *q __user = (*p)++; + + return cobalt_copy_to_user(q, mmsg, sizeof(*q)); +} + +COBALT_SYSCALL(recvmmsg, primary, + (int fd, struct mmsghdr __user *u_msgvec, unsigned int vlen, + unsigned int flags, struct timespec *u_timeout)) +{ + return __rtdm_fd_recvmmsg(fd, u_msgvec, vlen, flags, u_timeout, + get_mmsg, put_mmsg, get_timespec); +} + COBALT_SYSCALL(sendmsg, handover, (int fd, struct user_msghdr __user *umsg, int flags)) { @@ -104,6 +131,22 @@ COBALT_SYSCALL(sendmsg, handover, return ret ?: rtdm_fd_sendmsg(fd, &m, flags); } +static int put_mmsglen(void __user **u_mmsg_p, const struct mmsghdr *mmsg) +{ + struct mmsghdr __user **p = (struct mmsghdr **)u_mmsg_p, + *q __user = (*p)++; + + return __xn_put_user(mmsg->msg_len, &q->msg_len); +} + +COBALT_SYSCALL(sendmmsg, primary, + (int fd, struct mmsghdr __user *u_msgvec, + unsigned int vlen, unsigned int flags)) +{ + return __rtdm_fd_sendmmsg(fd, u_msgvec, vlen, flags, + get_mmsg, put_mmsglen); +} + COBALT_SYSCALL(mmap, lostage, (int fd, struct _rtdm_mmap_request __user *u_rma, void __user **u_addrp)) diff --git a/kernel/cobalt/posix/io.h b/kernel/cobalt/posix/io.h index b2db702..647f7f3 100644 --- a/kernel/cobalt/posix/io.h +++ b/kernel/cobalt/posix/io.h @@ -51,9 +51,17 @@ COBALT_SYSCALL_DECL(write, COBALT_SYSCALL_DECL(recvmsg, (int fd, struct user_msghdr __user *umsg, int flags)); +COBALT_SYSCALL_DECL(recvmmsg, + (int fd, struct mmsghdr __user *u_msgvec, unsigned int vlen, + unsigned int flags, struct timespec *u_timeout)); + COBALT_SYSCALL_DECL(sendmsg, (int fd, struct user_msghdr __user *umsg, int flags)); +COBALT_SYSCALL_DECL(sendmmsg, + (int fd, struct mmsghdr __user *u_msgvec, + unsigned int vlen, unsigned int flags)); + COBALT_SYSCALL_DECL(mmap, (int fd, struct _rtdm_mmap_request __user *u_rma, void __user * __user *u_addrp)); diff --git a/kernel/cobalt/posix/syscall32.c b/kernel/cobalt/posix/syscall32.c index e79173e..93e5077 100644 --- a/kernel/cobalt/posix/syscall32.c +++ b/kernel/cobalt/posix/syscall32.c @@ -784,6 +784,34 @@ COBALT_SYSCALL32emu(recvmsg, handover, return sys32_put_msghdr(umsg, &m) ?: ret; } +static int get_timespec32(struct timespec *ts, + const void __user *u_ts) +{ + return sys32_get_timespec(ts, u_ts); +} + +static int get_mmsg32(struct mmsghdr *mmsg, void __user *u_mmsg) +{ + return sys32_get_mmsghdr(mmsg, u_mmsg); +} + +static int put_mmsg32(void __user **u_mmsg_p, const struct mmsghdr *mmsg) +{ + struct compat_mmsghdr __user **p = (struct compat_mmsghdr **)u_mmsg_p, + *q __user = (*p)++; + + return sys32_put_mmsghdr(q, mmsg); +} + +COBALT_SYSCALL32emu(recvmmsg, primary, + (int ufd, struct compat_mmsghdr __user *u_msgvec, unsigned int vlen, + unsigned int flags, struct compat_timespec *u_timeout)) +{ + return __rtdm_fd_recvmmsg(ufd, u_msgvec, vlen, flags, u_timeout, + get_mmsg32, put_mmsg32, + get_timespec32); +} + COBALT_SYSCALL32emu(sendmsg, handover, (int fd, struct compat_msghdr __user *umsg, int flags)) { @@ -795,6 +823,22 @@ COBALT_SYSCALL32emu(sendmsg, handover, return ret ?: rtdm_fd_sendmsg(fd, &m, flags); } +static int put_mmsglen32(void __user **u_mmsg_p, const struct mmsghdr *mmsg) +{ + struct compat_mmsghdr __user **p = (struct compat_mmsghdr **)u_mmsg_p, + *q __user = (*p)++; + + return __xn_put_user(mmsg->msg_len, &q->msg_len); +} + +COBALT_SYSCALL32emu(sendmmsg, primary, + (int fd, struct compat_mmsghdr __user *u_msgvec, unsigned int vlen, + unsigned int flags)) +{ + return __rtdm_fd_sendmmsg(fd, u_msgvec, vlen, flags, + get_mmsg32, put_mmsglen32); +} + COBALT_SYSCALL32emu(mmap, lostage, (int fd, struct compat_rtdm_mmap_request __user *u_crma, compat_uptr_t __user *u_caddrp)) diff --git a/kernel/cobalt/posix/syscall32.h b/kernel/cobalt/posix/syscall32.h index 64f0958..730568c 100644 --- a/kernel/cobalt/posix/syscall32.h +++ b/kernel/cobalt/posix/syscall32.h @@ -190,10 +190,19 @@ COBALT_SYSCALL32emu_DECL(recvmsg, (int fd, struct compat_msghdr __user *umsg, int flags)); +COBALT_SYSCALL32emu_DECL(recvmmsg, + (int fd, struct compat_mmsghdr __user *u_msgvec, + unsigned int vlen, + unsigned int flags, struct compat_timespec *u_timeout)); + COBALT_SYSCALL32emu_DECL(sendmsg, (int fd, struct compat_msghdr __user *umsg, int flags)); +COBALT_SYSCALL32emu_DECL(sendmmsg, + (int fd, struct compat_mmsghdr __user *u_msgvec, unsigned int vlen, + unsigned int flags)); + COBALT_SYSCALL32emu_DECL(mmap, (int fd, struct compat_rtdm_mmap_request __user *u_rma, diff --git a/kernel/cobalt/rtdm/Makefile b/kernel/cobalt/rtdm/Makefile index ce215fe..e10568c 100644 --- a/kernel/cobalt/rtdm/Makefile +++ b/kernel/cobalt/rtdm/Makefile @@ -7,4 +7,4 @@ xenomai-y := core.o \ fd.o \ wrappers.o -ccflags-y += -I$(src)/.. +ccflags-y += -I$(src)/.. -Ikernel diff --git a/kernel/cobalt/rtdm/fd.c b/kernel/cobalt/rtdm/fd.c index b97e917..459b22b 100644 --- a/kernel/cobalt/rtdm/fd.c +++ b/kernel/cobalt/rtdm/fd.c @@ -33,6 +33,7 @@ #include "internal.h" #include "posix/process.h" #include "posix/syscall.h" +#include "posix/clock.h" #define RTDM_SETFL_MASK (O_NONBLOCK) @@ -583,6 +584,121 @@ out: } EXPORT_SYMBOL_GPL(rtdm_fd_recvmsg); +struct cobalt_recvmmsg_timer { + struct xntimer timer; + struct xnthread *waiter; +}; + +static void recvmmsg_timeout_handler(struct xntimer *timer) +{ + struct cobalt_recvmmsg_timer *rq; + + rq = container_of(timer, struct cobalt_recvmmsg_timer, timer); + xnthread_set_info(rq->waiter, XNTIMEO); + xnthread_resume(rq->waiter, XNDELAY); +} + +int __rtdm_fd_recvmmsg(int ufd, void __user *u_msgvec, unsigned int vlen, + unsigned int flags, void __user *u_timeout, + int (*get_mmsg)(struct mmsghdr *mmsg, void __user *u_mmsg), + int (*put_mmsg)(void __user **u_mmsg_p, const struct mmsghdr *mmsg), + int (*get_timespec)(struct timespec *ts, const void __user *u_ts)) +{ + struct cobalt_recvmmsg_timer rq; + xntmode_t tmode = XN_RELATIVE; + struct timespec ts = { 0 }; + int ret, datagrams = 0; + xnticks_t timeout = 0; + struct mmsghdr mmsg; + struct rtdm_fd *fd; + void __user *u_p; + ssize_t len; + spl_t s; + + if (vlen == 0) + return 0; + + fd = rtdm_fd_get(ufd, 0); + if (IS_ERR(fd)) { + ret = PTR_ERR(fd); + goto out; + } + + set_compat_bit(fd); + + trace_cobalt_fd_recvmmsg(current, fd, ufd, flags); + + if (u_timeout) { + ret = get_timespec(&ts, u_timeout); + if (ret) + goto fail; + + if ((unsigned long)ts.tv_nsec >= ONE_BILLION) { + ret = -EINVAL; + goto fail; + } + + tmode = XN_ABSOLUTE; + timeout = ts2ns(&ts); + if (timeout == 0) + flags |= MSG_DONTWAIT; + else { + timeout += xnclock_read_monotonic(&nkclock); + rq.waiter = xnthread_current(); + xntimer_init(&rq.timer, &nkclock, + recvmmsg_timeout_handler, + NULL, XNTIMER_KGRAVITY); + xnlock_get_irqsave(&nklock, s); + ret = xntimer_start(&rq.timer, timeout, + XN_INFINITE, tmode); + xnlock_put_irqrestore(&nklock, s); + } + } + + if (fd->oflags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + + for (u_p = u_msgvec; vlen > 0; vlen--) { + ret = get_mmsg(&mmsg, u_p); + if (ret) + break; + len = fd->ops->recvmsg_rt(fd, &mmsg.msg_hdr, flags); + if (len < 0) { + ret = len; + break; + } + mmsg.msg_len = (unsigned int)len; + ret = put_mmsg(&u_p, &mmsg); + if (ret) + break; + datagrams++; + /* OOB data requires immediate handling. */ + if (mmsg.msg_hdr.msg_flags & MSG_OOB) + break; + if (flags & MSG_WAITFORONE) + flags |= MSG_DONTWAIT; + } + + if (timeout) { + xnlock_get_irqsave(&nklock, s); + xntimer_destroy(&rq.timer); + xnlock_put_irqrestore(&nklock, s); + } + + if (datagrams > 0 && + (ret == 0 || ret == -ETIMEDOUT || ret == -EWOULDBLOCK)) { + /* NOTE: SO_ERROR should be honored for other errors. */ + rtdm_fd_put(fd); + return datagrams; + } +fail: + rtdm_fd_put(fd); +out: + trace_cobalt_fd_recvmmsg_status(current, fd, ufd, ret); + + return ret; +} + ssize_t rtdm_fd_sendmsg(int ufd, const struct user_msghdr *msg, int flags) { struct rtdm_fd *fd; @@ -618,6 +734,62 @@ out: } EXPORT_SYMBOL_GPL(rtdm_fd_sendmsg); +int __rtdm_fd_sendmmsg(int ufd, void __user *u_msgvec, unsigned int vlen, + unsigned int flags, + int (*get_mmsg)(struct mmsghdr *mmsg, void __user *u_mmsg), + int (*put_mmsg)(void __user **u_mmsg_p, const struct mmsghdr *mmsg)) +{ + int ret, datagrams = 0; + struct mmsghdr mmsg; + struct rtdm_fd *fd; + void __user *u_p; + ssize_t len; + + if (vlen == 0) + return 0; + + fd = rtdm_fd_get(ufd, 0); + if (IS_ERR(fd)) { + ret = PTR_ERR(fd); + goto out; + } + + set_compat_bit(fd); + + trace_cobalt_fd_sendmmsg(current, fd, ufd, flags); + + if (fd->oflags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + + for (u_p = u_msgvec; vlen > 0; vlen--) { + ret = get_mmsg(&mmsg, u_p); + if (ret) + break; + len = fd->ops->sendmsg_rt(fd, &mmsg.msg_hdr, flags); + if (len < 0) { + ret = len; + break; + } + mmsg.msg_len = (unsigned int)len; + ret = put_mmsg(&u_p, &mmsg); + if (ret) + break; + datagrams++; + } + + if (datagrams > 0 && (ret == 0 || ret == -EWOULDBLOCK)) { + /* NOTE: SO_ERROR should be honored for other errors. */ + rtdm_fd_put(fd); + return datagrams; + } + + rtdm_fd_put(fd); +out: + trace_cobalt_fd_sendmmsg_status(current, fd, ufd, ret); + + return ret; +} + static void __fd_close(struct cobalt_ppd *p, struct rtdm_fd_index *idx, spl_t s) { diff --git a/kernel/cobalt/trace/cobalt-rtdm.h b/kernel/cobalt/trace/cobalt-rtdm.h index 6634cd6..91b6390 100644 --- a/kernel/cobalt/trace/cobalt-rtdm.h +++ b/kernel/cobalt/trace/cobalt-rtdm.h @@ -268,6 +268,13 @@ DEFINE_EVENT(fd_request, cobalt_fd_sendmsg, TP_ARGS(task, fd, ufd, flags) ); +DEFINE_EVENT(fd_request, cobalt_fd_sendmmsg, + TP_PROTO(struct task_struct *task, + struct rtdm_fd *fd, int ufd, + unsigned long flags), + TP_ARGS(task, fd, ufd, flags) +); + DEFINE_EVENT(fd_request, cobalt_fd_recvmsg, TP_PROTO(struct task_struct *task, struct rtdm_fd *fd, int ufd, @@ -275,6 +282,13 @@ DEFINE_EVENT(fd_request, cobalt_fd_recvmsg, TP_ARGS(task, fd, ufd, flags) ); +DEFINE_EVENT(fd_request, cobalt_fd_recvmmsg, + TP_PROTO(struct task_struct *task, + struct rtdm_fd *fd, int ufd, + unsigned long flags), + TP_ARGS(task, fd, ufd, flags) +); + #define cobalt_print_protbits(__prot) \ __print_flags(__prot, "|", \ {PROT_EXEC, "exec"}, \ @@ -357,6 +371,13 @@ DEFINE_EVENT(fd_request_status, cobalt_fd_recvmsg_status, TP_ARGS(task, fd, ufd, status) ); +DEFINE_EVENT(fd_request_status, cobalt_fd_recvmmsg_status, + TP_PROTO(struct task_struct *task, + struct rtdm_fd *fd, int ufd, + int status), + TP_ARGS(task, fd, ufd, status) +); + DEFINE_EVENT(fd_request_status, cobalt_fd_sendmsg_status, TP_PROTO(struct task_struct *task, struct rtdm_fd *fd, int ufd, @@ -364,6 +385,13 @@ DEFINE_EVENT(fd_request_status, cobalt_fd_sendmsg_status, TP_ARGS(task, fd, ufd, status) ); +DEFINE_EVENT(fd_request_status, cobalt_fd_sendmmsg_status, + TP_PROTO(struct task_struct *task, + struct rtdm_fd *fd, int ufd, + int status), + TP_ARGS(task, fd, ufd, status) +); + DEFINE_EVENT(fd_request_status, cobalt_fd_mmap_status, TP_PROTO(struct task_struct *task, struct rtdm_fd *fd, int ufd, _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org https://xenomai.org/mailman/listinfo/xenomai-git