aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/fs/nfs/nfs_commonkrpc.c195
-rw-r--r--sys/fs/nfs/nfsport.h2
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c75
-rw-r--r--sys/fs/nfsclient/nfs_clvfsops.c124
-rw-r--r--sys/fs/nfsclient/nfsmount.h2
5 files changed, 304 insertions, 94 deletions
diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c
index 705e65d81d41..813005ed0cc4 100644
--- a/sys/fs/nfs/nfs_commonkrpc.c
+++ b/sys/fs/nfs/nfs_commonkrpc.c
@@ -261,7 +261,7 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp,
CLIENT *client;
struct netconfig *nconf;
struct socket *so;
- int one = 1, retries, error = 0;
+ int one = 1, retries, error = 0, val;
struct thread *td = curthread;
SVCXPRT *xprt;
struct timeval timo;
@@ -289,93 +289,101 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp,
td->td_ucred = cred;
saddr = nrp->nr_nam;
- if (saddr->sa_family == AF_INET)
- if (nrp->nr_sotype == SOCK_DGRAM)
+ if (saddr->sa_family == AF_INET) {
+ if (nmp != NULL && NFSHASRDMA(nmp))
+ nconf = getnetconfigent("rdma");
+ else if (nrp->nr_sotype == SOCK_DGRAM)
nconf = getnetconfigent("udp");
else
nconf = getnetconfigent("tcp");
- else
- if (nrp->nr_sotype == SOCK_DGRAM)
+ } else {
+ if (nmp != NULL && NFSHASRDMA(nmp))
+ nconf = getnetconfigent("rdma6");
+ else if (nrp->nr_sotype == SOCK_DGRAM)
nconf = getnetconfigent("udp6");
else
nconf = getnetconfigent("tcp6");
+ }
- pktscale = nfs_bufpackets;
- if (pktscale < 2)
- pktscale = 2;
- if (pktscale > 64)
- pktscale = 64;
- pktscalesav = pktscale;
- /*
- * soreserve() can fail if sb_max is too small, so shrink pktscale
- * and try again if there is an error.
- * Print a log message suggesting increasing sb_max.
- * Creating a socket and doing this is necessary since, if the
- * reservation sizes are too large and will make soreserve() fail,
- * the connection will work until a large send is attempted and
- * then it will loop in the krpc code.
- */
- so = NULL;
- saddr = NFSSOCKADDR(nrp->nr_nam, struct sockaddr *);
- error = socreate(saddr->sa_family, &so, nrp->nr_sotype,
- nrp->nr_soproto, td->td_ucred, td);
- if (error != 0)
- goto out;
- do {
- if (error != 0 && pktscale > 2) {
- if (nmp != NULL && nrp->nr_sotype == SOCK_STREAM &&
- pktscale == pktscalesav) {
- /*
- * Suggest vfs.nfs.bufpackets * maximum RPC message,
- * adjusted for the sb_max->sb_max_adj conversion of
- * MCLBYTES / (MSIZE + MCLBYTES) as the minimum setting
- * for kern.ipc.maxsockbuf.
- */
- tval = (NFS_MAXBSIZE + NFS_MAXXDR) * nfs_bufpackets;
- tval *= MSIZE + MCLBYTES;
- tval += MCLBYTES - 1; /* Round up divide by MCLBYTES. */
- tval /= MCLBYTES;
- printf("Consider increasing kern.ipc.maxsockbuf to a "
- "minimum of %ju to support %ubyte NFS I/O\n",
- (uintmax_t)tval, NFS_MAXBSIZE);
- }
- pktscale--;
- }
- if (nrp->nr_sotype == SOCK_DGRAM) {
- if (nmp != NULL) {
- sndreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) *
- pktscale;
- rcvreserve = (NFS_MAXDGRAMDATA + NFS_MAXPKTHDR) *
- pktscale;
- } else {
- sndreserve = rcvreserve = 1024 * pktscale;
- }
- } else {
- if (nrp->nr_sotype != SOCK_STREAM)
- panic("nfscon sotype");
- if (nmp != NULL) {
- sndreserve = (NFS_MAXBSIZE + NFS_MAXXDR) *
- pktscale;
- rcvreserve = (NFS_MAXBSIZE + NFS_MAXXDR) *
- pktscale;
- } else {
- sndreserve = rcvreserve = 1024 * pktscale;
- }
- }
- error = soreserve(so, sndreserve, rcvreserve);
- if (error != 0 && nmp != NULL && nrp->nr_sotype == SOCK_STREAM &&
- pktscale <= 2)
- printf("Must increase kern.ipc.maxsockbuf or reduce"
- " rsize, wsize\n");
- } while (error != 0 && pktscale > 2);
- soclose(so);
+ sndreserve = rcvreserve = 0;
+ if (nmp == NULL || !NFSHASRDMA(nmp)) {
+ pktscale = nfs_bufpackets;
+ if (pktscale < 2)
+ pktscale = 2;
+ if (pktscale > 64)
+ pktscale = 64;
+ pktscalesav = pktscale;
+ /*
+ * soreserve() can fail if sb_max is too small, so shrink
+ * pktscale and try again if there is an error.
+ * Print a log message suggesting increasing sb_max.
+ * Creating a socket and doing this is necessary since, if the
+ * reservation sizes are too large and will make soreserve()
+ * fail, the connection will work until a large send is
+ * attempted and then it will loop in the krpc code.
+ */
+ so = NULL;
+ saddr = NFSSOCKADDR(nrp->nr_nam, struct sockaddr *);
+ error = socreate(saddr->sa_family, &so, nrp->nr_sotype,
+ nrp->nr_soproto, td->td_ucred, td);
+ if (error != 0)
+ goto out;
+ do {
+ if (error != 0 && pktscale > 2) {
+ if (nmp != NULL && nrp->nr_sotype == SOCK_STREAM &&
+ pktscale == pktscalesav) {
+ /*
+ * Suggest vfs.nfs.bufpackets * maximum RPC message,
+ * adjusted for the sb_max->sb_max_adj conversion of
+ * MCLBYTES / (MSIZE + MCLBYTES) as the minimum
+ * setting for kern.ipc.maxsockbuf.
+ */
+ tval = (NFS_MAXBSIZE + NFS_MAXXDR) * nfs_bufpackets;
+ tval *= MSIZE + MCLBYTES;
+ tval += MCLBYTES - 1; /* Round up divide. */
+ tval /= MCLBYTES;
+ printf("Consider increasing kern.ipc.maxsockbuf to "
+ "a minimum of %ju to support %ubyte NFS I/O\n",
+ (uintmax_t)tval, NFS_MAXBSIZE);
+ }
+ pktscale--;
+ }
+ if (nrp->nr_sotype == SOCK_DGRAM) {
+ if (nmp != NULL) {
+ sndreserve = (NFS_MAXDGRAMDATA +
+ NFS_MAXPKTHDR) * pktscale;
+ rcvreserve = (NFS_MAXDGRAMDATA +
+ NFS_MAXPKTHDR) * pktscale;
+ } else {
+ sndreserve = rcvreserve = 1024 * pktscale;
+ }
+ } else {
+ if (nrp->nr_sotype != SOCK_STREAM)
+ panic("nfscon sotype");
+ if (nmp != NULL) {
+ sndreserve = (NFS_MAXBSIZE + NFS_MAXXDR) *
+ pktscale;
+ rcvreserve = (NFS_MAXBSIZE + NFS_MAXXDR) *
+ pktscale;
+ } else {
+ sndreserve = rcvreserve = 1024 * pktscale;
+ }
+ }
+ error = soreserve(so, sndreserve, rcvreserve);
+ if (error != 0 && nmp != NULL &&
+ nrp->nr_sotype == SOCK_STREAM && pktscale <= 2)
+ printf("Must increase kern.ipc.maxsockbuf or reduce"
+ " rsize, wsize\n");
+ } while (error != 0 && pktscale > 2);
+ soclose(so);
+ }
if (error != 0)
goto out;
client = clnt_reconnect_create(nconf, saddr, nrp->nr_prog,
nrp->nr_vers, sndreserve, rcvreserve);
CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq");
- if (nmp != NULL) {
+ if (nmp != NULL && !NFSHASRDMA(nmp)) {
if ((nmp->nm_flag & NFSMNT_INT))
CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
if ((nmp->nm_flag & NFSMNT_RESVPORT))
@@ -466,7 +474,7 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp,
retries = nfs_dsretries;
}
}
- } else {
+ } else if (nmp == NULL) {
/*
* Three cases:
* - Null RPC callback to client
@@ -481,6 +489,41 @@ newnfs_connect(struct nfsmount *nmp, struct nfssockreq *nrp,
}
if (dotls)
CLNT_CONTROL(client, CLSET_TLS, &one);
+ } else {
+ /* RDMA. */
+ if (NFSHASNFSV4N(nmp) && cred != NULL) {
+ /*
+ * Set up the backchannel. svc_vc_create_backchannel()
+ * is sufficient. The rdma boolean in conn_cf will get
+ * set by the CLSET_BACKCHANNEL control.
+ */
+ /*
+ * Make sure the nfscbd_pool doesn't get
+ * destroyed while doing this.
+ */
+ NFSD_LOCK();
+ if (nfs_numnfscbd > 0) {
+ nfs_numnfscbd++;
+ NFSD_UNLOCK();
+ xprt = svc_vc_create_backchannel(nfscbd_pool);
+ CLNT_CONTROL(client, CLSET_BACKCHANNEL, xprt);
+ NFSD_LOCK();
+ nfs_numnfscbd--;
+ if (nfs_numnfscbd == 0)
+ wakeup(&nfs_numnfscbd);
+ }
+ NFSD_UNLOCK();
+ }
+
+ /* Set the small reply size for a Readdir. */
+ val = NFS_DIRBLKSIZ + PAGE_SIZE;
+ CLNT_CONTROL(client, CLSET_RDMASMALL_REPLY, &val);
+ val = NFSV4_CBSLOTS;
+ CLNT_CONTROL(client, CLSET_RDMA_CBSLOTS, &val);
+ if (NFSHASSOFT(nmp))
+ retries = nmp->nm_retry;
+ else
+ retries = INT_MAX;
}
CLNT_CONTROL(client, CLSET_RETRIES, &retries);
diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h
index 91345bde3441..cd50d12dbe5f 100644
--- a/sys/fs/nfs/nfsport.h
+++ b/sys/fs/nfs/nfsport.h
@@ -1065,6 +1065,8 @@ void ncl_copy_vattr(struct vnode *vp, struct vattr *dst, struct vattr *src);
(n)->nm_minorvers > 0)
#define NFSHASTLS(n) (((n)->nm_newflag & NFSMNT_TLS) != 0)
#define NFSHASSYSKRB5(n) (((n)->nm_newflag & NFSMNT_SYSKRB5) != 0)
+#define NFSHASRDMA(n) (((n)->nm_newflag & NFSMNT_RDMA) != 0)
+#define NFSHASNOWRITEREDUCE(n) (((n)->nm_newflag & NFSMNT_NOWRITEREDUCE) != 0)
/*
* Set boottime.
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 7984737a2f65..6e84567649d7 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -49,6 +49,7 @@
#include <sys/extattr.h>
#include <sys/sysctl.h>
#include <sys/taskqueue.h>
+#include <rpc/clntrdma.h>
SYSCTL_DECL(_vfs_nfs);
@@ -236,6 +237,8 @@ static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *,
int, struct nfsvattr *, int *, struct ucred *);
static struct mbuf *nfsm_split(struct mbuf *, uint64_t);
static void nfscl_statfs(struct vnode *, struct ucred *, NFSPROC_T *);
+static struct mbuf *nfsm_build_rdma_reduction(struct nfsrv_descript *nd,
+ int len, int pos, bool to_mem);
int nfs_pnfsio(task_fn_t *, void *);
@@ -1692,11 +1695,16 @@ nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
u_int32_t *tl;
struct nfsrv_descript nfsd, *nd = &nfsd;
struct nfsnode *np = VTONFS(vp);
+ struct nfsmount *nmp;
nfsattrbit_t attrbits;
int error, len, cangetattr = 1;
*attrflagp = 0;
+ nmp = VFSTONFS(vp->v_mount);
NFSCL_REQSTART(nd, NFSPROC_READLINK, vp, cred);
+ /* For RDMA, mark that a one page rdma_reply is required. */
+ if (NFSHASRDMA(nmp))
+ nd->nd_mreq->m_flags |= M_PROTO7;
if (nd->nd_flag & ND_NFSV4) {
/*
* And do a Getattr op.
@@ -1817,13 +1825,18 @@ nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
u_int32_t *tl;
int error = 0, len, retlen, tsiz, eof = 0;
struct nfsrv_descript nfsd;
+ struct mbuf *mr;
struct nfsmount *nmp = VFSTONFS(vp->v_mount);
struct nfsrv_descript *nd = &nfsd;
int rsize;
off_t tmp_off;
+ bool did_rdma;
*attrflagp = 0;
tsiz = uiop->uio_resid;
+ did_rdma = false;
+ if (NFSHASRDMA(nmp) && tsiz > RPCRDMA_MAX_SMALL_MSG / 2)
+ did_rdma = true;
tmp_off = uiop->uio_offset + tsiz;
NFSLOCKMNT(nmp);
if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
@@ -1848,6 +1861,9 @@ nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
txdr_hyper(uiop->uio_offset, tl);
*(tl + 2) = txdr_unsigned(len);
}
+ /* For RDMA, make the data a separate chunk. */
+ if (did_rdma)
+ mr = nfsm_build_rdma_reduction(nd, len, 0, true);
/*
* Since I can't do a Getattr for NFSv4 for Write, there
* doesn't seem any point in doing one here, either.
@@ -1876,7 +1892,12 @@ nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
eof = fxdr_unsigned(int, *tl);
}
NFSM_STRSIZ(retlen, len);
- error = nfsm_mbufuio(nd, uiop, retlen);
+ if (!did_rdma) {
+ error = nfsm_mbufuio(nd, uiop, retlen);
+ } else {
+ error = rpc_copy_uio_pages(mr, uiop, retlen, true);
+ rpc_free_rdma_reduction(mr);
+ }
if (error)
goto nfsmout;
m_freem(nd->nd_mrep);
@@ -1998,14 +2019,18 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
int wccflag = 0;
int32_t backup;
struct nfsrv_descript *nd;
+ struct mbuf *mr;
nfsattrbit_t attrbits;
uint64_t tmp_off;
ssize_t tsiz, wsize;
- bool do_append;
+ bool do_append, did_rdma;
KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
*attrflagp = 0;
tsiz = uiop->uio_resid;
+ did_rdma = false;
+ if (NFSHASRDMA(nmp) && tsiz > RPCRDMA_MAX_SMALL_MSG / 2)
+ did_rdma = true;
tmp_off = uiop->uio_offset + tsiz;
NFSLOCKMNT(nmp);
if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
@@ -2069,7 +2094,16 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
*tl++ = x; /* total to this offset */
*tl = x; /* size of this write */
}
- error = nfsm_uiombuf(nd, uiop, len);
+ /* For RDMA, make the data a separate chunk. */
+ if (did_rdma && !NFSHASNOWRITEREDUCE(nmp)) {
+ rlen = m_length(nd->nd_mreq, NULL);
+ mr = nfsm_build_rdma_reduction(nd, len, rlen, false);
+ error = rpc_copy_uio_pages(mr, uiop, len, false);
+ if (error)
+ rpc_free_rdma_reduction(mr);
+ } else {
+ error = nfsm_uiombuf(nd, uiop, len);
+ }
if (error != 0) {
m_freem(nd->nd_mreq);
free(nd, M_TEMP);
@@ -2106,6 +2140,8 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
free(nd, M_TEMP);
return (error);
}
+ if (did_rdma && !NFSHASNOWRITEREDUCE(nmp))
+ rpc_free_rdma_reduction(mr);
if (nd->nd_repstat) {
/*
* In case the rpc gets retried, roll
@@ -3631,6 +3667,9 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
while (more_dirs && bigenough) {
*attrflagp = 0;
NFSCL_REQSTART(nd, NFSPROC_READDIR, vp, cred);
+ /* For RDMA, mark that a rdma_reply is needed. */
+ if (NFSHASRDMA(nmp))
+ nd->nd_mreq->m_flags |= M_PROTO8;
if (nd->nd_flag & ND_NFSV2) {
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
*tl++ = cookie.lval[1];
@@ -4122,6 +4161,9 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
while (more_dirs && bigenough) {
*attrflagp = 0;
NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp, cred);
+ /* For RDMA, mark that a small rdma_reply is needed. */
+ if (NFSHASRDMA(nmp))
+ nd->nd_mreq->m_flags |= M_PROTO8;
NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
*tl++ = cookie.lval[0];
*tl++ = cookie.lval[1];
@@ -5372,6 +5414,9 @@ nfsrpc_getacl(struct vnode *vp, acl_type_t acltype, struct ucred *cred,
(acltype == ACL_TYPE_ACCESS || acltype == ACL_TYPE_DEFAULT))
return (EOPNOTSUPP);
NFSCL_REQSTART(nd, NFSPROC_GETACL, vp, cred);
+ /* For RDMA, mark that a large rdma_reply is required. */
+ if (NFSHASRDMA(nmp))
+ nd->nd_mreq->m_flags |= M_PROTO9;
NFSZERO_ATTRBIT(&attrbits);
if (acltype == ACL_TYPE_NFS4)
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
@@ -9581,6 +9626,9 @@ nfsrpc_getextattr(vnode_t vp, const char *name, struct uio *uiop, ssize_t *lenp,
*attrflagp = 0;
NFSCL_REQSTART(nd, NFSPROC_GETEXTATTR, vp, cred);
+ /* For RDMA, mark that a large rdma_reply is required. */
+ if (NFSHASRDMA(VFSTONFS(vp->v_mount)))
+ nd->nd_mreq->m_flags |= M_PROTO9;
nfsm_strtom(nd, name, strlen(name));
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_GETATTR);
@@ -10047,3 +10095,24 @@ nfscl_statfs(struct vnode *vp, struct ucred *cred, NFSPROC_T *td)
mtx_unlock(&nmp->nm_mtx);
}
}
+
+/*
+ * Set up the RDMA reduction mbuf in the build list.
+ */
+static struct mbuf *
+nfsm_build_rdma_reduction(struct nfsrv_descript *nd, int len, int pos,
+ bool to_mem)
+{
+ struct mbuf *m, *mr;
+
+ mr = rpc_reduce_pg(len, pos, to_mem);
+ nd->nd_mb->m_next = mr;
+ nd->nd_mb = mr;
+ NFSMCLGET(m, M_NOWAIT);
+ m->m_len = 0;
+ nd->nd_bpos = mtod(m, char *);
+ nd->nd_mb->m_next = m;
+ nd->nd_mb = m;
+ nd->nd_mreq->m_flags |= M_PROTO11;
+ return (mr);
+}
diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c
index 74e5e2dc9b1b..e057324f1f20 100644
--- a/sys/fs/nfsclient/nfs_clvfsops.c
+++ b/sys/fs/nfsclient/nfs_clvfsops.c
@@ -38,6 +38,8 @@
#include "opt_bootp.h"
#include "opt_nfsroot.h"
#include "opt_kern_tls.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -74,6 +76,7 @@
#include <fs/nfsclient/nfs.h>
#include <nfs/nfsdiskless.h>
+#include <rpc/krpc.h>
#include <rpc/rpcsec_tls.h>
FEATURE(nfscl, "NFSv4 client");
@@ -87,6 +90,7 @@ extern struct nfsmount *ncl_iodmount[NFS_MAXASYNCDAEMON];
extern struct mtx ncl_iod_mutex;
NFSCLSTATEMUTEX;
extern struct mtx nfsrv_dslock_mtx;
+extern int newnfs_directio_enable;
MALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "NFS request header");
MALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "NFS mount struct");
@@ -192,6 +196,7 @@ int
newnfs_iosize(struct nfsmount *nmp)
{
int iosize, maxio;
+ uint32_t rdma_maxio;
/* First, set the upper limit for iosize */
if (nmp->nm_flag & NFSMNT_NFSV4) {
@@ -204,6 +209,15 @@ newnfs_iosize(struct nfsmount *nmp)
} else {
maxio = NFS_V2MAXDATA;
}
+
+ /* For an RDMA mount, find out what the RDMA's limit is. */
+ if (NFSHASRDMA(nmp) && nmp->nm_sockreq.nr_client != NULL) {
+ CLNT_CONTROL(nmp->nm_sockreq.nr_client, CLGET_RDMAMAX_IO,
+ &rdma_maxio);
+ if (rdma_maxio > 0)
+ maxio = MIN(maxio, rdma_maxio);
+ }
+
if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0)
nmp->nm_rsize = maxio;
if (nmp->nm_rsize > NFS_MAXBSIZE)
@@ -228,6 +242,11 @@ newnfs_iosize(struct nfsmount *nmp)
iosize = imax(iosize, PAGE_SIZE);
iosize = imax(iosize, NFS_DIRBLKSIZ);
nmp->nm_mountp->mnt_stat.f_iosize = iosize;
+ if (NFSHASRDMA(nmp) && nmp->nm_sockreq.nr_client != NULL) {
+ rdma_maxio = iosize;
+ CLNT_CONTROL(nmp->nm_sockreq.nr_client, CLSET_RDMAMAX_IO,
+ &rdma_maxio);
+ }
return (iosize);
}
@@ -788,7 +807,7 @@ static const char *nfs_opts[] = { "from", "nfs_args",
"nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath",
"minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr",
"pnfs", "wcommitsize", "oneopenown", "tls", "tlscertname", "nconnect",
- "syskrb5", NULL };
+ "syskrb5", "rdma", "nowritereduce", NULL };
/*
* Parse the "from" mountarg, passed by the generic mount(8) program
@@ -939,7 +958,7 @@ nfs_mount(struct mount *mp)
krbnamelen, srvkrbnamelen;
size_t hstlen;
uint32_t newflag;
- int aconn = 0;
+ int aconn = 0, rdma_port;
has_nfs_args_opt = 0;
has_nfs_from_opt = 0;
@@ -1031,6 +1050,8 @@ nfs_mount(struct mount *mp)
args.flags |= NFSMNT_ONEOPENOWN;
if (vfs_getopt(mp->mnt_optnew, "tls", NULL, NULL) == 0)
newflag |= NFSMNT_TLS;
+ if (vfs_getopt(mp->mnt_optnew, "nowritereduce", NULL, NULL) == 0)
+ newflag |= NFSMNT_NOWRITEREDUCE;
if (vfs_getopt(mp->mnt_optnew, "tlscertname", (void **)&opt, &len) ==
0) {
/*
@@ -1247,6 +1268,27 @@ nfs_mount(struct mount *mp)
}
if (vfs_getopt(mp->mnt_optnew, "syskrb5", NULL, NULL) == 0)
newflag |= NFSMNT_SYSKRB5;
+ if (vfs_getopt(mp->mnt_optnew, "rdma", (void **)&opt, NULL) ==
+ 0) {
+ ret = sscanf(opt, "%d", &rdma_port);
+ if (ret != 1 || rdma_port < 1 || rdma_port > IPPORT_MAX) {
+ vfs_mount_error(mp, "Bad RDMA port#: %s", opt);
+ error = EINVAL;
+ goto out;
+ }
+ if (PMAP_HAS_DMAP == 0) {
+ vfs_mount_error(mp, "RDMA requires a DMAP");
+ error = EINVAL;
+ goto out;
+ }
+ if (clnt_rdma_create_call == NULL) {
+ vfs_mount_error(mp, "RDMA requires the nfsclrdma.ko "
+ "module be loaded");
+ error = EINVAL;
+ goto out;
+ }
+ newflag |= NFSMNT_RDMA;
+ }
if (vfs_getopt(mp->mnt_optnew, "sec",
(void **) &secname, NULL) == 0)
nfs_sec_name(secname, &args.flags);
@@ -1414,19 +1456,26 @@ nfs_mount(struct mount *mp)
}
}
- if (aconn > 0 && (args.sotype != SOCK_STREAM ||
- (args.flags & NFSMNT_NFSV4) == 0 || minvers == 0)) {
- /*
- * RFC 5661 requires that an NFSv4.1/4.2 server
- * send an RPC reply on the same TCP connection
- * as the one it received the request on.
- * This property in required for "nconnect" and
- * might not be the case for NFSv3 or NFSv4.0 servers.
- */
- vfs_mount_error(mp, "nconnect should only be used "
- "for NFSv4.1/4.2 mounts");
- error = EINVAL;
- goto out;
+ if (aconn > 0) {
+ if (args.sotype != SOCK_STREAM ||
+ (args.flags & NFSMNT_NFSV4) == 0 || minvers == 0) {
+ /*
+ * RFC 5661 requires that an NFSv4.1/4.2 server
+ * send an RPC reply on the same TCP connection
+ * as the one it received the request on.
+ * This property in required for "nconnect" and
+ * might not be the case for NFSv3 or NFSv4.0 servers.
+ */
+ vfs_mount_error(mp, "nconnect should only be used "
+ "for NFSv4.1/4.2 mounts");
+ error = EINVAL;
+ goto out;
+ } else if ((newflag & NFSMNT_RDMA) != 0) {
+ vfs_mount_error(mp, "nconnect cannot be used "
+ "for RDMA mounts");
+ error = EINVAL;
+ goto out;
+ }
}
if ((newflag & NFSMNT_SYSKRB5) != 0 &&
@@ -1462,6 +1511,47 @@ nfs_mount(struct mount *mp)
goto out;
}
+ if ((newflag & NFSMNT_RDMA) != 0) {
+#ifdef INET
+ struct sockaddr_in *sin;
+#endif
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
+
+ if (rdma_check_route == NULL) {
+ vfs_mount_error(mp, "nfsclrdma module not loaded");
+ error = EINVAL;
+ goto out;
+ }
+
+ /* Replace the NFS port# with the NFS RDMA one. */
+ switch (nam->sa_family) {
+#ifdef INET
+ case AF_INET:
+ sin = (struct sockaddr_in *)nam;
+ sin->sin_port = htons(rdma_port);
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)nam;
+ sin6->sin6_port = htons(rdma_port);
+ break;
+#endif
+ default:
+ vfs_mount_error(mp, "rdma address not inet/inet6");
+ error = EINVAL;
+ goto out;
+ }
+ error = rdma_check_route(vnet0, nam, NFSV4_CBSLOTS);
+ if (error != 0) {
+ vfs_mount_error(mp, "rdma is not configured");
+ error = EINVAL;
+ goto out;
+ }
+ }
+
args.fh = nfh;
error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
@@ -2238,6 +2328,10 @@ void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen)
&blen);
nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_SYSKRB5) != 0,
",syskrb5", &buf, &blen);
+ nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_RDMA) != 0,
+ ",rdma", &buf, &blen);
+ nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_NOWRITEREDUCE) != 0,
+ ",nowritereduce", &buf, &blen);
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
&buf, &blen);
nfscl_printoptval(nmp, nmp->nm_aconnect + 1, ",nconnect", &buf, &blen);
diff --git a/sys/fs/nfsclient/nfsmount.h b/sys/fs/nfsclient/nfsmount.h
index ef876dd30e59..800aaeb7f46d 100644
--- a/sys/fs/nfsclient/nfsmount.h
+++ b/sys/fs/nfsclient/nfsmount.h
@@ -129,6 +129,8 @@ struct nfsmount {
/* New mount flags only used by the kernel via nmount(2). */
#define NFSMNT_TLS 0x00000001
#define NFSMNT_SYSKRB5 0x00000002
+#define NFSMNT_RDMA 0x00000004
+#define NFSMNT_NOWRITEREDUCE 0x00000008
#define NFSMNT_DIRPATH(m) (&((m)->nm_name[(m)->nm_krbnamelen + 1]))
#define NFSMNT_SRVKRBNAME(m) \