Does FreeBSD have sendmmsg or recvmmsg system calls?
Konstantin Belousov
kostikbel at gmail.com
Thu Jan 7 10:54:24 UTC 2016
On Thu, Jan 07, 2016 at 12:28:32PM +0200, Boris Astardzhiev wrote:
See inline comments and final notes at the end.
> diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
> index 5caf9a3..7e2a902 100644
> --- a/lib/libc/include/libc_private.h
> +++ b/lib/libc/include/libc_private.h
> @@ -200,8 +200,10 @@ enum {
> INTERPOS_pselect,
> INTERPOS_recvfrom,
> INTERPOS_recvmsg,
> + INTERPOS_recvmmsg,
> INTERPOS_select,
> INTERPOS_sendmsg,
> + INTERPOS_sendmmsg,
> INTERPOS_sendto,
> INTERPOS_setcontext,
> INTERPOS_sigaction,
The interposing table must be extended at the end, and not in the middle.
otherwise you introduce too large inconsistence with older libthr.
That said, you changed libc table, but did not updated libthr. The result
is random segfaults in the multithreaded processes.
> diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
> index 7b3257c..6cc3c6e 100644
> --- a/lib/libc/sys/Symbol.map
> +++ b/lib/libc/sys/Symbol.map
> @@ -220,6 +220,7 @@ FBSD_1.0 {
> reboot;
> recvfrom;
> recvmsg;
> + recvmmsg;
> rename;
> revoke;
> rfork;
> @@ -240,6 +241,7 @@ FBSD_1.0 {
> semsys;
> sendfile;
> sendmsg;
> + sendmmsg;
> sendto;
> setaudit;
> setaudit_addr;
The versioning is wrong, new non-private symbols for 11.0 go into _1.4.
> @@ -851,6 +853,8 @@ FBSDprivate_1.0 {
> __sys_recvfrom;
> _recvmsg;
> __sys_recvmsg;
> + _recvmmsg;
> + __sys_recvmmsg;
> _rename;
> __sys_rename;
> _revoke;
> @@ -891,6 +895,8 @@ FBSDprivate_1.0 {
> __sys_sendfile;
> _sendmsg;
> __sys_sendmsg;
> + _sendmmsg;
> + __sys_sendmmsg;
> _sendto;
> __sys_sendto;
> _setaudit;
> diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
> index c33a2cf..7354b4f 100644
> --- a/sys/kern/uipc_syscalls.c
> +++ b/sys/kern/uipc_syscalls.c
> +int
> +sys_recvmmsg(td, uap)
> + struct thread *td;
> + struct recvmmsg_args /* {
> + int s;
> + struct mmsghdr *msgvec;
> + unsigned int vlen;
> + int flags;
> + } */ *uap;
Use ANSI C definitions for new code, please.
I personally do not inline uap declaration, the time has gone.
> +{
> + struct mmsghdr *vec, *mmp;
> + struct msghdr *mp, msg;
> + struct iovec *uiov, *iov;
> + unsigned int vlen, len;
> + int i, rcvd = 0, error;
> + struct socket *so = NULL;
Style, no initialization in declaration.
> + struct file *fp;
> + cap_rights_t rights;
> +
> + if (fget(td, uap->s, cap_rights_init(&rights, CAP_RECV), &fp) != 0)
> + return (EBADF);
> +
> + so = fp->f_data;
What if uap->s filedescriptor does not reference a socket ?
> +
> + vlen = uap->vlen;
> + if (vlen > UIO_MAXIOV)
> + vlen = UIO_MAXIOV;
> +
> + len = vlen * sizeof(*uap->msgvec);
> + vec = malloc(len, M_TEMP, M_WAITOK);
This is a user-controlled malloc(9), i.e. an easy kernel panic due to
impossible to satisfy request, or KVA and memory exhaustion.
> +
> + error = copyin(uap->msgvec, vec, len);
> + if (error != 0)
> + goto out;
> +
> + for (i = 0; i < vlen; i++) {
> + mmp = &vec[i];
> + mp = &mmp->msg_hdr;
> + msg = *mp;
> +
> + error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
> + if (error != 0)
> + goto out;
> +
> + msg.msg_flags = uap->flags;
> +#ifdef COMPAT_OLDSOCK
> + msg.msg_flags &= ~MSG_COMPAT;
> +#endif
> + uiov = msg.msg_iov;
> + msg.msg_iov = iov;
> +
> + error = recvit(td, uap->s, &msg, NULL);
> + if (error == 0) {
> + msg.msg_iov = uiov;
> + error = copyout(&msg, &uap->msgvec[i].msg_hdr, sizeof(msg));
> + if (error != 0) {
> + free(iov, M_IOV);
> + goto out;
> + }
> + error = copyout(&td->td_retval[0], &uap->msgvec[i].msg_len,
> + sizeof(td->td_retval[0]));
> + if (error != 0) {
> + free(iov, M_IOV);
> + goto out;
> + }
> + }
> + free(iov, M_IOV);
> + rcvd++;
> + }
> +
> + td->td_retval[0] = rcvd;
> +
> +out:
> + if (error != 0 && rcvd != 0 && rcvd != vlen) {
> + so->so_error = error;
> + error = 0;
> + td->td_retval[0] = rcvd;
> + }
> +
> + fdrop(fp, td);
> +
> + free(vec, M_TEMP);
> + return (error);
> +}
> +
> /* ARGSUSED */
> int
> sys_shutdown(td, uap)
> diff --git a/sys/sys/socket.h b/sys/sys/socket.h
> index 18e2de1..d352cd2 100644
> --- a/sys/sys/socket.h
> +++ b/sys/sys/socket.h
> @@ -414,6 +414,11 @@ struct msghdr {
> int msg_flags; /* flags on received message */
> };
>
> +struct mmsghdr {
> + struct msghdr msg_hdr; /* message header */
> + unsigned int msg_len; /* message length */
> +};
> +
> #define MSG_OOB 0x1 /* process out-of-band data */
> #define MSG_PEEK 0x2 /* peek at incoming message */
> #define MSG_DONTROUTE 0x4 /* send without using routing tables */
> @@ -615,10 +620,12 @@ int listen(int, int);
> ssize_t recv(int, void *, size_t, int);
> ssize_t recvfrom(int, void *, size_t, int, struct sockaddr * __restrict, socklen_t * __restrict);
> ssize_t recvmsg(int, struct msghdr *, int);
> +ssize_t recvmmsg(int, struct mmsghdr *, unsigned int, int);
> ssize_t send(int, const void *, size_t, int);
> ssize_t sendto(int, const void *,
> size_t, int, const struct sockaddr *, socklen_t);
> ssize_t sendmsg(int, const struct msghdr *, int);
> +ssize_t sendmmsg(int, const struct mmsghdr *, unsigned int, int);
Why did you put new functions into POSIX namespace ?
They are GNU (and now BSD) extensions, at least I do not see then in SUS.
> #if __BSD_VISIBLE
> int sendfile(int, int, off_t, size_t, struct sf_hdtr *, off_t *, int);
> int setfib(int);
The patch lacks man page update, and lacks the freebsd32 compat shims.
What are the reasons to go with the trivial kernel implementation
right now, instead of trivial and simpler libc wrapper ? I think the
speed would be same, but the code _much_ simpler.
More information about the freebsd-net
mailing list