diff --git a/sys/fs/nfs/nfs.h b/sys/fs/nfs/nfs.h --- a/sys/fs/nfs/nfs.h +++ b/sys/fs/nfs/nfs.h @@ -156,7 +156,7 @@ (t).tv_sec = time.tv_sec; (t).tv_nsec = 1000 * time.tv_usec; } while (0) #define NFS_SRVMAXDATA(n) \ (((n)->nd_flag & (ND_NFSV3 | ND_NFSV4)) ? \ - NFS_SRVMAXIO : NFS_V2MAXDATA) + nfs_srvmaxio : NFS_V2MAXDATA) #define NFS64BITSSET 0xffffffffffffffffull #define NFS64BITSMINUS1 0xfffffffffffffffeull diff --git a/sys/fs/nfs/nfs_commonport.c b/sys/fs/nfs/nfs_commonport.c --- a/sys/fs/nfs/nfs_commonport.c +++ b/sys/fs/nfs/nfs_commonport.c @@ -76,6 +76,7 @@ void (*ncl_call_invalcaches)(struct vnode *) = NULL; vop_advlock_t *nfs_advlock_p = NULL; vop_reclaim_t *nfs_reclaim_p = NULL; +uint32_t nfs_srvmaxio = NFS_SRVMAXIO; int nfs_pnfsio(task_fn_t *, void *); @@ -303,11 +304,11 @@ if (isdgram) pref = NFS_MAXDGRAMDATA; else - pref = NFS_SRVMAXIO; - sip->fs_rtmax = NFS_SRVMAXIO; + pref = nfs_srvmaxio; + sip->fs_rtmax = nfs_srvmaxio; sip->fs_rtpref = pref; sip->fs_rtmult = NFS_FABLKSIZE; - sip->fs_wtmax = NFS_SRVMAXIO; + sip->fs_wtmax = nfs_srvmaxio; sip->fs_wtpref = pref; sip->fs_wtmult = NFS_FABLKSIZE; sip->fs_dtpref = pref; diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -85,6 +85,7 @@ extern int nfscl_debuglevel; extern struct nfsdevicehead nfsrv_devidhead; extern struct nfsstatsv1 nfsstatsv1; +extern uint32_t nfs_srvmaxio; SYSCTL_DECL(_vfs_nfs); SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW, @@ -2201,7 +2202,7 @@ NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); attrsum += NFSX_UNSIGNED; i = fxdr_unsigned(int, *tl); - if (compare && !(*retcmpp) && i != NFS_SRVMAXIO) + if (compare && !(*retcmpp) && i != nfs_srvmaxio) *retcmpp = NFSERR_NOTSAME; break; default: @@ -3012,7 +3013,7 @@ case NFSATTRBIT_LAYOUTALIGNMENT: case NFSATTRBIT_LAYOUTBLKSIZE: NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = txdr_unsigned(NFS_SRVMAXIO); + *tl = txdr_unsigned(nfs_srvmaxio); retnum += NFSX_UNSIGNED; break; case NFSATTRBIT_XATTRSUPPORT: diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h --- a/sys/fs/nfs/nfsproto.h +++ b/sys/fs/nfs/nfsproto.h @@ -73,7 +73,6 @@ */ #define NFS_MAXPKTHDR 404 #define NFS_MAXXDR 4096 -#define NFS_MAXPACKET (NFS_SRVMAXIO + NFS_MAXXDR) #define NFS_MINPACKET 20 #define NFS_FABLKSIZE 512 /* Size in bytes of a block wrt fa_blocks */ #define NFSV4_MINORVERSION 0 /* V4 Minor version */ diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -76,6 +76,9 @@ extern volatile int nfsrv_dontlistlen; extern volatile int nfsrv_devidcnt; extern int nfsrv_maxpnfsmirror; +extern uint32_t nfs_srvmaxio; +extern int nfs_bufpackets; +extern u_long sb_max_adj; struct vfsoptlist nfsv4root_opt, nfsv4root_newopt; NFSDLOCKMUTEX; NFSSTATESPINLOCK; @@ -195,6 +198,84 @@ CTLTYPE_UINT | CTLFLAG_MPSAFE | CTLFLAG_RW, 0, sizeof(nfsrv_dsdirsize), sysctl_dsdirsize, "IU", "Number of dsN subdirs on the DS servers"); +/* + * nfs_srvmaxio can only be increased and only when the nfsd threads are + * not running. The setting must be a power of 2, with the current limit of + * 1Mbyte. + */ +static int +sysctl_srvmaxio(SYSCTL_HANDLER_ARGS) +{ + int error; + u_int newsrvmaxio; + uint64_t tval; + + newsrvmaxio = nfs_srvmaxio; + error = sysctl_handle_int(oidp, &newsrvmaxio, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + if (newsrvmaxio == nfs_srvmaxio) + return (0); + if (newsrvmaxio < nfs_srvmaxio) { + printf("nfsd: vfs.nfsd.srvmaxio can only be increased\n"); + return (EINVAL); + } + if (newsrvmaxio > 1048576) { + printf("nfsd: vfs.nfsd.srvmaxio cannot be > 1Mbyte\n"); + return (EINVAL); + } + if ((newsrvmaxio & (newsrvmaxio - 1)) != 0) { + printf("nfsd: vfs.nfsd.srvmaxio must be a power of 2\n"); + return (EINVAL); + } + + /* + * Check that kern.ipc.maxsockbuf is large enough for + * newsrviomax, given the setting of vfs.nfs.bufpackets. + */ + if ((newsrvmaxio + NFS_MAXXDR) * nfs_bufpackets > + sb_max_adj) { + /* + * Suggest vfs.nfs.bufpackets * maximum RPC message for + * sb_max_adj. + */ + tval = (newsrvmaxio + NFS_MAXXDR) * nfs_bufpackets; + + /* + * Convert suggested sb_max_adj value to a suggested + * sb_max value, which is what is set via kern.ipc.maxsockbuf. + * Perform the inverse calculation of (from uipc_sockbuf.c): + * sb_max_adj = (u_quad_t)sb_max * MCLBYTES / + * (MSIZE + MCLBYTES); + * XXX If the calculation of sb_max_adj from sb_max changes, + * this calculation must be changed as well. + */ + tval *= (MSIZE + MCLBYTES); /* Brackets for readability. */ + tval += MCLBYTES - 1; /* Round up divide. */ + tval /= MCLBYTES; + printf("nfsd: set kern.ipc.maxsockbuf to a minimum of " + "%ju to support %ubyte NFS I/O\n", (uintmax_t)tval, + newsrvmaxio); + return (EINVAL); + } + + NFSD_LOCK(); + if (newnfs_numnfsd != 0) { + NFSD_UNLOCK(); + printf("nfsd: cannot set vfs.nfsd.srvmaxio when nfsd " + "threads are running\n"); + return (EINVAL); + } + + + nfs_srvmaxio = newsrvmaxio; + NFSD_UNLOCK(); + return (0); +} +SYSCTL_PROC(_vfs_nfsd, OID_AUTO, srvmaxio, + CTLTYPE_UINT | CTLFLAG_MPSAFE | CTLFLAG_RW, NULL, 0, + sysctl_srvmaxio, "IU", "Maximum I/O size in bytes"); + #define MAX_REORDERED_RPC 16 #define NUM_HEURISTIC 1031 #define NHUSE_INIT 64 diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c --- a/sys/fs/nfsserver/nfs_nfsdserv.c +++ b/sys/fs/nfsserver/nfs_nfsdserv.c @@ -66,6 +66,7 @@ extern int nfsrv_pnfsatime; extern int nfsrv_maxpnfsmirror; extern int nfs_maxcopyrange; +extern uint32_t nfs_srvmaxio; static int nfs_async = 0; SYSCTL_DECL(_vfs_nfsd); @@ -1023,7 +1024,7 @@ lop->lo_end = NFS64BITSSET; } - if (retlen > NFS_SRVMAXIO || retlen < 0) + if (retlen > nfs_srvmaxio || retlen < 0) nd->nd_repstat = EIO; if (vnode_vtype(vp) != VREG && !nd->nd_repstat) { if (nd->nd_flag & ND_NFSV3) @@ -4417,6 +4418,7 @@ struct nfsdsession *sep = NULL; uint32_t rdmacnt; struct thread *p = curthread; + static bool do_printf = true; if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) goto nfsmout; @@ -4438,12 +4440,16 @@ sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) { sep->sess_maxreq = sb_max_adj - NFS_MAXXDR; - printf("Consider increasing kern.ipc.maxsockbuf\n"); + if (do_printf) + printf("Consider increasing kern.ipc.maxsockbuf\n"); + do_printf = false; } sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) { sep->sess_maxresp = sb_max_adj - NFS_MAXXDR; - printf("Consider increasing kern.ipc.maxsockbuf\n"); + if (do_printf) + printf("Consider increasing kern.ipc.maxsockbuf\n"); + do_printf = false; } sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -42,6 +42,7 @@ time_t nfsdev_time = 0; int nfsrv_layouthashsize; volatile int nfsrv_layoutcnt = 0; +extern uint32_t nfs_srvmaxio; extern int newnfs_numnfsd; extern struct nfsstatsv1 nfsstatsv1; @@ -6898,7 +6899,7 @@ tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); /* Set the stripe size to the maximum I/O size. */ - *tl++ = txdr_unsigned(NFS_SRVMAXIO & NFSFLAYUTIL_STRIPE_MASK); + *tl++ = txdr_unsigned(nfs_srvmaxio & NFSFLAYUTIL_STRIPE_MASK); *tl++ = 0; /* 1st stripe index. */ pattern_offset = 0; txdr_hyper(pattern_offset, tl); tl += 2; /* Pattern offset. */ @@ -7964,13 +7965,13 @@ *tl++ = txdr_unsigned(2); /* Two NFS Versions. */ *tl++ = txdr_unsigned(NFS_VER4); /* NFSv4. */ *tl++ = txdr_unsigned(NFSV42_MINORVERSION); /* Minor version 2. */ - *tl++ = txdr_unsigned(NFS_SRVMAXIO); /* DS max rsize. */ - *tl++ = txdr_unsigned(NFS_SRVMAXIO); /* DS max wsize. */ + *tl++ = txdr_unsigned(nfs_srvmaxio); /* DS max rsize. */ + *tl++ = txdr_unsigned(nfs_srvmaxio); /* DS max wsize. */ *tl++ = newnfs_true; /* Tightly coupled. */ *tl++ = txdr_unsigned(NFS_VER4); /* NFSv4. */ *tl++ = txdr_unsigned(NFSV41_MINORVERSION); /* Minor version 1. */ - *tl++ = txdr_unsigned(NFS_SRVMAXIO); /* DS max rsize. */ - *tl++ = txdr_unsigned(NFS_SRVMAXIO); /* DS max wsize. */ + *tl++ = txdr_unsigned(nfs_srvmaxio); /* DS max rsize. */ + *tl++ = txdr_unsigned(nfs_srvmaxio); /* DS max wsize. */ *tl = newnfs_true; /* Tightly coupled. */ ds->nfsdev_hostnamelen = strlen(dnshost);