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",