Print this page
4953763 Need way to configure NFS window sizes without changing system wide defaults
6216670 NFS server needs a bigger transmit buffer

@@ -17,20 +17,18 @@
  * information: Portions Copyright [yyyy] [name of copyright owner]
  *
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 /*
  * nfs_tbind.c, common part for nfsd and lockd.
  */
 
-#pragma ident   "%Z%%M% %I%     %E% SMI"
-
 #define PORTMAP
 
 #include <tiuser.h>
 #include <fcntl.h>
 #include <netconfig.h>

@@ -101,13 +99,13 @@
 static  int     recvucred(int);
 static  int     anonmlp(int);
 static  void    add_to_poll_list(int, struct netconfig *);
 static  char    *serv_name_to_port_name(char *);
 static  int     bind_to_proto(char *, char *, struct netbuf **,
-                                struct netconfig **);
+                                struct netconfig **, int, int);
 static  int     bind_to_provider(char *, char *, struct netbuf **,
-                                        struct netconfig **);
+                                struct netconfig **, int, int);
 static  void    conn_close_oldest(void);
 static  boolean_t conn_get(int, struct netconfig *, struct conn_ind **);
 static  void    cots_listen_event(int, int);
 static  int     discon_get(int, struct netconfig *, struct conn_ind **);
 static  int     do_poll_clts_action(int, int);

@@ -119,10 +117,11 @@
 static  struct pollfd *poll_array;
 static  struct conn_entry *conn_polled;
 static  int     num_conns;              /* Current number of connections */
 int             (*Mysvc4)(int, struct netbuf *, struct netconfig *, int,
                 struct netbuf *);
+static int      setopt(int fd, int level, int name, int value);
 
 extern bool_t __pmap_set(const rpcprog_t program, const rpcvers_t version,
     const struct netconfig *nconf, const struct netbuf *address);
 
 /*

@@ -238,13 +237,32 @@
         }
 
         return (0);
 }
 
+static int
+nfslib_set_sockbuf(int fd, int which, int val)
+{
+        if ((which != SO_RCVBUF) && (which != SO_SNDBUF))
+                return (-1);
+
+        syslog(LOG_DEBUG, "Set %s option to %d",
+            ((which == SO_RCVBUF) ? "SO_RCVBUF" : "SO_SNDBUF"), val);
+
+        if (setopt(fd, SOL_SOCKET, which, val) < 0) {
+                syslog(LOG_ERR, "couldn't set %s to %d - t_errno = %d",
+                    ((which == SO_RCVBUF) ? "SO_RCVBUF" : "SO_SNDBUF"),
+                    val, t_errno);
+                syslog(LOG_ERR, "Check and increase system-wide tcp_max_buf");
+                return (-1);
+        }
+        return (0);
+}
+
 int
 nfslib_bindit(struct netconfig *nconf, struct netbuf **addr,
-        struct nd_hostserv *hs, int backlog)
+        struct nd_hostserv *hs, int backlog, int sndbufsz, int rcvbufsz)
 {
         int fd;
         struct t_bind  *ntb;
         struct t_bind tb;
         struct nd_addrlist *addrlist;

@@ -400,10 +418,15 @@
                     resp.flags != T_SUCCESS) {
                         syslog(LOG_ERR,
         "couldn't set NODELAY option for proto %s: t_errno = %d, %m",
                             nconf->nc_proto, t_errno);
                 }
+
+                if (sndbufsz > 0)
+                        (void) nfslib_set_sockbuf(fd, SO_SNDBUF, sndbufsz);
+                if (rcvbufsz > 0)
+                        (void) nfslib_set_sockbuf(fd, SO_RCVBUF, rcvbufsz);
         }
 
         return (fd);
 }
 

@@ -475,15 +498,17 @@
         }
         errno = error;
 }
 
 /*
- * Called to set up service over a particular transport.
+ * Called to set up service over a particular transport also
+ * set send and receive buffer size for transport connection.
  */
 void
-do_one(char *provider, NETSELDECL(proto), struct protob *protobp0,
-        int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap)
+do_one_setbuf(char *provider, NETSELDECL(proto), struct protob *protobp0,
+        int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap,
+        int sndbufsz, int rcvbufsz)
 {
         register int sock;
         struct protob *protobp;
         struct netbuf *retaddr;
         struct netconfig *retnconf;

@@ -492,14 +517,14 @@
         int err;
         int l;
 
         if (provider)
                 sock = bind_to_provider(provider, protobp0->serv, &retaddr,
-                    &retnconf);
+                    &retnconf, sndbufsz, rcvbufsz);
         else
                 sock = bind_to_proto(proto, protobp0->serv, &retaddr,
-                    &retnconf);
+                    &retnconf, sndbufsz, rcvbufsz);
 
         if (sock == -1) {
                 (void) syslog(LOG_ERR,
         "Cannot establish %s service over %s: transport setup problem.",
                     protobp0->serv, provider ? provider : proto);

@@ -580,17 +605,20 @@
          * We successfully set up the server over this transport.
          * Add this descriptor to the one being polled on.
          */
         add_to_poll_list(sock, retnconf);
 }
+
 /*
- * Set up the NFS service over all the available transports.
+ * Set up the NFS service over all the available transports and
+ * also set send and receive buffer size for transport connection.
  * Returns -1 for failure, 0 for success.
  */
 int
-do_all(struct protob *protobp,
-        int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap)
+do_all_setbuf(struct protob *protobp,
+        int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap,
+        int sndbufsz, int rcvbufsz)
 {
         struct netconfig *nconf;
         NCONF_HANDLE *nc;
         int l;
 

@@ -603,18 +631,39 @@
                 if ((nconf->nc_flag & NC_VISIBLE) &&
                     strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 &&
                     OK_TPI_TYPE(nconf) &&
                     (protobp->program != NFS4_CALLBACK ||
                     strncasecmp(nconf->nc_proto, NC_UDP, l) != 0))
-                        do_one(nconf->nc_device, nconf->nc_proto,
-                            protobp, svc, use_pmap);
+                        do_one_setbuf(nconf->nc_device, nconf->nc_proto,
+                            protobp, svc, use_pmap, sndbufsz, rcvbufsz);
         }
         (void) endnetconfig(nc);
         return (0);
 }
 
 /*
+ * Called to set up service over a particular transport.
+ */
+void
+do_one(char *provider, NETSELDECL(proto), struct protob *protobp0,
+        int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap)
+{
+        do_one_setbuf(provider, proto, protobp0, svc, use_pmap, 0, 0);
+}
+
+/*
+ * Set up the NFS service over all the available transports.
+ * Returns -1 for failure, 0 for success.
+ */
+int
+do_all(struct protob *protobp,
+        int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap)
+{
+        return (do_all_setbuf(protobp, svc, use_pmap, 0, 0));
+}
+
+/*
  * poll on the open transport descriptors for events and errors.
  */
 void
 poll_for_action(void)
 {

@@ -1575,11 +1624,11 @@
         return ("unrecognized");
 }
 
 static int
 bind_to_provider(char *provider, char *serv, struct netbuf **addr,
-                struct netconfig **retnconf)
+                struct netconfig **retnconf, int sndbufsz, int rcvbufsz)
 {
         struct netconfig *nconf;
         NCONF_HANDLE *nc;
         struct nd_hostserv hs;
 

@@ -1593,11 +1642,11 @@
         while (nconf = getnetconfig(nc)) {
                 if (OK_TPI_TYPE(nconf) &&
                     strcmp(nconf->nc_device, provider) == 0) {
                         *retnconf = nconf;
                         return (nfslib_bindit(nconf, addr, &hs,
-                            listen_backlog));
+                            listen_backlog, sndbufsz, rcvbufsz));
                 }
         }
         (void) endnetconfig(nc);
 
         syslog(LOG_ERR, "couldn't find netconfig entry for provider %s",

@@ -1605,11 +1654,11 @@
         return (-1);
 }
 
 static int
 bind_to_proto(NETSELDECL(proto), char *serv, struct netbuf **addr,
-                struct netconfig **retnconf)
+                struct netconfig **retnconf, int sndbufsz, int rcvbufsz)
 {
         struct netconfig *nconf;
         NCONF_HANDLE *nc = NULL;
         struct nd_hostserv hs;
 

@@ -1622,11 +1671,11 @@
         }
         while (nconf = getnetconfig(nc)) {
                 if (OK_TPI_TYPE(nconf) && NETSELEQ(nconf->nc_proto, proto)) {
                         *retnconf = nconf;
                         return (nfslib_bindit(nconf, addr, &hs,
-                            listen_backlog));
+                            listen_backlog, sndbufsz, rcvbufsz));
                 }
         }
         (void) endnetconfig(nc);
 
         syslog(LOG_ERR, "couldn't find netconfig entry for protocol %s",