net: rock: Mirror F_SETFL flags to all FDs (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 15 Dec 2017 20:40:33 +0000 (15:40 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 20 Dec 2017 18:37:08 +0000 (13:37 -0500)
When the application attempts a fcntl + F_SETFL on a Rock FD (which is a
data FD), we'll mirror those commands to the other FDs (ctl and listen).

The motivator for this is dropbear, which sets a socket O_NONBLOCK and then
polls with connect().  It expects the O_NONBLOCK set on the socket FD to
apply to the entire socket.  Recall that all of the files that make up a
Rock collectively are a socket.

Back before commit 765fc2a8270a ("Remove the O_NONBLOCK fcntl() intercept
(XCC)"), we handled O_NONBLOCK in userspace.  This commit is somewhat
similar in that we need to do special Rock processing, but we still just do
fcntls.

Rebuild glibc.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/fcntl.c
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/plan9_sockets.c
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sys/plan9_helpers.h

index 74267b3..56e108b 100644 (file)
@@ -8,6 +8,14 @@
 #include <stdlib.h>
 #include <ros/syscall.h>
 
+/* This is overridden when we're building with sockets.  We need to go through
+ * these hoops since fnctl is a lower-level glibc function and is included in
+ * code that can't use sockets/rocks/stdio. */
+static void __weak_sock_mirror_fcntl(int sock_fd, int cmd, long arg)
+{
+}
+weak_alias(__weak_sock_mirror_fcntl, _sock_mirror_fcntl);
+
 int __vfcntl(int fd, int cmd, va_list vl)
 {
        int ret, arg, advise;
@@ -20,9 +28,16 @@ int __vfcntl(int fd, int cmd, va_list vl)
                case F_DUPFD:
                case F_SETFD:
                case F_GETFL:
+                       arg = va_arg(vl, int);
+                       ret = ros_syscall(SYS_fcntl, fd, cmd, arg, 0, 0, 0);
+                       break;
                case F_SETFL:
                        arg = va_arg(vl, int);
                        ret = ros_syscall(SYS_fcntl, fd, cmd, arg, 0, 0, 0);
+                       /* For SETFL, we mirror the operation on all of the Rocks FDs.  If
+                        * the others fail, we won't hear about it.  Similarly, we only
+                        * GETFL for the data FD. */
+                       _sock_mirror_fcntl(fd, cmd, arg);
                        break;
                case F_ADVISE:
                        offset = va_arg(vl, __off64_t);
@@ -38,7 +53,7 @@ int __vfcntl(int fd, int cmd, va_list vl)
 }
 
 /* We used to override fcntl() with some Rock processing from within Glibc.  It
- * might be useful to overrider fcntl() in the future. */
+ * might be useful to override fcntl() in the future. */
 int __fcntl(int fd, int cmd, ...)
 {
        int ret;
index 412618f..9f2ea48 100644 (file)
@@ -366,6 +366,19 @@ int _sock_lookup_listen_fd(int sock_fd, bool can_open)
        return _rock_open_listen_fd(r);
 }
 
+/* Used by fcntl for F_SETFL. */
+void _sock_mirror_fcntl(int sock_fd, int cmd, long arg)
+{
+       Rock *r = _sock_findrock(sock_fd, 0);
+
+       if (!r || r->domain == PF_UNIX)
+               return;
+       if (r->ctl_fd >= 0)
+               syscall(SYS_fcntl, r->ctl_fd, cmd, arg);
+       if (r->has_listen_fd)
+               syscall(SYS_fcntl, r->listen_fd, cmd, arg);
+}
+
 /* Given an FD, opens the FD with the name 'sibling' in the same directory.
  * e.g., you have a data, you open a ctl.  Don't use this with cloned FDs (i.e.
  * open clone, get a ctl back) until we fix 9p and fd2path.
index fa18861..74d2f70 100644 (file)
@@ -76,6 +76,7 @@ extern void _sock_ingetaddr(Rock *, struct sockaddr_in *, socklen_t *,
 extern int _sock_strip_opts(int type);
 extern int _sock_get_opts(int type);
 extern int _sock_lookup_listen_fd(int sock_fd, bool can_open);
+extern void _sock_mirror_fcntl(int sock_fd, int cmd, long arg);
 
 int get_sibling_fd(int fd, const char *sibling);
 int write_hex_to_fd(int fd, uint64_t num);