From: Jan Kiszka <jan.kis...@siemens.com>

Rather than duplicating lots of code for the sake of compat userspace
accesses, provide a common version that is given a flag to decide
whether to take the compat or regular code paths.

This also brings restart support to the compat selection version which
was forgotten by 36132cdb21cd.

Signed-off-by: Jan Kiszka <jan.kis...@siemens.com>
---
 kernel/cobalt/posix/io.c        | 97 ++++++++++++++++++++++++---------
 kernel/cobalt/posix/io.h        |  3 +
 kernel/cobalt/posix/syscall32.c | 92 +------------------------------
 3 files changed, 76 insertions(+), 116 deletions(-)

diff --git a/kernel/cobalt/posix/io.c b/kernel/cobalt/posix/io.c
index 8a74074f3c..0c17f55bf3 100644
--- a/kernel/cobalt/posix/io.c
+++ b/kernel/cobalt/posix/io.c
@@ -19,6 +19,7 @@
  */
 #include <linux/err.h>
 #include <linux/fs.h>
+#include <cobalt/kernel/compat.h>
 #include <cobalt/kernel/ppd.h>
 #include <xenomai/rtdm/internal.h>
 #include "process.h"
@@ -210,15 +211,10 @@ int __cobalt_select_bind_all(struct xnselector *selector,
        return 0;
 }
 
-/* int select(int, fd_set *, fd_set *, fd_set *, struct __kernel_old_timeval 
*) */
-COBALT_SYSCALL(select, primary,
-              (int nfds,
-               fd_set __user *u_rfds,
-               fd_set __user *u_wfds,
-               fd_set __user *u_xfds,
-               struct __kernel_old_timeval __user *u_tv))
+int __cobalt_select(int nfds, void __user *u_rfds, void __user *u_wfds,
+                   void __user *u_xfds, void __user *u_tv, bool compat)
 {
-       fd_set __user *ufd_sets[XNSELECT_MAX_TYPES] = {
+       void __user *ufd_sets[XNSELECT_MAX_TYPES] = {
                [XNSELECT_READ] = u_rfds,
                [XNSELECT_WRITE] = u_wfds,
                [XNSELECT_EXCEPT] = u_xfds
@@ -250,9 +246,18 @@ COBALT_SYSCALL(select, primary,
                                goto out;
                        }
                } else {
-                       if (!access_wok(u_tv, sizeof(tv))
-                           || cobalt_copy_from_user(&tv, u_tv, sizeof(tv)))
-                               return -EFAULT;
+#ifdef CONFIG_XENO_ARCH_SYS3264
+                       if (compat) {
+                               if (sys32_get_timeval(&tv, u_tv))
+                                       return -EFAULT;
+                       } else
+#endif
+                       {
+                               if (!access_wok(u_tv, sizeof(tv))
+                                   || cobalt_copy_from_user(&tv, u_tv,
+                                                            sizeof(tv)))
+                                       return -EFAULT;
+                       }
 
                        if (tv.tv_usec >= 1000000)
                                return -EINVAL;
@@ -268,13 +273,22 @@ COBALT_SYSCALL(select, primary,
        for (i = 0; i < XNSELECT_MAX_TYPES; i++)
                if (ufd_sets[i]) {
                        in_fds[i] = &in_fds_storage[i];
-                       out_fds[i] = & out_fds_storage[i];
-                       if (!access_wok((void __user *) ufd_sets[i],
-                                       sizeof(fd_set))
-                           || cobalt_copy_from_user(in_fds[i],
-                                                    (void __user *) 
ufd_sets[i],
-                                                    fds_size))
-                               return -EFAULT;
+                       out_fds[i] = &out_fds_storage[i];
+#ifdef CONFIG_XENO_ARCH_SYS3264
+                       if (compat) {
+                               if (sys32_get_fdset(in_fds[i], ufd_sets[i],
+                                                   fds_size))
+                                       return -EFAULT;
+                       } else
+#endif
+                       {
+                               if (!access_wok((void __user *) ufd_sets[i],
+                                               sizeof(fd_set))
+                                   || cobalt_copy_from_user(in_fds[i],
+                                                            (void __user 
*)ufd_sets[i],
+                                                            fds_size))
+                                       return -EFAULT;
+                       }
                }
 
        selector = curr->selector;
@@ -294,7 +308,8 @@ COBALT_SYSCALL(select, primary,
 
                /* Bind directly the file descriptors, we do not need to go
                   through xnselect returning -ECHRNG */
-               if ((err = __cobalt_select_bind_all(selector, in_fds, nfds)))
+               err = __cobalt_select_bind_all(selector, in_fds, nfds);
+               if (err)
                        return err;
        }
 
@@ -326,15 +341,45 @@ out:
                else
                        tv.tv_sec = tv.tv_usec = 0;
 
-               if (cobalt_copy_to_user(u_tv, &tv, sizeof(tv)))
-                       return -EFAULT;
+#ifdef CONFIG_XENO_ARCH_SYS3264
+               if (compat) {
+                       if (sys32_put_timeval(u_tv, &tv))
+                               return -EFAULT;
+               } else
+#endif
+               {
+                       if (cobalt_copy_to_user(u_tv, &tv, sizeof(tv)))
+                               return -EFAULT;
+               }
        }
 
        if (err >= 0)
-               for (i = 0; i < XNSELECT_MAX_TYPES; i++)
-                       if (ufd_sets[i]
-                           && cobalt_copy_to_user((void __user *) ufd_sets[i],
-                                                  out_fds[i], sizeof(fd_set)))
-                               return -EFAULT;
+               for (i = 0; i < XNSELECT_MAX_TYPES; i++) {
+                       if (!ufd_sets[i])
+                               continue;
+#ifdef CONFIG_XENO_ARCH_SYS3264
+                       if (compat) {
+                               if (sys32_put_fdset(ufd_sets[i], out_fds[i],
+                                                   sizeof(fd_set)))
+                                       return -EFAULT;
+                       } else
+#endif
+                       {
+                               if (cobalt_copy_to_user((void __user 
*)ufd_sets[i],
+                                                       out_fds[i], 
sizeof(fd_set)))
+                                       return -EFAULT;
+                       }
+               }
        return err;
 }
+
+/* int select(int, fd_set *, fd_set *, fd_set *, struct __kernel_old_timeval 
*) */
+COBALT_SYSCALL(select, primary,
+              (int nfds,
+               fd_set __user *u_rfds,
+               fd_set __user *u_wfds,
+               fd_set __user *u_xfds,
+               struct __kernel_old_timeval __user *u_tv))
+{
+       return __cobalt_select(nfds, u_rfds, u_wfds, u_xfds, u_tv, false);
+}
diff --git a/kernel/cobalt/posix/io.h b/kernel/cobalt/posix/io.h
index e4f7d4d51f..d9f29fa595 100644
--- a/kernel/cobalt/posix/io.h
+++ b/kernel/cobalt/posix/io.h
@@ -28,6 +28,9 @@ int __cobalt_first_fd_valid_p(fd_set 
*fds[XNSELECT_MAX_TYPES], int nfds);
 int __cobalt_select_bind_all(struct xnselector *selector,
                             fd_set *fds[XNSELECT_MAX_TYPES], int nfds);
 
+int __cobalt_select(int nfds, void __user *u_rfds, void __user *u_wfds,
+                   void __user *u_xfds, void __user *u_tv, bool compat);
+
 COBALT_SYSCALL_DECL(open,
                    (const char __user *u_path, int oflag));
 
diff --git a/kernel/cobalt/posix/syscall32.c b/kernel/cobalt/posix/syscall32.c
index c298f38f5a..a37478f3f9 100644
--- a/kernel/cobalt/posix/syscall32.c
+++ b/kernel/cobalt/posix/syscall32.c
@@ -743,102 +743,14 @@ COBALT_SYSCALL32emu(event_wait, primary,
        return __cobalt_event_wait(u_event, bits, u_bits_r, mode, tsp);
 }
 
-COBALT_SYSCALL32emu(select, nonrestartable,
+COBALT_SYSCALL32emu(select, primary,
                    (int nfds,
                     compat_fd_set __user *u_rfds,
                     compat_fd_set __user *u_wfds,
                     compat_fd_set __user *u_xfds,
                     struct old_timeval32 __user *u_tv))
 {
-       compat_fd_set __user *ufd_sets[XNSELECT_MAX_TYPES] = {
-               [XNSELECT_READ] = u_rfds,
-               [XNSELECT_WRITE] = u_wfds,
-               [XNSELECT_EXCEPT] = u_xfds
-       };
-       fd_set *in_fds[XNSELECT_MAX_TYPES] = {NULL, NULL, NULL};
-       fd_set *out_fds[XNSELECT_MAX_TYPES] = {NULL, NULL, NULL};
-       fd_set in_fds_storage[XNSELECT_MAX_TYPES],
-               out_fds_storage[XNSELECT_MAX_TYPES];
-       xnticks_t timeout = XN_INFINITE;
-       xntmode_t mode = XN_RELATIVE;
-       struct xnselector *selector;
-       struct xnthread *curr;
-       struct __kernel_old_timeval tv;
-       xnsticks_t diff;
-       size_t fds_size;
-       int i, err;
-
-       curr = xnthread_current();
-
-       if (u_tv) {
-               err = sys32_get_timeval(&tv, u_tv);
-               if (err)
-                       return err;
-
-               if (tv.tv_usec >= 1000000)
-                       return -EINVAL;
-
-               timeout = clock_get_ticks(CLOCK_MONOTONIC) + tv2ns(&tv);
-               mode = XN_ABSOLUTE;
-       }
-
-       fds_size = __FDELT__(nfds + __NFDBITS__ - 1) * sizeof(compat_ulong_t);
-
-       for (i = 0; i < XNSELECT_MAX_TYPES; i++)
-               if (ufd_sets[i]) {
-                       in_fds[i] = &in_fds_storage[i];
-                       out_fds[i] = & out_fds_storage[i];
-                       if (sys32_get_fdset(in_fds[i], ufd_sets[i], fds_size) < 
0)
-                               return -EFAULT;
-               }
-
-       selector = curr->selector;
-       if (selector == NULL) {
-               /* Bail out if non-RTDM fildes is found. */
-               if (!__cobalt_first_fd_valid_p(in_fds, nfds))
-                       return -EADV;
-
-               selector = xnmalloc(sizeof(*curr->selector));
-               if (selector == NULL)
-                       return -ENOMEM;
-               xnselector_init(selector);
-               curr->selector = selector;
-
-               /* Bind directly the file descriptors, we do not need to go
-                  through xnselect returning -ECHRNG */
-               err = __cobalt_select_bind_all(selector, in_fds, nfds);
-               if (err)
-                       return err;
-       }
-
-       do {
-               err = xnselect(selector, out_fds, in_fds, nfds, timeout, mode);
-               if (err == -ECHRNG) {
-                       int bind_err = __cobalt_select_bind_all(selector,
-                                                               out_fds, nfds);
-                       if (bind_err)
-                               return bind_err;
-               }
-       } while (err == -ECHRNG);
-
-       if (u_tv && (err > 0 || err == -EINTR)) {
-               diff = timeout - clock_get_ticks(CLOCK_MONOTONIC);
-               if (diff > 0)
-                       ticks2tv(&tv, diff);
-               else
-                       tv.tv_sec = tv.tv_usec = 0;
-
-               if (sys32_put_timeval(u_tv, &tv))
-                       return -EFAULT;
-       }
-
-       if (err >= 0)
-               for (i = 0; i < XNSELECT_MAX_TYPES; i++)
-                       if (ufd_sets[i] &&
-                           sys32_put_fdset(ufd_sets[i], out_fds[i],
-                                           sizeof(fd_set)) < 0)
-                               return -EFAULT;
-       return err;
+       return __cobalt_select(nfds, u_rfds, u_wfds, u_xfds, u_tv, true);
 }
 
 COBALT_SYSCALL32emu(recvmsg, handover,
-- 
2.26.2


Reply via email to