Module: xenomai-3
Branch: master
Commit: 1ba2fc8ef98d927f07a8d7465fe9ea541f501e39
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=1ba2fc8ef98d927f07a8d7465fe9ea541f501e39

Author: Philippe Gerum <r...@xenomai.org>
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
Xenomai-git@xenomai.org
https://xenomai.org/mailman/listinfo/xenomai-git

Reply via email to