1 /* $NetBSD: nfs_srvsocket.c,v 1.3 2009/03/14 15:36:24 dsl Exp $ */
4 * Copyright (c) 1989, 1991, 1993, 1995
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * @(#)nfs_socket.c 8.5 (Berkeley) 3/30/95
38 * Socket operations for use by nfs
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: nfs_srvsocket.c,v 1.3 2009/03/14 15:36:24 dsl Exp $");
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/evcnt.h>
47 #include <sys/callout.h>
49 #include <sys/mount.h>
50 #include <sys/kernel.h>
53 #include <sys/vnode.h>
54 #include <sys/domain.h>
55 #include <sys/protosw.h>
56 #include <sys/socket.h>
57 #include <sys/socketvar.h>
58 #include <sys/syslog.h>
59 #include <sys/tprintf.h>
60 #include <sys/namei.h>
61 #include <sys/signal.h>
62 #include <sys/signalvar.h>
63 #include <sys/kauth.h>
65 #include <netinet/in.h>
66 #include <netinet/tcp.h>
68 #include <nfs/rpcv2.h>
69 #include <nfs/nfsproto.h>
71 #include <nfs/xdr_subs.h>
72 #include <nfs/nfsm_subs.h>
73 #include <nfs/nfsmount.h>
74 #include <nfs/nfsnode.h>
75 #include <nfs/nfsrtt.h>
76 #include <nfs/nfs_var.h>
78 static void nfsrv_wakenfsd_locked(struct nfssvc_sock
*);
80 int (*nfsrv3_procs
[NFS_NPROCS
])(struct nfsrv_descript
*,
81 struct nfssvc_sock
*, struct lwp
*,
109 * Socket upcall routine for the nfsd sockets.
110 * The void *arg is a pointer to the "struct nfssvc_sock".
113 nfsrv_soupcall(struct socket
*so
, void *arg
, int events
, int waitflag
)
115 struct nfssvc_sock
*slp
= (struct nfssvc_sock
*)arg
;
117 nfsdsock_setbits(slp
, SLP_A_NEEDQ
);
122 nfsrv_rcv(struct nfssvc_sock
*slp
)
126 struct mbuf
*mp
, *nam
;
132 error
= nfsdsock_lock(slp
, true);
134 setflags
|= SLP_A_NEEDQ
;
135 goto dorecs_unlocked
;
138 nfsdsock_clearbits(slp
, SLP_A_NEEDQ
);
141 if (so
->so_type
== SOCK_STREAM
) {
145 auio
.uio_resid
= 1000000000;
146 /* not need to setup uio_vmspace */
147 flags
= MSG_DONTWAIT
;
148 error
= (*so
->so_receive
)(so
, &nam
, &auio
, &mp
, NULL
, &flags
);
149 if (error
|| mp
== NULL
) {
150 if (error
== EWOULDBLOCK
)
151 setflags
|= SLP_A_NEEDQ
;
153 setflags
|= SLP_A_DISCONN
;
157 m_claimm(m
, &nfs_mowner
);
158 if (slp
->ns_rawend
) {
159 slp
->ns_rawend
->m_next
= m
;
160 slp
->ns_cc
+= 1000000000 - auio
.uio_resid
;
163 slp
->ns_cc
= 1000000000 - auio
.uio_resid
;
170 * Now try and parse record(s) out of the raw stream data.
172 error
= nfsrv_getstream(slp
, M_WAIT
);
175 setflags
|= SLP_A_DISCONN
;
177 setflags
|= SLP_A_NEEDQ
;
181 auio
.uio_resid
= 1000000000;
182 /* not need to setup uio_vmspace */
183 flags
= MSG_DONTWAIT
;
184 error
= (*so
->so_receive
)(so
, &nam
, &auio
, &mp
, NULL
,
192 m_claimm(m
, &nfs_mowner
);
194 slp
->ns_recend
->m_nextpkt
= m
;
198 m
->m_nextpkt
= (struct mbuf
*)0;
201 if ((so
->so_proto
->pr_flags
& PR_CONNREQUIRED
)
202 && error
!= EWOULDBLOCK
) {
203 setflags
|= SLP_A_DISCONN
;
210 nfsdsock_unlock(slp
);
214 nfsdsock_setbits(slp
, setflags
);
219 nfsdsock_lock(struct nfssvc_sock
*slp
, bool waitok
)
222 mutex_enter(&slp
->ns_lock
);
223 while ((~slp
->ns_flags
& (SLP_BUSY
|SLP_VALID
)) == 0) {
225 mutex_exit(&slp
->ns_lock
);
228 cv_wait(&slp
->ns_cv
, &slp
->ns_lock
);
230 if ((slp
->ns_flags
& SLP_VALID
) == 0) {
231 mutex_exit(&slp
->ns_lock
);
234 KASSERT((slp
->ns_flags
& SLP_BUSY
) == 0);
235 slp
->ns_flags
|= SLP_BUSY
;
236 mutex_exit(&slp
->ns_lock
);
242 nfsdsock_unlock(struct nfssvc_sock
*slp
)
245 mutex_enter(&slp
->ns_lock
);
246 KASSERT((slp
->ns_flags
& SLP_BUSY
) != 0);
247 cv_broadcast(&slp
->ns_cv
);
248 slp
->ns_flags
&= ~SLP_BUSY
;
249 mutex_exit(&slp
->ns_lock
);
253 nfsdsock_drain(struct nfssvc_sock
*slp
)
257 mutex_enter(&slp
->ns_lock
);
258 if ((slp
->ns_flags
& SLP_VALID
) == 0) {
262 slp
->ns_flags
&= ~SLP_VALID
;
263 while ((slp
->ns_flags
& SLP_BUSY
) != 0) {
264 cv_wait(&slp
->ns_cv
, &slp
->ns_lock
);
267 mutex_exit(&slp
->ns_lock
);
273 * Try and extract an RPC request from the mbuf data list received on a
274 * stream socket. The "waitflag" argument indicates whether or not it
278 nfsrv_getstream(struct nfssvc_sock
*slp
, int waitflag
)
280 struct mbuf
*m
, **mpp
;
285 KASSERT((slp
->ns_flags
& SLP_BUSY
) != 0);
287 if (slp
->ns_reclen
== 0) {
288 if (slp
->ns_cc
< NFSX_UNSIGNED
) {
292 m_copydata(m
, 0, NFSX_UNSIGNED
, (void *)&recmark
);
293 m_adj(m
, NFSX_UNSIGNED
);
294 slp
->ns_cc
-= NFSX_UNSIGNED
;
295 recmark
= ntohl(recmark
);
296 slp
->ns_reclen
= recmark
& ~0x80000000;
297 if (recmark
& 0x80000000)
298 slp
->ns_sflags
|= SLP_S_LASTFRAG
;
300 slp
->ns_sflags
&= ~SLP_S_LASTFRAG
;
301 if (slp
->ns_reclen
> NFS_MAXPACKET
) {
308 * Now get the record part.
310 * Note that slp->ns_reclen may be 0. Linux sometimes
311 * generates 0-length records.
313 if (slp
->ns_cc
== slp
->ns_reclen
) {
315 slp
->ns_raw
= slp
->ns_rawend
= (struct mbuf
*)0;
316 slp
->ns_cc
= slp
->ns_reclen
= 0;
317 } else if (slp
->ns_cc
> slp
->ns_reclen
) {
319 m
= m_split(recm
, slp
->ns_reclen
, waitflag
);
324 m_claimm(recm
, &nfs_mowner
);
326 if (m
->m_next
== NULL
)
328 slp
->ns_cc
-= slp
->ns_reclen
;
335 * Accumulate the fragments into a record.
339 mpp
= &((*mpp
)->m_next
);
341 if (slp
->ns_sflags
& SLP_S_LASTFRAG
) {
343 slp
->ns_recend
->m_nextpkt
= slp
->ns_frag
;
345 slp
->ns_rec
= slp
->ns_frag
;
346 slp
->ns_recend
= slp
->ns_frag
;
355 * Parse an RPC header.
358 nfsrv_dorec(struct nfssvc_sock
*slp
, struct nfsd
*nfsd
,
359 struct nfsrv_descript
**ndp
, bool *more
)
361 struct mbuf
*m
, *nam
;
362 struct nfsrv_descript
*nd
;
368 if (nfsdsock_lock(slp
, true)) {
373 nfsdsock_unlock(slp
);
376 slp
->ns_rec
= m
->m_nextpkt
;
381 slp
->ns_recend
= NULL
;
383 nfsdsock_unlock(slp
);
385 if (m
->m_type
== MT_SONAME
) {
391 nd
= nfsdreq_alloc();
392 nd
->nd_md
= nd
->nd_mrep
= m
;
394 nd
->nd_dpos
= mtod(m
, void *);
395 error
= nfs_getreq(nd
, nfsd
, true);
410 struct nfssvc_sock
*slp
;
412 struct nfsrv_descript
*nd
;
416 * Scan the write gathering queues for writes that need to be
420 cur_usec
= (u_quad_t
)tv
.tv_sec
* 1000000 + (u_quad_t
)tv
.tv_usec
;
422 mutex_enter(&nfsd_lock
);
423 TAILQ_FOREACH(slp
, &nfssvc_sockhead
, ns_chain
) {
424 nd
= LIST_FIRST(&slp
->ns_tq
);
426 if (nd
->nd_time
<= cur_usec
) {
427 nfsrv_wakenfsd_locked(slp
);
432 mutex_exit(&nfsd_lock
);
437 * Search for a sleeping nfsd and wake it up.
438 * SIDE EFFECT: If none found, set NFSD_CHECKSLP flag, so that one of the
439 * running nfsds will go look for the work in the nfssvc_sock list.
442 nfsrv_wakenfsd_locked(struct nfssvc_sock
*slp
)
446 KASSERT(mutex_owned(&nfsd_lock
));
448 if ((slp
->ns_flags
& SLP_VALID
) == 0)
450 if (slp
->ns_gflags
& SLP_G_DOREC
)
452 nd
= SLIST_FIRST(&nfsd_idle_head
);
454 SLIST_REMOVE_HEAD(&nfsd_idle_head
, nfsd_idle
);
456 panic("nfsd wakeup");
458 KASSERT(slp
->ns_sref
> 0);
460 cv_signal(&nd
->nfsd_cv
);
462 slp
->ns_gflags
|= SLP_G_DOREC
;
463 nfsd_head_flag
|= NFSD_CHECKSLP
;
464 TAILQ_INSERT_TAIL(&nfssvc_sockpending
, slp
, ns_pending
);
469 nfsrv_wakenfsd(struct nfssvc_sock
*slp
)
472 mutex_enter(&nfsd_lock
);
473 nfsrv_wakenfsd_locked(slp
);
474 mutex_exit(&nfsd_lock
);
478 nfsdsock_sendreply(struct nfssvc_sock
*slp
, struct nfsrv_descript
*nd
)
482 if (nd
->nd_mrep
!= NULL
) {
483 m_freem(nd
->nd_mrep
);
487 mutex_enter(&slp
->ns_lock
);
488 if ((slp
->ns_flags
& SLP_SENDING
) != 0) {
489 SIMPLEQ_INSERT_TAIL(&slp
->ns_sendq
, nd
, nd_sendq
);
490 mutex_exit(&slp
->ns_lock
);
493 KASSERT(SIMPLEQ_EMPTY(&slp
->ns_sendq
));
494 slp
->ns_flags
|= SLP_SENDING
;
495 mutex_exit(&slp
->ns_lock
);
498 error
= nfs_send(slp
->ns_so
, nd
->nd_nam2
, nd
->nd_mreq
, NULL
, curlwp
);
504 mutex_enter(&slp
->ns_lock
);
505 KASSERT((slp
->ns_flags
& SLP_SENDING
) != 0);
506 nd
= SIMPLEQ_FIRST(&slp
->ns_sendq
);
508 SIMPLEQ_REMOVE_HEAD(&slp
->ns_sendq
, nd_sendq
);
509 mutex_exit(&slp
->ns_lock
);
512 slp
->ns_flags
&= ~SLP_SENDING
;
513 mutex_exit(&slp
->ns_lock
);
519 nfsdsock_setbits(struct nfssvc_sock
*slp
, int bits
)
522 mutex_enter(&slp
->ns_alock
);
523 slp
->ns_aflags
|= bits
;
524 mutex_exit(&slp
->ns_alock
);
528 nfsdsock_clearbits(struct nfssvc_sock
*slp
, int bits
)
531 mutex_enter(&slp
->ns_alock
);
532 slp
->ns_aflags
&= ~bits
;
533 mutex_exit(&slp
->ns_alock
);
537 nfsdsock_testbits(struct nfssvc_sock
*slp
, int bits
)
540 return (slp
->ns_aflags
& bits
);