Module: xenomai-3 Branch: next Commit: 1ba2fc8ef98d927f07a8d7465fe9ea541f501e39 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=1ba2fc8ef98d927f07a8d7465fe9ea541f501e39
Author: Philippe Gerum <[email protected]> Date: Sun Mar 12 11:37:20 2017 +0100 drivers/ipc: reduce stack footprint of I/O vectors Resort to dynamic allocation of the I/O vector when more than 16 entries are needed, otherwise stick to a stack-based fast vector as previously. As a by-product of this change, we can now align on the regular UIO_MAXIOV limit for all RTIPC protocols. --- kernel/drivers/ipc/bufp.c | 24 +++++++++++++--------- kernel/drivers/ipc/iddp.c | 24 +++++++++++++--------- kernel/drivers/ipc/internal.h | 20 +++++++++++++----- kernel/drivers/ipc/rtipc.c | 45 +++++++++++++++++++++++++++++------------ kernel/drivers/ipc/xddp.c | 24 +++++++++++++--------- 5 files changed, 89 insertions(+), 48 deletions(-) diff --git a/kernel/drivers/ipc/bufp.c b/kernel/drivers/ipc/bufp.c index 2e7f5ad..3b565bd 100644 --- a/kernel/drivers/ipc/bufp.c +++ b/kernel/drivers/ipc/bufp.c @@ -359,7 +359,7 @@ static ssize_t __bufp_recvmsg(struct rtdm_fd *fd, static ssize_t bufp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int flags) { - struct iovec iov[RTIPC_IOV_MAX]; + struct iovec iov_fast[RTIPC_IOV_FASTMAX], *iov; struct sockaddr_ipc saddr; ssize_t ret; @@ -372,20 +372,22 @@ static ssize_t bufp_recvmsg(struct rtdm_fd *fd, } else if (msg->msg_namelen != 0) return -EINVAL; - if (msg->msg_iovlen >= RTIPC_IOV_MAX) + if (msg->msg_iovlen >= UIO_MAXIOV) return -EINVAL; /* Copy I/O vector in */ - ret = rtipc_get_iovec(fd, iov, msg); + ret = rtipc_get_iovec(fd, &iov, msg, iov_fast); if (ret) return ret; ret = __bufp_recvmsg(fd, iov, msg->msg_iovlen, flags, &saddr); - if (ret <= 0) + if (ret <= 0) { + rtipc_drop_iovec(iov, iov_fast); return ret; + } /* Copy the updated I/O vector back */ - if (rtipc_put_iovec(fd, iov, msg)) + if (rtipc_put_iovec(fd, iov, msg, iov_fast)) return -EFAULT; /* Copy the source address if required. */ @@ -607,8 +609,8 @@ static ssize_t bufp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int flags) { struct rtipc_private *priv = rtdm_fd_to_private(fd); + struct iovec iov_fast[RTIPC_IOV_FASTMAX], *iov; struct bufp_socket *sk = priv->state; - struct iovec iov[RTIPC_IOV_MAX]; struct sockaddr_ipc daddr; ssize_t ret; @@ -634,20 +636,22 @@ static ssize_t bufp_sendmsg(struct rtdm_fd *fd, return -EDESTADDRREQ; } - if (msg->msg_iovlen >= RTIPC_IOV_MAX) + if (msg->msg_iovlen >= UIO_MAXIOV) return -EINVAL; /* Copy I/O vector in */ - ret = rtipc_get_iovec(fd, iov, msg); + ret = rtipc_get_iovec(fd, &iov, msg, iov_fast); if (ret) return ret; ret = __bufp_sendmsg(fd, iov, msg->msg_iovlen, flags, &daddr); - if (ret <= 0) + if (ret <= 0) { + rtipc_drop_iovec(iov, iov_fast); return ret; + } /* Copy updated I/O vector back */ - return rtipc_put_iovec(fd, iov, msg) ?: ret; + return rtipc_put_iovec(fd, iov, msg, iov_fast) ?: ret; } static ssize_t bufp_write(struct rtdm_fd *fd, diff --git a/kernel/drivers/ipc/iddp.c b/kernel/drivers/ipc/iddp.c index 6d3da57..5e2a2a1 100644 --- a/kernel/drivers/ipc/iddp.c +++ b/kernel/drivers/ipc/iddp.c @@ -326,7 +326,7 @@ static ssize_t __iddp_recvmsg(struct rtdm_fd *fd, static ssize_t iddp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int flags) { - struct iovec iov[RTIPC_IOV_MAX]; + struct iovec iov_fast[RTIPC_IOV_FASTMAX], *iov; struct sockaddr_ipc saddr; ssize_t ret; @@ -339,20 +339,22 @@ static ssize_t iddp_recvmsg(struct rtdm_fd *fd, } else if (msg->msg_namelen != 0) return -EINVAL; - if (msg->msg_iovlen >= RTIPC_IOV_MAX) + if (msg->msg_iovlen >= UIO_MAXIOV) return -EINVAL; /* Copy I/O vector in */ - ret = rtipc_get_iovec(fd, iov, msg); + ret = rtipc_get_iovec(fd, &iov, msg, iov_fast); if (ret) return ret; ret = __iddp_recvmsg(fd, iov, msg->msg_iovlen, flags, &saddr); - if (ret <= 0) + if (ret <= 0) { + rtipc_drop_iovec(iov, iov_fast); return ret; + } /* Copy the updated I/O vector back */ - if (rtipc_put_iovec(fd, iov, msg)) + if (rtipc_put_iovec(fd, iov, msg, iov_fast)) return -EFAULT; /* Copy the source address if required. */ @@ -468,8 +470,8 @@ static ssize_t iddp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int flags) { struct rtipc_private *priv = rtdm_fd_to_private(fd); + struct iovec iov_fast[RTIPC_IOV_FASTMAX], *iov; struct iddp_socket *sk = priv->state; - struct iovec iov[RTIPC_IOV_MAX]; struct sockaddr_ipc daddr; ssize_t ret; @@ -495,20 +497,22 @@ static ssize_t iddp_sendmsg(struct rtdm_fd *fd, return -EDESTADDRREQ; } - if (msg->msg_iovlen >= RTIPC_IOV_MAX) + if (msg->msg_iovlen >= UIO_MAXIOV) return -EINVAL; /* Copy I/O vector in */ - ret = rtipc_get_iovec(fd, iov, msg); + ret = rtipc_get_iovec(fd, &iov, msg, iov_fast); if (ret) return ret; ret = __iddp_sendmsg(fd, iov, msg->msg_iovlen, flags, &daddr); - if (ret <= 0) + if (ret <= 0) { + rtipc_drop_iovec(iov, iov_fast); return ret; + } /* Copy updated I/O vector back */ - return rtipc_put_iovec(fd, iov, msg) ?: ret; + return rtipc_put_iovec(fd, iov, msg, iov_fast) ?: ret; } static ssize_t iddp_write(struct rtdm_fd *fd, diff --git a/kernel/drivers/ipc/internal.h b/kernel/drivers/ipc/internal.h index 6e20971..e4614c1 100644 --- a/kernel/drivers/ipc/internal.h +++ b/kernel/drivers/ipc/internal.h @@ -20,6 +20,7 @@ #ifndef _RTIPC_INTERNAL_H #define _RTIPC_INTERNAL_H +#include <linux/uio.h> #include <cobalt/kernel/registry.h> #include <cobalt/kernel/clock.h> #include <cobalt/kernel/select.h> @@ -27,7 +28,7 @@ #include <rtdm/compat.h> #include <rtdm/driver.h> -#define RTIPC_IOV_MAX 64 +#define RTIPC_IOV_FASTMAX 16 struct rtipc_protocol; @@ -84,11 +85,20 @@ static inline void rtipc_ns_to_timeval(struct timeval *tv, nanosecs_rel_t ns) tv->tv_usec = nsecs / 1000; } -int rtipc_get_iovec(struct rtdm_fd *fd, struct iovec *iov, - const struct user_msghdr *msg); +int rtipc_get_iovec(struct rtdm_fd *fd, struct iovec **iov, + const struct user_msghdr *msg, + struct iovec *iov_fast); -int rtipc_put_iovec(struct rtdm_fd *fd, const struct iovec *iov, - const struct user_msghdr *msg); +int rtipc_put_iovec(struct rtdm_fd *fd, struct iovec *iov, + const struct user_msghdr *msg, + struct iovec *iov_fast); + +static inline +void rtipc_drop_iovec(struct iovec *iov, struct iovec *iov_fast) +{ + if (iov != iov_fast) + xnfree(iov); +} int rtipc_get_sockaddr(struct rtdm_fd *fd, struct sockaddr_ipc **saddrp, diff --git a/kernel/drivers/ipc/rtipc.c b/kernel/drivers/ipc/rtipc.c index 7bd4950..46b253a 100644 --- a/kernel/drivers/ipc/rtipc.c +++ b/kernel/drivers/ipc/rtipc.c @@ -63,10 +63,25 @@ int rtipc_put_arg(struct rtdm_fd *fd, void *dst, const void *src, size_t len) return rtdm_copy_to_user(fd, dst, src, len); } -int rtipc_get_iovec(struct rtdm_fd *fd, struct iovec *iov, - const struct user_msghdr *msg) +int rtipc_get_iovec(struct rtdm_fd *fd, struct iovec **iovp, + const struct user_msghdr *msg, + struct iovec *iov_fast) { - size_t len = sizeof(iov[0]) * msg->msg_iovlen; + size_t len = sizeof(struct iovec) * msg->msg_iovlen; + struct iovec *iov = iov_fast; + + /* + * If the I/O vector doesn't fit in the fast memory, allocate + * a chunk from the system heap which is large enough to hold + * it. + */ + if (msg->msg_iovlen > RTIPC_IOV_FASTMAX) { + iov = xnmalloc(len); + if (iov == NULL) + return -ENOMEM; + } + + *iovp = iov; if (!rtdm_fd_is_user(fd)) { memcpy(iov, msg->msg_iov, len); @@ -83,23 +98,27 @@ int rtipc_get_iovec(struct rtdm_fd *fd, struct iovec *iov, return rtdm_copy_from_user(fd, iov, msg->msg_iov, len); } -int rtipc_put_iovec(struct rtdm_fd *fd, const struct iovec *iov, - const struct user_msghdr *msg) +int rtipc_put_iovec(struct rtdm_fd *fd, struct iovec *iov, + const struct user_msghdr *msg, + struct iovec *iov_fast) { size_t len = sizeof(iov[0]) * msg->msg_iovlen; + int ret; if (!rtdm_fd_is_user(fd)) { memcpy(msg->msg_iov, iov, len); - return 0; - } + ret = 0; + } else if (IS_ENABLED(CONFIG_XENO_ARCH_SYS3264) && + rtdm_fd_is_compat(fd)) + ret = sys32_put_iovec((struct compat_iovec __user *)msg->msg_iov, + iov, msg->msg_iovlen); + else + ret = rtdm_copy_to_user(fd, msg->msg_iov, iov, len); -#ifdef CONFIG_XENO_ARCH_SYS3264 - if (rtdm_fd_is_compat(fd)) - return sys32_put_iovec((struct compat_iovec __user *)msg->msg_iov, - iov, msg->msg_iovlen); -#endif + if (iov != iov_fast) + xnfree(iov); - return rtdm_copy_to_user(fd, msg->msg_iov, iov, len); + return ret; } int rtipc_get_sockaddr(struct rtdm_fd *fd, struct sockaddr_ipc **saddrp, diff --git a/kernel/drivers/ipc/xddp.c b/kernel/drivers/ipc/xddp.c index c48b935..4d43cfa 100644 --- a/kernel/drivers/ipc/xddp.c +++ b/kernel/drivers/ipc/xddp.c @@ -337,7 +337,7 @@ out: static ssize_t xddp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int flags) { - struct iovec iov[RTIPC_IOV_MAX]; + struct iovec iov_fast[RTIPC_IOV_FASTMAX], *iov; struct sockaddr_ipc saddr; ssize_t ret; @@ -350,20 +350,22 @@ static ssize_t xddp_recvmsg(struct rtdm_fd *fd, } else if (msg->msg_namelen != 0) return -EINVAL; - if (msg->msg_iovlen >= RTIPC_IOV_MAX) + if (msg->msg_iovlen >= UIO_MAXIOV) return -EINVAL; /* Copy I/O vector in */ - ret = rtipc_get_iovec(fd, iov, msg); + ret = rtipc_get_iovec(fd, &iov, msg, iov_fast); if (ret) return ret; ret = __xddp_recvmsg(fd, iov, msg->msg_iovlen, flags, &saddr); - if (ret <= 0) + if (ret <= 0) { + rtipc_drop_iovec(iov, iov_fast); return ret; + } /* Copy the updated I/O vector back */ - if (rtipc_put_iovec(fd, iov, msg)) + if (rtipc_put_iovec(fd, iov, msg, iov_fast)) return -EFAULT; /* Copy the source address if required. */ @@ -591,8 +593,8 @@ static ssize_t xddp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int flags) { struct rtipc_private *priv = rtdm_fd_to_private(fd); + struct iovec iov_fast[RTIPC_IOV_FASTMAX], *iov; struct xddp_socket *sk = priv->state; - struct iovec iov[RTIPC_IOV_MAX]; struct sockaddr_ipc daddr; ssize_t ret; @@ -630,20 +632,22 @@ static ssize_t xddp_sendmsg(struct rtdm_fd *fd, return -EDESTADDRREQ; } - if (msg->msg_iovlen >= RTIPC_IOV_MAX) + if (msg->msg_iovlen >= UIO_MAXIOV) return -EINVAL; /* Copy I/O vector in */ - ret = rtipc_get_iovec(fd, iov, msg); + ret = rtipc_get_iovec(fd, &iov, msg, iov_fast); if (ret) return ret; ret = __xddp_sendmsg(fd, iov, msg->msg_iovlen, flags, &daddr); - if (ret <= 0) + if (ret <= 0) { + rtipc_drop_iovec(iov, iov_fast); return ret; + } /* Copy updated I/O vector back */ - return rtipc_put_iovec(fd, iov, msg) ?: ret; + return rtipc_put_iovec(fd, iov, msg, iov_fast) ?: ret; } static ssize_t xddp_write(struct rtdm_fd *fd, _______________________________________________ Xenomai-git mailing list [email protected] https://xenomai.org/mailman/listinfo/xenomai-git
