xref: /netbsd-src/sys/nfs/nfs_srvsocket.c (revision 481d3881954fd794ca5f2d880b68c53a5db8620e)
1*481d3881Srin /*	$NetBSD: nfs_srvsocket.c,v 1.6 2024/07/05 04:31:54 rin Exp $	*/
292ce8c6aSad 
392ce8c6aSad /*
492ce8c6aSad  * Copyright (c) 1989, 1991, 1993, 1995
592ce8c6aSad  *	The Regents of the University of California.  All rights reserved.
692ce8c6aSad  *
792ce8c6aSad  * This code is derived from software contributed to Berkeley by
892ce8c6aSad  * Rick Macklem at The University of Guelph.
992ce8c6aSad  *
1092ce8c6aSad  * Redistribution and use in source and binary forms, with or without
1192ce8c6aSad  * modification, are permitted provided that the following conditions
1292ce8c6aSad  * are met:
1392ce8c6aSad  * 1. Redistributions of source code must retain the above copyright
1492ce8c6aSad  *    notice, this list of conditions and the following disclaimer.
1592ce8c6aSad  * 2. Redistributions in binary form must reproduce the above copyright
1692ce8c6aSad  *    notice, this list of conditions and the following disclaimer in the
1792ce8c6aSad  *    documentation and/or other materials provided with the distribution.
1892ce8c6aSad  * 3. Neither the name of the University nor the names of its contributors
1992ce8c6aSad  *    may be used to endorse or promote products derived from this software
2092ce8c6aSad  *    without specific prior written permission.
2192ce8c6aSad  *
2292ce8c6aSad  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2392ce8c6aSad  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2492ce8c6aSad  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2592ce8c6aSad  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2692ce8c6aSad  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2792ce8c6aSad  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2892ce8c6aSad  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2992ce8c6aSad  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3092ce8c6aSad  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3192ce8c6aSad  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3292ce8c6aSad  * SUCH DAMAGE.
3392ce8c6aSad  *
3492ce8c6aSad  *	@(#)nfs_socket.c	8.5 (Berkeley) 3/30/95
3592ce8c6aSad  */
3692ce8c6aSad 
3792ce8c6aSad /*
3892ce8c6aSad  * Socket operations for use by nfs
3992ce8c6aSad  */
4092ce8c6aSad 
4192ce8c6aSad #include <sys/cdefs.h>
42*481d3881Srin __KERNEL_RCSID(0, "$NetBSD: nfs_srvsocket.c,v 1.6 2024/07/05 04:31:54 rin Exp $");
4392ce8c6aSad 
4492ce8c6aSad #include <sys/param.h>
4592ce8c6aSad #include <sys/systm.h>
4692ce8c6aSad #include <sys/evcnt.h>
4792ce8c6aSad #include <sys/callout.h>
4892ce8c6aSad #include <sys/proc.h>
4992ce8c6aSad #include <sys/mount.h>
5092ce8c6aSad #include <sys/kernel.h>
5192ce8c6aSad #include <sys/kmem.h>
5292ce8c6aSad #include <sys/mbuf.h>
5392ce8c6aSad #include <sys/vnode.h>
5492ce8c6aSad #include <sys/domain.h>
5592ce8c6aSad #include <sys/protosw.h>
5692ce8c6aSad #include <sys/socket.h>
5792ce8c6aSad #include <sys/socketvar.h>
5892ce8c6aSad #include <sys/syslog.h>
5992ce8c6aSad #include <sys/tprintf.h>
6092ce8c6aSad #include <sys/namei.h>
6192ce8c6aSad #include <sys/signal.h>
6292ce8c6aSad #include <sys/signalvar.h>
6392ce8c6aSad #include <sys/kauth.h>
6492ce8c6aSad 
6592ce8c6aSad #include <netinet/in.h>
6692ce8c6aSad #include <netinet/tcp.h>
6792ce8c6aSad 
6892ce8c6aSad #include <nfs/rpcv2.h>
6992ce8c6aSad #include <nfs/nfsproto.h>
7092ce8c6aSad #include <nfs/nfs.h>
7192ce8c6aSad #include <nfs/xdr_subs.h>
7292ce8c6aSad #include <nfs/nfsm_subs.h>
7392ce8c6aSad #include <nfs/nfsmount.h>
7492ce8c6aSad #include <nfs/nfsnode.h>
7592ce8c6aSad #include <nfs/nfsrtt.h>
7692ce8c6aSad #include <nfs/nfs_var.h>
7792ce8c6aSad 
7892ce8c6aSad static void nfsrv_wakenfsd_locked(struct nfssvc_sock *);
7992ce8c6aSad 
8002cdf4d2Sdsl int (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *,
8192ce8c6aSad 				    struct nfssvc_sock *, struct lwp *,
8202cdf4d2Sdsl 				    struct mbuf **) = {
8392ce8c6aSad 	nfsrv_null,
8492ce8c6aSad 	nfsrv_getattr,
8592ce8c6aSad 	nfsrv_setattr,
8692ce8c6aSad 	nfsrv_lookup,
8792ce8c6aSad 	nfsrv3_access,
8892ce8c6aSad 	nfsrv_readlink,
8992ce8c6aSad 	nfsrv_read,
9092ce8c6aSad 	nfsrv_write,
9192ce8c6aSad 	nfsrv_create,
9292ce8c6aSad 	nfsrv_mkdir,
9392ce8c6aSad 	nfsrv_symlink,
9492ce8c6aSad 	nfsrv_mknod,
9592ce8c6aSad 	nfsrv_remove,
9692ce8c6aSad 	nfsrv_rmdir,
9792ce8c6aSad 	nfsrv_rename,
9892ce8c6aSad 	nfsrv_link,
9992ce8c6aSad 	nfsrv_readdir,
10092ce8c6aSad 	nfsrv_readdirplus,
10192ce8c6aSad 	nfsrv_statfs,
10292ce8c6aSad 	nfsrv_fsinfo,
10392ce8c6aSad 	nfsrv_pathconf,
10492ce8c6aSad 	nfsrv_commit,
10592ce8c6aSad 	nfsrv_noop
10692ce8c6aSad };
10792ce8c6aSad 
10892ce8c6aSad /*
10992ce8c6aSad  * Socket upcall routine for the nfsd sockets.
11092ce8c6aSad  * The void *arg is a pointer to the "struct nfssvc_sock".
11192ce8c6aSad  */
11292ce8c6aSad void
nfsrv_soupcall(struct socket * so,void * arg,int events,int waitflag)11341715850Stls nfsrv_soupcall(struct socket *so, void *arg, int events, int waitflag)
11492ce8c6aSad {
11592ce8c6aSad 	struct nfssvc_sock *slp = (struct nfssvc_sock *)arg;
11692ce8c6aSad 
11792ce8c6aSad 	nfsdsock_setbits(slp, SLP_A_NEEDQ);
11892ce8c6aSad 	nfsrv_wakenfsd(slp);
11992ce8c6aSad }
12092ce8c6aSad 
12192ce8c6aSad void
nfsrv_rcv(struct nfssvc_sock * slp)12292ce8c6aSad nfsrv_rcv(struct nfssvc_sock *slp)
12392ce8c6aSad {
12492ce8c6aSad 	struct socket *so;
12592ce8c6aSad 	struct mbuf *m;
12692ce8c6aSad 	struct mbuf *mp, *nam;
12792ce8c6aSad 	struct uio auio;
12892ce8c6aSad 	int flags;
12992ce8c6aSad 	int error;
13092ce8c6aSad 	int setflags = 0;
13192ce8c6aSad 
13292ce8c6aSad 	error = nfsdsock_lock(slp, true);
13392ce8c6aSad 	if (error) {
13492ce8c6aSad 		setflags |= SLP_A_NEEDQ;
13592ce8c6aSad 		goto dorecs_unlocked;
13692ce8c6aSad 	}
13792ce8c6aSad 
13892ce8c6aSad 	nfsdsock_clearbits(slp, SLP_A_NEEDQ);
13992ce8c6aSad 
14092ce8c6aSad 	so = slp->ns_so;
14192ce8c6aSad 	if (so->so_type == SOCK_STREAM) {
14292ce8c6aSad 		/*
14392ce8c6aSad 		 * Do soreceive().
14492ce8c6aSad 		 */
14592ce8c6aSad 		auio.uio_resid = 1000000000;
14692ce8c6aSad 		/* not need to setup uio_vmspace */
14792ce8c6aSad 		flags = MSG_DONTWAIT;
14892ce8c6aSad 		error = (*so->so_receive)(so, &nam, &auio, &mp, NULL, &flags);
14992ce8c6aSad 		if (error || mp == NULL) {
15092ce8c6aSad 			if (error == EWOULDBLOCK)
15192ce8c6aSad 				setflags |= SLP_A_NEEDQ;
15292ce8c6aSad 			else
15392ce8c6aSad 				setflags |= SLP_A_DISCONN;
15492ce8c6aSad 			goto dorecs;
15592ce8c6aSad 		}
15692ce8c6aSad 		m = mp;
15792ce8c6aSad 		m_claimm(m, &nfs_mowner);
15892ce8c6aSad 		if (slp->ns_rawend) {
15992ce8c6aSad 			slp->ns_rawend->m_next = m;
16092ce8c6aSad 			slp->ns_cc += 1000000000 - auio.uio_resid;
16192ce8c6aSad 		} else {
16292ce8c6aSad 			slp->ns_raw = m;
16392ce8c6aSad 			slp->ns_cc = 1000000000 - auio.uio_resid;
16492ce8c6aSad 		}
16592ce8c6aSad 		while (m->m_next)
16692ce8c6aSad 			m = m->m_next;
16792ce8c6aSad 		slp->ns_rawend = m;
16892ce8c6aSad 
16992ce8c6aSad 		/*
17092ce8c6aSad 		 * Now try and parse record(s) out of the raw stream data.
17192ce8c6aSad 		 */
17292ce8c6aSad 		error = nfsrv_getstream(slp, M_WAIT);
17392ce8c6aSad 		if (error) {
17492ce8c6aSad 			if (error == EPERM)
17592ce8c6aSad 				setflags |= SLP_A_DISCONN;
17692ce8c6aSad 			else
17792ce8c6aSad 				setflags |= SLP_A_NEEDQ;
17892ce8c6aSad 		}
17992ce8c6aSad 	} else {
18092ce8c6aSad 		do {
18192ce8c6aSad 			auio.uio_resid = 1000000000;
18292ce8c6aSad 			/* not need to setup uio_vmspace */
18392ce8c6aSad 			flags = MSG_DONTWAIT;
18492ce8c6aSad 			error = (*so->so_receive)(so, &nam, &auio, &mp, NULL,
18592ce8c6aSad 			    &flags);
18692ce8c6aSad 			if (mp) {
18792ce8c6aSad 				if (nam) {
18892ce8c6aSad 					m = nam;
18992ce8c6aSad 					m->m_next = mp;
19092ce8c6aSad 				} else
19192ce8c6aSad 					m = mp;
19292ce8c6aSad 				m_claimm(m, &nfs_mowner);
19392ce8c6aSad 				if (slp->ns_recend)
19492ce8c6aSad 					slp->ns_recend->m_nextpkt = m;
19592ce8c6aSad 				else
19692ce8c6aSad 					slp->ns_rec = m;
19792ce8c6aSad 				slp->ns_recend = m;
19892ce8c6aSad 				m->m_nextpkt = (struct mbuf *)0;
19992ce8c6aSad 			}
20092ce8c6aSad 			if (error) {
20192ce8c6aSad 				if ((so->so_proto->pr_flags & PR_CONNREQUIRED)
20292ce8c6aSad 				    && error != EWOULDBLOCK) {
20392ce8c6aSad 					setflags |= SLP_A_DISCONN;
20492ce8c6aSad 					goto dorecs;
20592ce8c6aSad 				}
20692ce8c6aSad 			}
20792ce8c6aSad 		} while (mp);
20892ce8c6aSad 	}
20992ce8c6aSad dorecs:
21092ce8c6aSad 	nfsdsock_unlock(slp);
21192ce8c6aSad 
21292ce8c6aSad dorecs_unlocked:
21392ce8c6aSad 	if (setflags) {
21492ce8c6aSad 		nfsdsock_setbits(slp, setflags);
21592ce8c6aSad 	}
21692ce8c6aSad }
21792ce8c6aSad 
21892ce8c6aSad int
nfsdsock_lock(struct nfssvc_sock * slp,bool waitok)21992ce8c6aSad nfsdsock_lock(struct nfssvc_sock *slp, bool waitok)
22092ce8c6aSad {
22192ce8c6aSad 
22292ce8c6aSad 	mutex_enter(&slp->ns_lock);
22392ce8c6aSad 	while ((~slp->ns_flags & (SLP_BUSY|SLP_VALID)) == 0) {
22492ce8c6aSad 		if (!waitok) {
22592ce8c6aSad 			mutex_exit(&slp->ns_lock);
22692ce8c6aSad 			return EWOULDBLOCK;
22792ce8c6aSad 		}
22892ce8c6aSad 		cv_wait(&slp->ns_cv, &slp->ns_lock);
22992ce8c6aSad 	}
23092ce8c6aSad 	if ((slp->ns_flags & SLP_VALID) == 0) {
23192ce8c6aSad 		mutex_exit(&slp->ns_lock);
23292ce8c6aSad 		return EINVAL;
23392ce8c6aSad 	}
23492ce8c6aSad 	KASSERT((slp->ns_flags & SLP_BUSY) == 0);
23592ce8c6aSad 	slp->ns_flags |= SLP_BUSY;
23692ce8c6aSad 	mutex_exit(&slp->ns_lock);
23792ce8c6aSad 
23892ce8c6aSad 	return 0;
23992ce8c6aSad }
24092ce8c6aSad 
24192ce8c6aSad void
nfsdsock_unlock(struct nfssvc_sock * slp)24292ce8c6aSad nfsdsock_unlock(struct nfssvc_sock *slp)
24392ce8c6aSad {
24492ce8c6aSad 
24592ce8c6aSad 	mutex_enter(&slp->ns_lock);
24692ce8c6aSad 	KASSERT((slp->ns_flags & SLP_BUSY) != 0);
24792ce8c6aSad 	cv_broadcast(&slp->ns_cv);
24892ce8c6aSad 	slp->ns_flags &= ~SLP_BUSY;
24992ce8c6aSad 	mutex_exit(&slp->ns_lock);
25092ce8c6aSad }
25192ce8c6aSad 
25292ce8c6aSad int
nfsdsock_drain(struct nfssvc_sock * slp)25392ce8c6aSad nfsdsock_drain(struct nfssvc_sock *slp)
25492ce8c6aSad {
25592ce8c6aSad 	int error = 0;
25692ce8c6aSad 
25792ce8c6aSad 	mutex_enter(&slp->ns_lock);
25892ce8c6aSad 	if ((slp->ns_flags & SLP_VALID) == 0) {
25992ce8c6aSad 		error = EINVAL;
26092ce8c6aSad 		goto done;
26192ce8c6aSad 	}
26292ce8c6aSad 	slp->ns_flags &= ~SLP_VALID;
26392ce8c6aSad 	while ((slp->ns_flags & SLP_BUSY) != 0) {
26492ce8c6aSad 		cv_wait(&slp->ns_cv, &slp->ns_lock);
26592ce8c6aSad 	}
26692ce8c6aSad done:
26792ce8c6aSad 	mutex_exit(&slp->ns_lock);
26892ce8c6aSad 
26992ce8c6aSad 	return error;
27092ce8c6aSad }
27192ce8c6aSad 
27292ce8c6aSad /*
27392ce8c6aSad  * Try and extract an RPC request from the mbuf data list received on a
27492ce8c6aSad  * stream socket. The "waitflag" argument indicates whether or not it
27592ce8c6aSad  * can sleep.
27692ce8c6aSad  */
27792ce8c6aSad int
nfsrv_getstream(struct nfssvc_sock * slp,int waitflag)278454af1c0Sdsl nfsrv_getstream(struct nfssvc_sock *slp, int waitflag)
27992ce8c6aSad {
28092ce8c6aSad 	struct mbuf *m, **mpp;
28192ce8c6aSad 	struct mbuf *recm;
28292ce8c6aSad 	u_int32_t recmark;
28392ce8c6aSad 	int error = 0;
28492ce8c6aSad 
28592ce8c6aSad 	KASSERT((slp->ns_flags & SLP_BUSY) != 0);
28692ce8c6aSad 	for (;;) {
28792ce8c6aSad 		if (slp->ns_reclen == 0) {
28892ce8c6aSad 			if (slp->ns_cc < NFSX_UNSIGNED) {
28992ce8c6aSad 				break;
29092ce8c6aSad 			}
29192ce8c6aSad 			m = slp->ns_raw;
29292ce8c6aSad 			m_copydata(m, 0, NFSX_UNSIGNED, (void *)&recmark);
29392ce8c6aSad 			m_adj(m, NFSX_UNSIGNED);
29492ce8c6aSad 			slp->ns_cc -= NFSX_UNSIGNED;
29592ce8c6aSad 			recmark = ntohl(recmark);
29692ce8c6aSad 			slp->ns_reclen = recmark & ~0x80000000;
29792ce8c6aSad 			if (recmark & 0x80000000)
29892ce8c6aSad 				slp->ns_sflags |= SLP_S_LASTFRAG;
29992ce8c6aSad 			else
30092ce8c6aSad 				slp->ns_sflags &= ~SLP_S_LASTFRAG;
30192ce8c6aSad 			if (slp->ns_reclen > NFS_MAXPACKET) {
30292ce8c6aSad 				error = EPERM;
30392ce8c6aSad 				break;
30492ce8c6aSad 			}
30592ce8c6aSad 		}
30692ce8c6aSad 
30792ce8c6aSad 		/*
30892ce8c6aSad 		 * Now get the record part.
30992ce8c6aSad 		 *
31092ce8c6aSad 		 * Note that slp->ns_reclen may be 0.  Linux sometimes
31192ce8c6aSad 		 * generates 0-length records.
31292ce8c6aSad 		 */
31392ce8c6aSad 		if (slp->ns_cc == slp->ns_reclen) {
31492ce8c6aSad 			recm = slp->ns_raw;
31592ce8c6aSad 			slp->ns_raw = slp->ns_rawend = (struct mbuf *)0;
31692ce8c6aSad 			slp->ns_cc = slp->ns_reclen = 0;
31792ce8c6aSad 		} else if (slp->ns_cc > slp->ns_reclen) {
31892ce8c6aSad 			recm = slp->ns_raw;
31992ce8c6aSad 			m = m_split(recm, slp->ns_reclen, waitflag);
32092ce8c6aSad 			if (m == NULL) {
32192ce8c6aSad 				error = EWOULDBLOCK;
32292ce8c6aSad 				break;
32392ce8c6aSad 			}
32492ce8c6aSad 			m_claimm(recm, &nfs_mowner);
32592ce8c6aSad 			slp->ns_raw = m;
326218437a4Shannken 			while (m->m_next)
327218437a4Shannken 				m = m->m_next;
32892ce8c6aSad 			slp->ns_rawend = m;
32992ce8c6aSad 			slp->ns_cc -= slp->ns_reclen;
33092ce8c6aSad 			slp->ns_reclen = 0;
33192ce8c6aSad 		} else {
33292ce8c6aSad 			break;
33392ce8c6aSad 		}
33492ce8c6aSad 
33592ce8c6aSad 		/*
33692ce8c6aSad 		 * Accumulate the fragments into a record.
33792ce8c6aSad 		 */
33892ce8c6aSad 		mpp = &slp->ns_frag;
33992ce8c6aSad 		while (*mpp)
34092ce8c6aSad 			mpp = &((*mpp)->m_next);
34192ce8c6aSad 		*mpp = recm;
34292ce8c6aSad 		if (slp->ns_sflags & SLP_S_LASTFRAG) {
34392ce8c6aSad 			if (slp->ns_recend)
34492ce8c6aSad 				slp->ns_recend->m_nextpkt = slp->ns_frag;
34592ce8c6aSad 			else
34692ce8c6aSad 				slp->ns_rec = slp->ns_frag;
34792ce8c6aSad 			slp->ns_recend = slp->ns_frag;
34892ce8c6aSad 			slp->ns_frag = NULL;
34992ce8c6aSad 		}
35092ce8c6aSad 	}
35192ce8c6aSad 
35292ce8c6aSad 	return error;
35392ce8c6aSad }
35492ce8c6aSad 
35592ce8c6aSad /*
35692ce8c6aSad  * Parse an RPC header.
35792ce8c6aSad  */
35892ce8c6aSad int
nfsrv_dorec(struct nfssvc_sock * slp,struct nfsd * nfsd,struct nfsrv_descript ** ndp,bool * more)35992ce8c6aSad nfsrv_dorec(struct nfssvc_sock *slp, struct nfsd *nfsd,
36092ce8c6aSad     struct nfsrv_descript **ndp, bool *more)
36192ce8c6aSad {
36292ce8c6aSad 	struct mbuf *m, *nam;
36392ce8c6aSad 	struct nfsrv_descript *nd;
36492ce8c6aSad 	int error;
36592ce8c6aSad 
36692ce8c6aSad 	*ndp = NULL;
36792ce8c6aSad 	*more = false;
36892ce8c6aSad 
36992ce8c6aSad 	if (nfsdsock_lock(slp, true)) {
37092ce8c6aSad 		return ENOBUFS;
37192ce8c6aSad 	}
37292ce8c6aSad 	m = slp->ns_rec;
37392ce8c6aSad 	if (m == NULL) {
37492ce8c6aSad 		nfsdsock_unlock(slp);
37592ce8c6aSad 		return ENOBUFS;
37692ce8c6aSad 	}
37792ce8c6aSad 	slp->ns_rec = m->m_nextpkt;
37892ce8c6aSad 	if (slp->ns_rec) {
37992ce8c6aSad 		m->m_nextpkt = NULL;
38092ce8c6aSad 		*more = true;
38192ce8c6aSad 	} else {
38292ce8c6aSad 		slp->ns_recend = NULL;
38392ce8c6aSad 	}
38492ce8c6aSad 	nfsdsock_unlock(slp);
38592ce8c6aSad 
38692ce8c6aSad 	if (m->m_type == MT_SONAME) {
38792ce8c6aSad 		nam = m;
38892ce8c6aSad 		m = m->m_next;
38992ce8c6aSad 		nam->m_next = NULL;
39092ce8c6aSad 	} else
39192ce8c6aSad 		nam = NULL;
39292ce8c6aSad 	nd = nfsdreq_alloc();
39392ce8c6aSad 	nd->nd_md = nd->nd_mrep = m;
39492ce8c6aSad 	nd->nd_nam2 = nam;
39592ce8c6aSad 	nd->nd_dpos = mtod(m, void *);
39692ce8c6aSad 	error = nfs_getreq(nd, nfsd, true);
39792ce8c6aSad 	if (error) {
39892ce8c6aSad 		m_freem(nam);
39992ce8c6aSad 		nfsdreq_free(nd);
40092ce8c6aSad 		return (error);
40192ce8c6aSad 	}
40292ce8c6aSad 	*ndp = nd;
40392ce8c6aSad 	nfsd->nfsd_nd = nd;
40492ce8c6aSad 	return (0);
40592ce8c6aSad }
40692ce8c6aSad 
40792ce8c6aSad bool
nfsrv_timer(void)40892ce8c6aSad nfsrv_timer(void)
40992ce8c6aSad {
41092ce8c6aSad 	struct timeval tv;
41192ce8c6aSad 	struct nfssvc_sock *slp;
41292ce8c6aSad 	u_quad_t cur_usec;
41392ce8c6aSad 	struct nfsrv_descript *nd;
41492ce8c6aSad 	bool more;
41592ce8c6aSad 
41692ce8c6aSad 	/*
41792ce8c6aSad 	 * Scan the write gathering queues for writes that need to be
41892ce8c6aSad 	 * completed now.
41992ce8c6aSad 	 */
42092ce8c6aSad 	getmicrotime(&tv);
42192ce8c6aSad 	cur_usec = (u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec;
42292ce8c6aSad 	more = false;
42392ce8c6aSad 	mutex_enter(&nfsd_lock);
42492ce8c6aSad 	TAILQ_FOREACH(slp, &nfssvc_sockhead, ns_chain) {
42592ce8c6aSad 		nd = LIST_FIRST(&slp->ns_tq);
42692ce8c6aSad 		if (nd != NULL) {
42792ce8c6aSad 			if (nd->nd_time <= cur_usec) {
42892ce8c6aSad 				nfsrv_wakenfsd_locked(slp);
42992ce8c6aSad 			}
43092ce8c6aSad 			more = true;
43192ce8c6aSad 		}
43292ce8c6aSad 	}
43392ce8c6aSad 	mutex_exit(&nfsd_lock);
43492ce8c6aSad 	return more;
43592ce8c6aSad }
43692ce8c6aSad 
43792ce8c6aSad /*
43892ce8c6aSad  * Search for a sleeping nfsd and wake it up.
43992ce8c6aSad  * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the
44092ce8c6aSad  * running nfsds will go look for the work in the nfssvc_sock list.
44192ce8c6aSad  */
44292ce8c6aSad static void
nfsrv_wakenfsd_locked(struct nfssvc_sock * slp)44392ce8c6aSad nfsrv_wakenfsd_locked(struct nfssvc_sock *slp)
44492ce8c6aSad {
44592ce8c6aSad 	struct nfsd *nd;
44692ce8c6aSad 
44792ce8c6aSad 	KASSERT(mutex_owned(&nfsd_lock));
44892ce8c6aSad 
44992ce8c6aSad 	if ((slp->ns_flags & SLP_VALID) == 0)
45092ce8c6aSad 		return;
45192ce8c6aSad 	if (slp->ns_gflags & SLP_G_DOREC)
45292ce8c6aSad 		return;
45392ce8c6aSad 	nd = SLIST_FIRST(&nfsd_idle_head);
45492ce8c6aSad 	if (nd) {
45592ce8c6aSad 		SLIST_REMOVE_HEAD(&nfsd_idle_head, nfsd_idle);
45692ce8c6aSad 		if (nd->nfsd_slp)
45792ce8c6aSad 			panic("nfsd wakeup");
45892ce8c6aSad 		slp->ns_sref++;
45992ce8c6aSad 		KASSERT(slp->ns_sref > 0);
46092ce8c6aSad 		nd->nfsd_slp = slp;
46192ce8c6aSad 		cv_signal(&nd->nfsd_cv);
46292ce8c6aSad 	} else {
46392ce8c6aSad 		slp->ns_gflags |= SLP_G_DOREC;
46492ce8c6aSad 		nfsd_head_flag |= NFSD_CHECKSLP;
46592ce8c6aSad 		TAILQ_INSERT_TAIL(&nfssvc_sockpending, slp, ns_pending);
46692ce8c6aSad 	}
46792ce8c6aSad }
46892ce8c6aSad 
46992ce8c6aSad void
nfsrv_wakenfsd(struct nfssvc_sock * slp)47092ce8c6aSad nfsrv_wakenfsd(struct nfssvc_sock *slp)
47192ce8c6aSad {
47292ce8c6aSad 
47392ce8c6aSad 	mutex_enter(&nfsd_lock);
47492ce8c6aSad 	nfsrv_wakenfsd_locked(slp);
47592ce8c6aSad 	mutex_exit(&nfsd_lock);
47692ce8c6aSad }
47792ce8c6aSad 
47892ce8c6aSad int
nfsdsock_sendreply(struct nfssvc_sock * slp,struct nfsrv_descript * nd)47992ce8c6aSad nfsdsock_sendreply(struct nfssvc_sock *slp, struct nfsrv_descript *nd)
48092ce8c6aSad {
48192ce8c6aSad 	int error;
48292ce8c6aSad 
48392ce8c6aSad 	m_freem(nd->nd_mrep);
48492ce8c6aSad 	nd->nd_mrep = NULL;
48592ce8c6aSad 
48692ce8c6aSad 	mutex_enter(&slp->ns_lock);
48792ce8c6aSad 	if ((slp->ns_flags & SLP_SENDING) != 0) {
48892ce8c6aSad 		SIMPLEQ_INSERT_TAIL(&slp->ns_sendq, nd, nd_sendq);
48992ce8c6aSad 		mutex_exit(&slp->ns_lock);
49092ce8c6aSad 		return 0;
49192ce8c6aSad 	}
49292ce8c6aSad 	KASSERT(SIMPLEQ_EMPTY(&slp->ns_sendq));
49392ce8c6aSad 	slp->ns_flags |= SLP_SENDING;
49492ce8c6aSad 	mutex_exit(&slp->ns_lock);
49592ce8c6aSad 
49692ce8c6aSad again:
49792ce8c6aSad 	error = nfs_send(slp->ns_so, nd->nd_nam2, nd->nd_mreq, NULL, curlwp);
49892ce8c6aSad 	if (nd->nd_nam2) {
49992ce8c6aSad 		m_free(nd->nd_nam2);
50092ce8c6aSad 	}
50192ce8c6aSad 	nfsdreq_free(nd);
50292ce8c6aSad 
50392ce8c6aSad 	mutex_enter(&slp->ns_lock);
50492ce8c6aSad 	KASSERT((slp->ns_flags & SLP_SENDING) != 0);
50592ce8c6aSad 	nd = SIMPLEQ_FIRST(&slp->ns_sendq);
50692ce8c6aSad 	if (nd != NULL) {
50792ce8c6aSad 		SIMPLEQ_REMOVE_HEAD(&slp->ns_sendq, nd_sendq);
50892ce8c6aSad 		mutex_exit(&slp->ns_lock);
50992ce8c6aSad 		goto again;
51092ce8c6aSad 	}
51192ce8c6aSad 	slp->ns_flags &= ~SLP_SENDING;
51292ce8c6aSad 	mutex_exit(&slp->ns_lock);
51392ce8c6aSad 
51492ce8c6aSad 	return error;
51592ce8c6aSad }
51692ce8c6aSad 
51792ce8c6aSad void
nfsdsock_setbits(struct nfssvc_sock * slp,int bits)51892ce8c6aSad nfsdsock_setbits(struct nfssvc_sock *slp, int bits)
51992ce8c6aSad {
52092ce8c6aSad 
52192ce8c6aSad 	mutex_enter(&slp->ns_alock);
52292ce8c6aSad 	slp->ns_aflags |= bits;
52392ce8c6aSad 	mutex_exit(&slp->ns_alock);
52492ce8c6aSad }
52592ce8c6aSad 
52692ce8c6aSad void
nfsdsock_clearbits(struct nfssvc_sock * slp,int bits)52792ce8c6aSad nfsdsock_clearbits(struct nfssvc_sock *slp, int bits)
52892ce8c6aSad {
52992ce8c6aSad 
53092ce8c6aSad 	mutex_enter(&slp->ns_alock);
53192ce8c6aSad 	slp->ns_aflags &= ~bits;
53292ce8c6aSad 	mutex_exit(&slp->ns_alock);
53392ce8c6aSad }
53492ce8c6aSad 
53592ce8c6aSad bool
nfsdsock_testbits(struct nfssvc_sock * slp,int bits)53692ce8c6aSad nfsdsock_testbits(struct nfssvc_sock *slp, int bits)
53792ce8c6aSad {
53892ce8c6aSad 
53992ce8c6aSad 	return (slp->ns_aflags & bits);
54092ce8c6aSad }
541