Module: xenomai-3
Branch: wip/drivers
Commit: a96a6d8e2816914aea7580bfd1ca969487bf2b01
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=a96a6d8e2816914aea7580bfd1ca969487bf2b01

Author: Philippe Gerum <r...@xenomai.org>
Date:   Thu Jul  7 18:35:47 2016 +0200

cobalt/rtdm: leave mode selection to I/O syscall handlers

We don't want requests bearing invalid file descriptors (RTDM-wise) to
trigger any mode switch, so that RTDM requests on regular fildes can
be rejected with little overhead.

Tell the core to hand over mode selection to RTDM I/O syscall
handlers, which now check the file descriptor prior to triggering any
mode transition.

---

 kernel/cobalt/posix/io.c        |   10 +--
 kernel/cobalt/posix/syscall32.c |    4 +-
 kernel/cobalt/rtdm/fd.c         |  144 +++++++++++++++++++++++----------------
 3 files changed, 92 insertions(+), 66 deletions(-)

diff --git a/kernel/cobalt/posix/io.c b/kernel/cobalt/posix/io.c
index 7110d21..42b7b00 100644
--- a/kernel/cobalt/posix/io.c
+++ b/kernel/cobalt/posix/io.c
@@ -58,25 +58,25 @@ COBALT_SYSCALL(fcntl, current, (int fd, int cmd, int arg))
        return rtdm_fd_fcntl(fd, cmd, arg);
 }
 
-COBALT_SYSCALL(ioctl, probing,
+COBALT_SYSCALL(ioctl, handover,
               (int fd, unsigned int request, void __user *arg))
 {
        return rtdm_fd_ioctl(fd, request, arg);
 }
 
-COBALT_SYSCALL(read, probing,
+COBALT_SYSCALL(read, handover,
               (int fd, void __user *buf, size_t size))
 {
        return rtdm_fd_read(fd, buf, size);
 }
 
-COBALT_SYSCALL(write, probing,
+COBALT_SYSCALL(write, handover,
               (int fd, const void __user *buf, size_t size))
 {
        return rtdm_fd_write(fd, buf, size);
 }
 
-COBALT_SYSCALL(recvmsg, probing,
+COBALT_SYSCALL(recvmsg, handover,
               (int fd, struct user_msghdr __user *umsg, int flags))
 {
        struct user_msghdr m;
@@ -93,7 +93,7 @@ COBALT_SYSCALL(recvmsg, probing,
        return cobalt_copy_to_user(umsg, &m, sizeof(*umsg)) ?: ret;
 }
 
-COBALT_SYSCALL(sendmsg, probing,
+COBALT_SYSCALL(sendmsg, handover,
               (int fd, struct user_msghdr __user *umsg, int flags))
 {
        struct user_msghdr m;
diff --git a/kernel/cobalt/posix/syscall32.c b/kernel/cobalt/posix/syscall32.c
index 0576b37..bc8b9d9 100644
--- a/kernel/cobalt/posix/syscall32.c
+++ b/kernel/cobalt/posix/syscall32.c
@@ -766,7 +766,7 @@ COBALT_SYSCALL32emu(select, nonrestartable,
        return err;
 }
 
-COBALT_SYSCALL32emu(recvmsg, probing,
+COBALT_SYSCALL32emu(recvmsg, handover,
                    (int fd, struct compat_msghdr __user *umsg,
                     int flags))
 {
@@ -784,7 +784,7 @@ COBALT_SYSCALL32emu(recvmsg, probing,
        return sys32_put_msghdr(umsg, &m) ?: ret;
 }
 
-COBALT_SYSCALL32emu(sendmsg, probing,
+COBALT_SYSCALL32emu(sendmsg, handover,
                    (int fd, struct compat_msghdr __user *umsg, int flags))
 {
        struct user_msghdr m;
diff --git a/kernel/cobalt/rtdm/fd.c b/kernel/cobalt/rtdm/fd.c
index d82cfe4..3381dea 100644
--- a/kernel/cobalt/rtdm/fd.c
+++ b/kernel/cobalt/rtdm/fd.c
@@ -392,6 +392,44 @@ int rtdm_fd_fcntl(int ufd, int cmd, ...)
 }
 EXPORT_SYMBOL_GPL(rtdm_fd_fcntl);
 
+static struct rtdm_fd *get_fd_fixup_mode(int ufd)
+{
+       struct xnthread *thread;
+       struct rtdm_fd *fd;
+       
+       fd = rtdm_fd_get(ufd, 0);
+       if (IS_ERR(fd))
+               return fd;
+
+       /*
+        * Mode is selected according to the following convention:
+        *
+        * - Cobalt threads must try running the syscall from primary
+        * mode as a first attempt, regardless of their scheduling
+        * class. The driver handler may ask for demoting the caller
+        * to secondary mode by returning -ENOSYS.
+        *
+        * - Regular threads (i.e. not bound to Cobalt) may only run
+        * the syscall from secondary mode.
+        */
+       thread = xnthread_current();
+       if (unlikely(ipipe_root_p)) {
+               if (thread == NULL ||
+                   xnthread_test_localinfo(thread, XNDESCENT))
+                       return fd;
+       } else if (likely(thread))
+               return fd;
+
+       /*
+        * We need to switch to the converse mode. Since all callers
+        * bear the "adaptive" tag, we just pass -ENOSYS back to the
+        * syscall dispatcher to get switched to the next mode.
+        */
+       rtdm_fd_put(fd);
+
+       return ERR_PTR(-ENOSYS);
+}
+
 int rtdm_fd_ioctl(int ufd, unsigned int request, ...)
 {
        struct rtdm_fd *fd;
@@ -399,16 +437,14 @@ int rtdm_fd_ioctl(int ufd, unsigned int request, ...)
        va_list args;
        int err, ret;
 
+       fd = get_fd_fixup_mode(ufd);
+       if (IS_ERR(fd))
+               return PTR_ERR(fd);
+
        va_start(args, request);
        arg = va_arg(args, void __user *);
        va_end(args);
 
-       fd = rtdm_fd_get(ufd, 0);
-       if (IS_ERR(fd)) {
-               err = PTR_ERR(fd);
-               goto out;
-       }
-
        set_compat_bit(fd);
 
        trace_cobalt_fd_ioctl(current, fd, ufd, request);
@@ -419,7 +455,7 @@ int rtdm_fd_ioctl(int ufd, unsigned int request, ...)
                err = fd->ops->ioctl_rt(fd, request, arg);
 
        if (!XENO_ASSERT(COBALT, !spltest()))
-                   splnone();
+               splnone();
 
        if (err < 0) {
                ret = __rtdm_dev_ioctl_core(fd, request, arg);
@@ -428,7 +464,7 @@ int rtdm_fd_ioctl(int ufd, unsigned int request, ...)
        }
 
        rtdm_fd_put(fd);
-  out:
+
        if (err < 0)
                trace_cobalt_fd_ioctl_status(current, fd, ufd, err);
 
@@ -440,130 +476,120 @@ ssize_t
 rtdm_fd_read(int ufd, void __user *buf, size_t size)
 {
        struct rtdm_fd *fd;
-       ssize_t err;
+       ssize_t ret;
 
-       fd = rtdm_fd_get(ufd, 0);
-       if (IS_ERR(fd)) {
-               err = PTR_ERR(fd);
-               goto out;
-       }
+       fd = get_fd_fixup_mode(ufd);
+       if (IS_ERR(fd))
+               return PTR_ERR(fd);
 
        set_compat_bit(fd);
 
        trace_cobalt_fd_read(current, fd, ufd, size);
 
        if (ipipe_root_p)
-               err = fd->ops->read_nrt(fd, buf, size);
+               ret = fd->ops->read_nrt(fd, buf, size);
        else
-               err = fd->ops->read_rt(fd, buf, size);
+               ret = fd->ops->read_rt(fd, buf, size);
 
        if (!XENO_ASSERT(COBALT, !spltest()))
-                   splnone();
+               splnone();
 
        rtdm_fd_put(fd);
 
-  out:
-       if (err < 0)
-               trace_cobalt_fd_read_status(current, fd, ufd, err);
+       if (ret < 0)
+               trace_cobalt_fd_read_status(current, fd, ufd, ret);
 
-       return err;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(rtdm_fd_read);
 
 ssize_t rtdm_fd_write(int ufd, const void __user *buf, size_t size)
 {
        struct rtdm_fd *fd;
-       ssize_t err;
+       ssize_t ret;
 
-       fd = rtdm_fd_get(ufd, 0);
-       if (IS_ERR(fd)) {
-               err = PTR_ERR(fd);
-               goto out;
-       }
+       fd = get_fd_fixup_mode(ufd);
+       if (IS_ERR(fd))
+               return PTR_ERR(fd);
 
        set_compat_bit(fd);
 
        trace_cobalt_fd_write(current, fd, ufd, size);
 
        if (ipipe_root_p)
-               err = fd->ops->write_nrt(fd, buf, size);
+               ret = fd->ops->write_nrt(fd, buf, size);
        else
-               err = fd->ops->write_rt(fd, buf, size);
+               ret = fd->ops->write_rt(fd, buf, size);
 
        if (!XENO_ASSERT(COBALT, !spltest()))
-                   splnone();
+               splnone();
 
        rtdm_fd_put(fd);
 
-  out:
-       if (err < 0)
-               trace_cobalt_fd_write_status(current, fd, ufd, err);
+       if (ret < 0)
+               trace_cobalt_fd_write_status(current, fd, ufd, ret);
 
-       return err;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(rtdm_fd_write);
 
 ssize_t rtdm_fd_recvmsg(int ufd, struct user_msghdr *msg, int flags)
 {
        struct rtdm_fd *fd;
-       ssize_t err;
+       ssize_t ret;
 
-       fd = rtdm_fd_get(ufd, 0);
-       if (IS_ERR(fd)) {
-               err = PTR_ERR(fd);
-               goto out;
-       }
+       fd = get_fd_fixup_mode(ufd);
+       if (IS_ERR(fd))
+               return PTR_ERR(fd);
 
        set_compat_bit(fd);
 
        trace_cobalt_fd_recvmsg(current, fd, ufd, flags);
 
        if (ipipe_root_p)
-               err = fd->ops->recvmsg_nrt(fd, msg, flags);
+               ret = fd->ops->recvmsg_nrt(fd, msg, flags);
        else
-               err = fd->ops->recvmsg_rt(fd, msg, flags);
+               ret = fd->ops->recvmsg_rt(fd, msg, flags);
 
        if (!XENO_ASSERT(COBALT, !spltest()))
                splnone();
 
        rtdm_fd_put(fd);
-out:
-       if (err < 0)
-               trace_cobalt_fd_recvmsg_status(current, fd, ufd, err);
 
-       return err;
+       if (ret < 0)
+               trace_cobalt_fd_recvmsg_status(current, fd, ufd, ret);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(rtdm_fd_recvmsg);
 
 ssize_t rtdm_fd_sendmsg(int ufd, const struct user_msghdr *msg, int flags)
 {
        struct rtdm_fd *fd;
-       ssize_t err;
+       ssize_t ret;
 
-       fd = rtdm_fd_get(ufd, 0);
-       if (IS_ERR(fd)) {
-               err = PTR_ERR(fd);
-               goto out;
-       }
+       fd = get_fd_fixup_mode(ufd);
+       if (IS_ERR(fd))
+               return PTR_ERR(fd);
 
        set_compat_bit(fd);
 
        trace_cobalt_fd_sendmsg(current, fd, ufd, flags);
 
        if (ipipe_root_p)
-               err = fd->ops->sendmsg_nrt(fd, msg, flags);
+               ret = fd->ops->sendmsg_nrt(fd, msg, flags);
        else
-               err = fd->ops->sendmsg_rt(fd, msg, flags);
+               ret = fd->ops->sendmsg_rt(fd, msg, flags);
 
        if (!XENO_ASSERT(COBALT, !spltest()))
-                   splnone();
+               splnone();
 
        rtdm_fd_put(fd);
-out:
-       if (err < 0)
-               trace_cobalt_fd_sendmsg_status(current, fd, ufd, err);
 
-       return err;
+       if (ret < 0)
+               trace_cobalt_fd_sendmsg_status(current, fd, ufd, ret);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(rtdm_fd_sendmsg);
 


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
https://xenomai.org/mailman/listinfo/xenomai-git

Reply via email to