Linux: Use kernel network helper functions
authorSimon Wilkinson <sxw@inf.ed.ac.uk>
Fri, 23 Apr 2010 17:03:49 +0000 (18:03 +0100)
committerDerrick Brashear <shadow@dementia.org>
Mon, 26 Apr 2010 04:09:20 +0000 (21:09 -0700)
Linux has various network helper functions available, which are
guaranteed to do the right thing in terms of setting address space
limits, not dereferencing NULL pointers, and the like. Use these, where
they're available, rather than rolling our own.

kernel_sendmsg and kernel_recvmsg appeared in 2.6.8.

Change-Id: I1cd91afd2182ad936756bbc4cf692262499c16e4
Reviewed-on: http://gerrit.openafs.org/1822
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

acinclude.m4
src/afs/LINUX/osi_compat.h
src/cf/linux-test4.m4
src/rx/LINUX/rx_knet.c

index 14f10e8..88be3f5 100644 (file)
@@ -816,6 +816,7 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*)
                 LINUX_HAVE_PAGE_OFFSET
                 LINUX_HAVE_ZERO_USER_SEGMENTS
                 LINUX_HAVE_VFS_LLSEEK
+                LINUX_HAVE_KERNEL_SETSOCKOPT
                  LINUX_STRUCT_TASK_HAS_CRED
                 LINUX_STRUCT_PROC_DIR_ENTRY_HAS_OWNER
                 LINUX_HAVE_KMEM_CACHE_T
index e507e6b..efdd13b 100644 (file)
@@ -239,3 +239,34 @@ vfs_llseek(struct file *filp, loff_t offset, int origin) {
 }
 #endif
 
+#ifndef HAVE_KERNEL_SETSOCKOPT
+/* Available from 2.6.19 */
+
+static inline int
+kernel_setsockopt(struct socket *sockp, int level, int name, char *val,
+                 unsigned int len) {
+    mm_segment_t old_fs = get_fs();
+    int ret;
+
+    set_fs(get_ds());
+    ret = sockp->ops->setsockopt(sockp, level, name, val, len);
+    set_fs(old_fs);
+
+    return ret;
+}
+
+static inline int
+kernel_getsockopt(struct socket *sockp, int level, int name, char *val,
+                 int *len) {
+    mm_segment_t old_fs = get_fs();
+    int ret;
+
+    set_fs(get_ds());
+    ret = sockp->ops->setsockopt(sockp, level, name, val, len);
+    set_fs(old_fs);
+
+    return ret;
+}
+
+#endif
+
index 8d0a00f..e442ee1 100644 (file)
@@ -1270,3 +1270,16 @@ AC_DEFUN([LINUX_HAVE_VFS_LLSEEK], [
     AC_DEFINE([HAVE_VFS_LLSEEK], 1, [define if your kernel has the vfs_llseek function])
   fi])
 
+AC_DEFUN([LINUX_HAVE_KERNEL_SETSOCKOPT], [
+  AC_MSG_CHECKING([for kernel_setsockopt])
+  AC_CACHE_VAL([ac_cv_linux_have_kernel_setsockopt], [
+    AC_TRY_KBUILD(
+[#include <linux/net.h>],
+[kernel_setsockopt(NULL, 0, 0, NULL, 0);],
+      ac_cv_linux_have_kernel_setsockopt=yes,
+      ac_cv_linux_have_kernel_setsockopt=no)])
+  AC_MSG_RESULT($ac_cv_linux_have_kernel_setsockopt)
+  if test "x$ac_cv_linux_have_kernel_setsockopt" = "xyes"; then
+    AC_DEFINE([HAVE_KERNEL_SETSOCKOPT], 1, [define if your kernel has the kernel_setsockopt function])
+  fi])
+
index d670a83..bfe7c07 100644 (file)
@@ -34,7 +34,6 @@ rxk_NewSocketHost(afs_uint32 ahost, short aport)
     struct socket *sockp;
     struct sockaddr_in myaddr;
     int code;
-    KERNEL_SPACE_DECL;
 #ifdef ADAPT_PMTU
     int pmtu = IP_PMTUDISC_WANT;
     int do_recverr = 1;
@@ -65,14 +64,12 @@ rxk_NewSocketHost(afs_uint32 ahost, short aport)
        return NULL;
     }
 
-    TO_USER_SPACE();
-    sockp->ops->setsockopt(sockp, SOL_IP, IP_MTU_DISCOVER, (char *)&pmtu,
-                           sizeof(pmtu));
+    kernel_setsockopt(sockp, SOL_IP, IP_MTU_DISCOVER, (char *)&pmtu,
+                     sizeof(pmtu));
 #ifdef ADAPT_PMTU
-    sockp->ops->setsockopt(sockp, SOL_IP, IP_RECVERR, (char *)&do_recverr,
-                           sizeof(do_recverr));
+    kernel_setsockopt(sockp, SOL_IP, IP_RECVERR, (char *)&do_recverr,
+                      sizeof(do_recverr));
 #endif
-    TO_KERNEL_SPACE();
     return (osi_socket *)sockp;
 }
 
@@ -94,7 +91,6 @@ rxk_FreeSocket(struct socket *asocket)
 void
 handle_socket_error(osi_socket so)
 {
-    KERNEL_SPACE_DECL;
     struct msghdr msg;
     struct cmsghdr *cmsg;
     struct sock_extended_err *err;
@@ -108,15 +104,12 @@ handle_socket_error(osi_socket so)
        return;
     msg.msg_name = &addr;
     msg.msg_namelen = sizeof(addr);
-    msg.msg_iov = NULL;
-    msg.msg_iovlen = 0;
     msg.msg_control = controlmsgbuf;
     msg.msg_controllen = 256;
     msg.msg_flags = 0;
 
-    TO_USER_SPACE();
-    code = sock_recvmsg(sop, &msg, 256, MSG_ERRQUEUE|MSG_DONTWAIT|MSG_TRUNC);
-    TO_KERNEL_SPACE();
+    code = kernel_recvmsg(sop, &msg, NULL, 0, 256,
+                         MSG_ERRQUEUE|MSG_DONTWAIT|MSG_TRUNC);
 
     if (code < 0 || !(msg.msg_flags & MSG_ERRQUEUE))
        goto out;
@@ -160,7 +153,6 @@ int
 osi_NetSend(osi_socket sop, struct sockaddr_in *to, struct iovec *iovec,
            int iovcnt, afs_int32 size, int istack)
 {
-    KERNEL_SPACE_DECL;
     struct msghdr msg;
     int code;
 #ifdef ADAPT_PMTU
@@ -170,27 +162,20 @@ osi_NetSend(osi_socket sop, struct sockaddr_in *to, struct iovec *iovec,
     while (1) {
        sockerr=0;
        esize = sizeof(sockerr);
-       TO_USER_SPACE();
-       sop->ops->getsockopt(sop, SOL_SOCKET, SO_ERROR, (char *)&sockerr,
-                          &esize);
-       TO_KERNEL_SPACE();
+       kernel_getsockopt(sop, SOL_SOCKET, SO_ERROR, (char *)&sockerr, &esize);
        if (sockerr == 0)
           break;
        handle_socket_error(sop);
     }
 #endif
 
-    msg.msg_iovlen = iovcnt;
-    msg.msg_iov = iovec;
     msg.msg_name = to;
     msg.msg_namelen = sizeof(*to);
     msg.msg_control = NULL;
     msg.msg_controllen = 0;
     msg.msg_flags = 0;
 
-    TO_USER_SPACE();
-    code = sock_sendmsg(sop, &msg, size);
-    TO_KERNEL_SPACE();
+    code = kernel_sendmsg(sop, &msg, (struct kvec *) iovec, iovcnt, size);
     return (code < 0) ? code : 0;
 }
 
@@ -220,7 +205,6 @@ int
 osi_NetReceive(osi_socket so, struct sockaddr_in *from, struct iovec *iov,
               int iovcnt, int *lengthp)
 {
-    KERNEL_SPACE_DECL;
     struct msghdr msg;
     int code;
 #ifdef ADAPT_PMTU
@@ -237,10 +221,7 @@ osi_NetReceive(osi_socket so, struct sockaddr_in *from, struct iovec *iov,
     while (1) {
        sockerr=0;
        esize = sizeof(sockerr);
-       TO_USER_SPACE();
-       sop->ops->getsockopt(sop, SOL_SOCKET, SO_ERROR, (char *)&sockerr,
-                          &esize);
-       TO_KERNEL_SPACE();
+       kernel_getsockopt(sop, SOL_SOCKET, SO_ERROR, (char *)&sockerr, &esize);
        if (sockerr == 0)
           break;
        handle_socket_error(so);
@@ -254,10 +235,8 @@ osi_NetReceive(osi_socket so, struct sockaddr_in *from, struct iovec *iov,
     msg.msg_controllen = 0;
     msg.msg_flags = 0;
 
-    TO_USER_SPACE();
-    code = sock_recvmsg(sop, &msg, *lengthp, 0);
-    TO_KERNEL_SPACE();
-
+    code = kernel_recvmsg(sop, &msg, (struct kvec *)tmpvec, iovcnt,
+                         *lengthp, 0);
     if (code < 0) {
 #ifdef CONFIG_PM
        if (