2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95
37 * $FreeBSD: src/sys/nfs/nfs_syscalls.c,v 1.58.2.1 2000/11/26 02:30:06 dillon Exp $
38 * $DragonFly: src/sys/vfs/nfs/nfs_syscalls.c,v 1.31 2008/01/05 14:02:41 swildner Exp $
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/sysproto.h>
44 #include <sys/kernel.h>
45 #include <sys/sysctl.h>
47 #include <sys/filedesc.h>
48 #include <sys/vnode.h>
49 #include <sys/malloc.h>
50 #include <sys/mount.h>
55 #include <sys/resourcevar.h>
56 #include <sys/socket.h>
57 #include <sys/socketvar.h>
58 #include <sys/domain.h>
59 #include <sys/protosw.h>
60 #include <sys/nlookup.h>
61 #include <vm/vm_zone.h>
63 #include <netinet/in.h>
64 #include <netinet/tcp.h>
69 #include "nfsm_subs.h"
70 #include "nfsrvcache.h"
75 #include <sys/thread2.h>
77 static MALLOC_DEFINE(M_NFSSVC
, "NFS srvsock", "Nfs server structure");
80 extern int32_t (*nfsrv3_procs
[NFS_NPROCS
]) (struct nfsrv_descript
*nd
,
81 struct nfssvc_sock
*slp
,
84 extern int nfs_numasync
;
86 extern struct nfsstats nfsstats
;
87 extern int nfsrvw_procrastinate
;
88 extern int nfsrvw_procrastinate_v3
;
89 static int nuidhash_max
= NFS_MAXUIDHASH
;
92 static void nfsrv_zapsock (struct nfssvc_sock
*slp
);
94 static int nfssvc_iod (struct thread
*);
99 static int nfs_asyncdaemon
[NFS_MAXASYNCDAEMON
];
101 SYSCTL_DECL(_vfs_nfs
);
104 int nfsd_waiting
= 0;
105 static struct nfsdrt nfsdrt
;
106 static int nfs_numnfsd
= 0;
107 static void nfsd_rt (int sotype
, struct nfsrv_descript
*nd
,
109 static int nfssvc_addsock (struct file
*, struct sockaddr
*,
111 static int nfssvc_nfsd (struct nfsd_srvargs
*,caddr_t
,struct thread
*);
113 static int nfs_privport
= 0;
114 SYSCTL_INT(_vfs_nfs
, NFS_NFSPRIVPORT
, nfs_privport
, CTLFLAG_RW
, &nfs_privport
, 0, "");
115 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, gatherdelay
, CTLFLAG_RW
, &nfsrvw_procrastinate
, 0, "");
116 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, gatherdelay_v3
, CTLFLAG_RW
, &nfsrvw_procrastinate_v3
, 0, "");
117 static int nfs_soreserve
= 65535;
118 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, soreserve
, CTLFLAG_RW
, &nfs_soreserve
, 0, "");
121 * NFS server system calls
124 #endif /* NFS_NOSERVER */
126 * nfssvc_args(int flag, caddr_t argp)
128 * Nfs server psuedo system call for the nfsd's
129 * Based on the flag value it either:
130 * - adds a socket to the selection list
131 * - remains in the kernel as an nfsd
132 * - remains in the kernel as an nfsiod
135 sys_nfssvc(struct nfssvc_args
*uap
)
138 struct nlookupdata nd
;
140 struct sockaddr
*nam
;
141 struct nfsd_args nfsdarg
;
142 struct nfsd_srvargs nfsd_srvargs
, *nsd
= &nfsd_srvargs
;
143 struct nfsd_cargs ncd
;
145 struct nfssvc_sock
*slp
;
146 struct nfsuid
*nuidp
;
147 struct nfsmount
*nmp
;
149 #endif /* NFS_NOSERVER */
151 struct thread
*td
= curthread
;
156 error
= priv_check(td
, PRIV_ROOT
);
159 KKASSERT(td
->td_proc
); /* for ucred and p_fd */
160 while (nfssvc_sockhead_flag
& SLP_INIT
) {
161 nfssvc_sockhead_flag
|= SLP_WANTINIT
;
162 (void) tsleep((caddr_t
)&nfssvc_sockhead
, 0, "nfsd init", 0);
164 if (uap
->flag
& NFSSVC_BIOD
)
165 error
= nfssvc_iod(td
);
169 #else /* !NFS_NOSERVER */
170 else if (uap
->flag
& NFSSVC_MNTD
) {
171 error
= copyin(uap
->argp
, (caddr_t
)&ncd
, sizeof (ncd
));
175 error
= nlookup_init(&nd
, ncd
.ncd_dirp
, UIO_USERSPACE
,
178 error
= nlookup(&nd
);
180 error
= cache_vget(&nd
.nl_nch
, nd
.nl_cred
, LK_EXCLUSIVE
, &vp
);
185 if ((vp
->v_flag
& VROOT
) == 0)
187 nmp
= VFSTONFS(vp
->v_mount
);
191 if ((nmp
->nm_state
& NFSSTA_MNTD
) &&
192 (uap
->flag
& NFSSVC_GOTAUTH
) == 0)
194 nmp
->nm_state
|= NFSSTA_MNTD
;
195 error
= nfs_clientd(nmp
, td
->td_proc
->p_ucred
, &ncd
, uap
->flag
,
197 } else if (uap
->flag
& NFSSVC_ADDSOCK
) {
198 error
= copyin(uap
->argp
, (caddr_t
)&nfsdarg
, sizeof(nfsdarg
));
201 error
= holdsock(td
->td_proc
->p_fd
, nfsdarg
.sock
, &fp
);
205 * Get the client address for connected sockets.
207 if (nfsdarg
.name
== NULL
|| nfsdarg
.namelen
== 0)
208 nam
= (struct sockaddr
*)0;
210 error
= getsockaddr(&nam
, nfsdarg
.name
,
217 error
= nfssvc_addsock(fp
, nam
, td
);
220 error
= copyin(uap
->argp
, (caddr_t
)nsd
, sizeof (*nsd
));
223 if ((uap
->flag
& NFSSVC_AUTHIN
) &&
224 ((nfsd
= nsd
->nsd_nfsd
)) != NULL
&&
225 (nfsd
->nfsd_slp
->ns_flag
& SLP_VALID
)) {
226 slp
= nfsd
->nfsd_slp
;
229 * First check to see if another nfsd has already
230 * added this credential.
232 for (nuidp
= NUIDHASH(slp
,nsd
->nsd_cr
.cr_uid
)->lh_first
;
233 nuidp
!= 0; nuidp
= nuidp
->nu_hash
.le_next
) {
234 if (nuidp
->nu_cr
.cr_uid
== nsd
->nsd_cr
.cr_uid
&&
235 (!nfsd
->nfsd_nd
->nd_nam2
||
236 netaddr_match(NU_NETFAM(nuidp
),
237 &nuidp
->nu_haddr
, nfsd
->nfsd_nd
->nd_nam2
)))
241 nfsrv_setcred(&nuidp
->nu_cr
,&nfsd
->nfsd_nd
->nd_cr
);
242 nfsd
->nfsd_nd
->nd_flag
|= ND_KERBFULL
;
247 if (slp
->ns_numuids
< nuidhash_max
) {
249 nuidp
= (struct nfsuid
*)
250 kmalloc(sizeof (struct nfsuid
), M_NFSUID
,
253 nuidp
= (struct nfsuid
*)0;
254 if ((slp
->ns_flag
& SLP_VALID
) == 0) {
256 kfree((caddr_t
)nuidp
, M_NFSUID
);
258 if (nuidp
== (struct nfsuid
*)0) {
259 nuidp
= TAILQ_FIRST(&slp
->ns_uidlruhead
);
260 LIST_REMOVE(nuidp
, nu_hash
);
261 TAILQ_REMOVE(&slp
->ns_uidlruhead
, nuidp
,
263 if (nuidp
->nu_flag
& NU_NAM
)
264 FREE(nuidp
->nu_nam
, M_SONAME
);
267 nuidp
->nu_cr
= nsd
->nsd_cr
;
268 if (nuidp
->nu_cr
.cr_ngroups
> NGROUPS
)
269 nuidp
->nu_cr
.cr_ngroups
= NGROUPS
;
270 nuidp
->nu_cr
.cr_ref
= 1;
271 nuidp
->nu_timestamp
= nsd
->nsd_timestamp
;
272 nuidp
->nu_expire
= time_second
+ nsd
->nsd_ttl
;
274 * and save the session key in nu_key.
276 bcopy(nsd
->nsd_key
, nuidp
->nu_key
,
277 sizeof (nsd
->nsd_key
));
278 if (nfsd
->nfsd_nd
->nd_nam2
) {
279 struct sockaddr_in
*saddr
;
281 saddr
= (struct sockaddr_in
*)
282 nfsd
->nfsd_nd
->nd_nam2
;
283 switch (saddr
->sin_family
) {
285 nuidp
->nu_flag
|= NU_INETADDR
;
287 saddr
->sin_addr
.s_addr
;
291 nuidp
->nu_flag
|= NU_NAM
;
293 dup_sockaddr(nfsd
->nfsd_nd
->nd_nam2
);
297 TAILQ_INSERT_TAIL(&slp
->ns_uidlruhead
, nuidp
,
299 LIST_INSERT_HEAD(NUIDHASH(slp
, nsd
->nsd_uid
),
301 nfsrv_setcred(&nuidp
->nu_cr
,
302 &nfsd
->nfsd_nd
->nd_cr
);
303 nfsd
->nfsd_nd
->nd_flag
|= ND_KERBFULL
;
307 if ((uap
->flag
& NFSSVC_AUTHINFAIL
) && (nfsd
= nsd
->nsd_nfsd
))
308 nfsd
->nfsd_flag
|= NFSD_AUTHFAIL
;
309 error
= nfssvc_nfsd(nsd
, uap
->argp
, td
);
311 #endif /* NFS_NOSERVER */
312 if (error
== EINTR
|| error
== ERESTART
)
319 * Adds a socket to the list for servicing by nfsds.
322 nfssvc_addsock(struct file
*fp
, struct sockaddr
*mynam
, struct thread
*td
)
325 struct nfssvc_sock
*slp
;
329 so
= (struct socket
*)fp
->f_data
;
331 tslp
= (struct nfssvc_sock
*)0;
333 * Add it to the list, as required.
335 if (so
->so_proto
->pr_protocol
== IPPROTO_UDP
) {
337 if (tslp
->ns_flag
& SLP_VALID
) {
339 FREE(mynam
, M_SONAME
);
345 * Reserve buffer space in the socket. Note that due to bugs in
346 * Linux's delayed-ack code, serious performance degredation may
347 * occur with linux hosts if the minimum is used.
349 if (so
->so_type
== SOCK_STREAM
)
350 siz
= NFS_MAXPACKET
+ sizeof (u_long
);
353 if (siz
< nfs_soreserve
)
355 if (siz
> sb_max_adj
) {
356 kprintf("Warning: vfs.nfs.soreserve (%d) "
357 "limited to adjusted sb_max (%ld)\n",
358 nfs_soreserve
, sb_max_adj
);
362 error
= soreserve(so
, siz
, siz
, &td
->td_proc
->p_rlimit
[RLIMIT_SBSIZE
]);
365 FREE(mynam
, M_SONAME
);
370 * Set protocol specific options { for now TCP only } and
371 * reserve some space. For datagram sockets, this can get called
372 * repeatedly for the same socket, but that isn't harmful.
374 if (so
->so_type
== SOCK_STREAM
) {
378 bzero(&sopt
, sizeof sopt
);
379 sopt
.sopt_level
= SOL_SOCKET
;
380 sopt
.sopt_name
= SO_KEEPALIVE
;
381 sopt
.sopt_val
= &val
;
382 sopt
.sopt_valsize
= sizeof val
;
386 if (so
->so_proto
->pr_domain
->dom_family
== AF_INET
&&
387 so
->so_proto
->pr_protocol
== IPPROTO_TCP
) {
391 bzero(&sopt
, sizeof sopt
);
392 sopt
.sopt_level
= IPPROTO_TCP
;
393 sopt
.sopt_name
= TCP_NODELAY
;
394 sopt
.sopt_val
= &val
;
395 sopt
.sopt_valsize
= sizeof val
;
399 so
->so_rcv
.ssb_flags
&= ~SSB_NOINTR
;
400 so
->so_rcv
.ssb_timeo
= 0;
401 so
->so_snd
.ssb_flags
&= ~SSB_NOINTR
;
402 so
->so_snd
.ssb_timeo
= 0;
404 slp
= (struct nfssvc_sock
*)kmalloc(sizeof (struct nfssvc_sock
),
405 M_NFSSVC
, M_WAITOK
| M_ZERO
);
406 STAILQ_INIT(&slp
->ns_rec
);
407 TAILQ_INIT(&slp
->ns_uidlruhead
);
408 TAILQ_INSERT_TAIL(&nfssvc_sockhead
, slp
, ns_chain
);
415 so
->so_upcallarg
= (caddr_t
)slp
;
416 so
->so_upcall
= nfsrv_rcv
;
417 so
->so_rcv
.ssb_flags
|= SSB_UPCALL
;
418 slp
->ns_flag
= (SLP_VALID
| SLP_NEEDQ
);
419 nfsrv_wakenfsd(slp
, 1);
425 * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
426 * until it is killed by a signal.
429 nfssvc_nfsd(struct nfsd_srvargs
*nsd
, caddr_t argp
, struct thread
*td
)
432 struct nfssvc_sock
*slp
;
433 struct nfsd
*nfsd
= nsd
->nsd_nfsd
;
434 struct nfsrv_descript
*nd
= NULL
;
435 struct mbuf
*m
, *mreq
;
436 int error
= 0, cacherep
, sotype
, writes_todo
;
444 if (nfsd
== (struct nfsd
*)0) {
445 nsd
->nsd_nfsd
= nfsd
= (struct nfsd
*)
446 kmalloc(sizeof (struct nfsd
), M_NFSD
, M_WAITOK
|M_ZERO
);
449 TAILQ_INSERT_TAIL(&nfsd_head
, nfsd
, nfsd_chain
);
455 * Loop getting rpc requests until SIGKILL.
458 if ((nfsd
->nfsd_flag
& NFSD_REQINPROG
) == 0) {
459 while (nfsd
->nfsd_slp
== NULL
&&
460 (nfsd_head_flag
& NFSD_CHECKSLP
) == 0) {
461 nfsd
->nfsd_flag
|= NFSD_WAITING
;
463 error
= tsleep((caddr_t
)nfsd
, PCATCH
, "nfsd", 0);
468 if (nfsd
->nfsd_slp
== NULL
&&
469 (nfsd_head_flag
& NFSD_CHECKSLP
) != 0) {
470 TAILQ_FOREACH(slp
, &nfssvc_sockhead
, ns_chain
) {
471 if ((slp
->ns_flag
& (SLP_VALID
| SLP_DOREC
))
472 == (SLP_VALID
| SLP_DOREC
)) {
473 slp
->ns_flag
&= ~SLP_DOREC
;
475 nfsd
->nfsd_slp
= slp
;
480 nfsd_head_flag
&= ~NFSD_CHECKSLP
;
482 if ((slp
= nfsd
->nfsd_slp
) == (struct nfssvc_sock
*)0)
484 if (slp
->ns_flag
& SLP_VALID
) {
485 if (slp
->ns_flag
& SLP_DISCONN
)
487 else if (slp
->ns_flag
& SLP_NEEDQ
) {
488 slp
->ns_flag
&= ~SLP_NEEDQ
;
489 (void) nfs_slplock(slp
, 1);
490 nfsrv_rcv(slp
->ns_so
, (caddr_t
)slp
,
494 error
= nfsrv_dorec(slp
, nfsd
, &nd
);
495 cur_usec
= nfs_curusec();
496 if (error
&& slp
->ns_tq
.lh_first
&&
497 slp
->ns_tq
.lh_first
->nd_time
<= cur_usec
) {
503 nfsd
->nfsd_flag
|= NFSD_REQINPROG
;
507 slp
= nfsd
->nfsd_slp
;
509 if (error
|| (slp
->ns_flag
& SLP_VALID
) == 0) {
511 kfree((caddr_t
)nd
, M_NFSRVDESC
);
514 nfsd
->nfsd_slp
= (struct nfssvc_sock
*)0;
515 nfsd
->nfsd_flag
&= ~NFSD_REQINPROG
;
520 sotype
= slp
->ns_so
->so_type
;
522 getmicrotime(&nd
->nd_starttime
);
524 nd
->nd_nam
= nd
->nd_nam2
;
526 nd
->nd_nam
= slp
->ns_nam
;
529 * Check to see if authorization is needed.
531 if (nfsd
->nfsd_flag
& NFSD_NEEDAUTH
) {
532 nfsd
->nfsd_flag
&= ~NFSD_NEEDAUTH
;
534 ((struct sockaddr_in
*)
535 nd
->nd_nam
)->sin_addr
.s_addr
;
536 nsd
->nsd_authlen
= nfsd
->nfsd_authlen
;
537 nsd
->nsd_verflen
= nfsd
->nfsd_verflen
;
538 if (!copyout(nfsd
->nfsd_authstr
,nsd
->nsd_authstr
,
539 nfsd
->nfsd_authlen
) &&
540 !copyout(nfsd
->nfsd_verfstr
, nsd
->nsd_verfstr
,
541 nfsd
->nfsd_verflen
) &&
542 !copyout((caddr_t
)nsd
, argp
, sizeof (*nsd
)))
544 cacherep
= RC_DROPIT
;
546 cacherep
= nfsrv_getcache(nd
, slp
, &mreq
);
549 if (nfsd
->nfsd_flag
& NFSD_AUTHFAIL
) {
550 nfsd
->nfsd_flag
&= ~NFSD_AUTHFAIL
;
551 nd
->nd_procnum
= NFSPROC_NOOP
;
552 nd
->nd_repstat
= (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
554 } else if (nfs_privport
) {
555 /* Check if source port is privileged */
557 struct sockaddr
*nam
= nd
->nd_nam
;
558 struct sockaddr_in
*sin
;
560 sin
= (struct sockaddr_in
*)nam
;
561 port
= ntohs(sin
->sin_port
);
562 if (port
>= IPPORT_RESERVED
&&
563 nd
->nd_procnum
!= NFSPROC_NULL
) {
564 nd
->nd_procnum
= NFSPROC_NOOP
;
565 nd
->nd_repstat
= (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
567 kprintf("NFS request from unprivileged port (%s:%d)\n",
568 inet_ntoa(sin
->sin_addr
), port
);
575 * Loop to get all the write rpc relies that have been
581 if (nd
&& (nd
->nd_flag
& ND_NFSV3
))
582 procrastinate
= nfsrvw_procrastinate_v3
;
584 procrastinate
= nfsrvw_procrastinate
;
585 if (writes_todo
|| (nd
->nd_procnum
== NFSPROC_WRITE
&&
588 error
= nfsrv_writegather(&nd
, slp
,
589 nfsd
->nfsd_td
, &mreq
);
591 error
= (*(nfsrv3_procs
[nd
->nd_procnum
]))(nd
,
592 slp
, nfsd
->nfsd_td
, &mreq
);
596 if (error
!= 0 && error
!= NFSERR_RETVOID
) {
597 if (nd
->nd_procnum
!= NQNFSPROC_VACATED
)
599 nfsrv_updatecache(nd
, FALSE
, mreq
);
601 FREE(nd
->nd_nam2
, M_SONAME
);
604 nfsstats
.srvrpccnt
[nd
->nd_procnum
]++;
605 nfsrv_updatecache(nd
, TRUE
, mreq
);
606 nd
->nd_mrep
= (struct mbuf
*)0;
614 if (siz
<= 0 || siz
> NFS_MAXPACKET
) {
615 kprintf("mbuf siz=%d\n",siz
);
616 panic("Bad nfs svc reply");
619 m
->m_pkthdr
.len
= siz
;
620 m
->m_pkthdr
.rcvif
= (struct ifnet
*)0;
622 * For stream protocols, prepend a Sun RPC
625 if (sotype
== SOCK_STREAM
) {
626 M_PREPEND(m
, NFSX_UNSIGNED
, MB_WAIT
);
629 *mtod(m
, u_int32_t
*) = htonl(0x80000000 | siz
);
631 if (slp
->ns_so
->so_proto
->pr_flags
& PR_CONNREQUIRED
)
632 (void) nfs_slplock(slp
, 1);
633 if (slp
->ns_flag
& SLP_VALID
)
634 error
= nfs_send(slp
->ns_so
, nd
->nd_nam2
, m
, NULL
);
640 nfsd_rt(sotype
, nd
, cacherep
);
642 FREE(nd
->nd_nam2
, M_SONAME
);
644 m_freem(nd
->nd_mrep
);
647 if (slp
->ns_so
->so_proto
->pr_flags
& PR_CONNREQUIRED
)
649 if (error
== EINTR
|| error
== ERESTART
) {
650 kfree((caddr_t
)nd
, M_NFSRVDESC
);
658 nfsd_rt(sotype
, nd
, cacherep
);
659 m_freem(nd
->nd_mrep
);
661 FREE(nd
->nd_nam2
, M_SONAME
);
665 FREE((caddr_t
)nd
, M_NFSRVDESC
);
670 * Check to see if there are outstanding writes that
671 * need to be serviced.
673 cur_usec
= nfs_curusec();
675 if (slp
->ns_tq
.lh_first
&&
676 slp
->ns_tq
.lh_first
->nd_time
<= cur_usec
) {
682 } while (writes_todo
);
684 if (nfsrv_dorec(slp
, nfsd
, &nd
)) {
685 nfsd
->nfsd_flag
&= ~NFSD_REQINPROG
;
686 nfsd
->nfsd_slp
= NULL
;
691 TAILQ_REMOVE(&nfsd_head
, nfsd
, nfsd_chain
);
693 kfree((caddr_t
)nfsd
, M_NFSD
);
694 nsd
->nsd_nfsd
= (struct nfsd
*)0;
695 if (--nfs_numnfsd
== 0)
696 nfsrv_init(TRUE
); /* Reinitialize everything */
701 * Shut down a socket associated with an nfssvc_sock structure.
702 * Should be called with the send lock set, if required.
703 * The trick here is to increment the sref at the start, so that the nfsds
704 * will stop using it and clear ns_flag at the end so that it will not be
705 * reassigned during cleanup.
708 nfsrv_zapsock(struct nfssvc_sock
*slp
)
710 struct nfsuid
*nuidp
, *nnuidp
;
711 struct nfsrv_descript
*nwp
, *nnwp
;
714 struct nfsrv_rec
*rec
;
716 slp
->ns_flag
&= ~SLP_ALLFLAGS
;
719 slp
->ns_fp
= (struct file
*)0;
721 so
->so_rcv
.ssb_flags
&= ~SSB_UPCALL
;
722 so
->so_upcall
= NULL
;
723 so
->so_upcallarg
= NULL
;
724 soshutdown(so
, SHUT_RDWR
);
727 FREE(slp
->ns_nam
, M_SONAME
);
728 m_freem(slp
->ns_raw
);
729 while ((rec
= STAILQ_FIRST(&slp
->ns_rec
)) != NULL
) {
731 STAILQ_REMOVE_HEAD(&slp
->ns_rec
, nr_link
);
733 FREE(rec
->nr_address
, M_SONAME
);
734 m_freem(rec
->nr_packet
);
735 kfree(rec
, M_NFSRVDESC
);
737 TAILQ_FOREACH_MUTABLE(nuidp
, &slp
->ns_uidlruhead
, nu_lru
,
739 LIST_REMOVE(nuidp
, nu_hash
);
740 TAILQ_REMOVE(&slp
->ns_uidlruhead
, nuidp
, nu_lru
);
741 if (nuidp
->nu_flag
& NU_NAM
)
742 FREE(nuidp
->nu_nam
, M_SONAME
);
743 kfree((caddr_t
)nuidp
, M_NFSUID
);
746 for (nwp
= slp
->ns_tq
.lh_first
; nwp
; nwp
= nnwp
) {
747 nnwp
= nwp
->nd_tq
.le_next
;
748 LIST_REMOVE(nwp
, nd_tq
);
749 kfree((caddr_t
)nwp
, M_NFSRVDESC
);
751 LIST_INIT(&slp
->ns_tq
);
757 * Derefence a server socket structure. If it has no more references and
758 * is no longer valid, you can throw it away.
761 nfsrv_slpderef(struct nfssvc_sock
*slp
)
763 if (--(slp
->ns_sref
) == 0 && (slp
->ns_flag
& SLP_VALID
) == 0) {
764 TAILQ_REMOVE(&nfssvc_sockhead
, slp
, ns_chain
);
765 kfree((caddr_t
)slp
, M_NFSSVC
);
770 * Lock a socket against others.
773 nfs_slplock(struct nfssvc_sock
*slp
, int wait
)
775 int *statep
= &slp
->ns_solock
;
777 if (!wait
&& (*statep
& NFSSTA_SNDLOCK
))
778 return(0); /* already locked, fail */
779 while (*statep
& NFSSTA_SNDLOCK
) {
780 *statep
|= NFSSTA_WANTSND
;
781 (void) tsleep((caddr_t
)statep
, 0, "nfsslplck", 0);
783 *statep
|= NFSSTA_SNDLOCK
;
788 * Unlock the stream socket for others.
791 nfs_slpunlock(struct nfssvc_sock
*slp
)
793 int *statep
= &slp
->ns_solock
;
795 if ((*statep
& NFSSTA_SNDLOCK
) == 0)
796 panic("nfs slpunlock");
797 *statep
&= ~NFSSTA_SNDLOCK
;
798 if (*statep
& NFSSTA_WANTSND
) {
799 *statep
&= ~NFSSTA_WANTSND
;
800 wakeup((caddr_t
)statep
);
805 * Initialize the data structures for the server.
806 * Handshake with any new nfsds starting up to avoid any chance of
810 nfsrv_init(int terminating
)
812 struct nfssvc_sock
*slp
, *nslp
;
814 if (nfssvc_sockhead_flag
& SLP_INIT
)
816 nfssvc_sockhead_flag
|= SLP_INIT
;
818 TAILQ_FOREACH_MUTABLE(slp
, &nfssvc_sockhead
, ns_chain
, nslp
) {
819 if (slp
->ns_flag
& SLP_VALID
)
821 TAILQ_REMOVE(&nfssvc_sockhead
, slp
, ns_chain
);
822 kfree((caddr_t
)slp
, M_NFSSVC
);
824 nfsrv_cleancache(); /* And clear out server cache */
826 nfs_pub
.np_valid
= 0;
828 TAILQ_INIT(&nfssvc_sockhead
);
829 nfssvc_sockhead_flag
&= ~SLP_INIT
;
830 if (nfssvc_sockhead_flag
& SLP_WANTINIT
) {
831 nfssvc_sockhead_flag
&= ~SLP_WANTINIT
;
832 wakeup((caddr_t
)&nfssvc_sockhead
);
835 TAILQ_INIT(&nfsd_head
);
836 nfsd_head_flag
&= ~NFSD_CHECKSLP
;
839 nfs_udpsock
= (struct nfssvc_sock
*)
840 kmalloc(sizeof (struct nfssvc_sock
), M_NFSSVC
, M_WAITOK
| M_ZERO
);
841 STAILQ_INIT(&nfs_udpsock
->ns_rec
);
842 TAILQ_INIT(&nfs_udpsock
->ns_uidlruhead
);
843 TAILQ_INSERT_HEAD(&nfssvc_sockhead
, nfs_udpsock
, ns_chain
);
845 nfs_cltpsock
= (struct nfssvc_sock
*)
846 kmalloc(sizeof (struct nfssvc_sock
), M_NFSSVC
, M_WAITOK
| M_ZERO
);
847 STAILQ_INIT(&nfs_cltpsock
->ns_rec
);
848 TAILQ_INIT(&nfs_cltpsock
->ns_uidlruhead
);
849 TAILQ_INSERT_TAIL(&nfssvc_sockhead
, nfs_cltpsock
, ns_chain
);
854 * Add entries to the server monitor log.
857 nfsd_rt(int sotype
, struct nfsrv_descript
*nd
, int cacherep
)
861 rt
= &nfsdrt
.drt
[nfsdrt
.pos
];
862 if (cacherep
== RC_DOIT
)
864 else if (cacherep
== RC_REPLY
)
865 rt
->flag
= DRT_CACHEREPLY
;
867 rt
->flag
= DRT_CACHEDROP
;
868 if (sotype
== SOCK_STREAM
)
870 if (nd
->nd_flag
& ND_NFSV3
)
871 rt
->flag
|= DRT_NFSV3
;
872 rt
->proc
= nd
->nd_procnum
;
873 if (nd
->nd_nam
->sa_family
== AF_INET
)
874 rt
->ipadr
= ((struct sockaddr_in
*)nd
->nd_nam
)->sin_addr
.s_addr
;
876 rt
->ipadr
= INADDR_ANY
;
877 rt
->resptime
= nfs_curusec() - (nd
->nd_starttime
.tv_sec
* 1000000 + nd
->nd_starttime
.tv_usec
);
878 getmicrotime(&rt
->tstamp
);
879 nfsdrt
.pos
= (nfsdrt
.pos
+ 1) % NFSRTTLOGSIZ
;
881 #endif /* NFS_NOSERVER */
883 static int nfs_defect
= 0;
884 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, defect
, CTLFLAG_RW
, &nfs_defect
, 0, "");
887 * Asynchronous I/O daemons for client nfs.
888 * They do read-ahead and write-behind operations on the block I/O cache.
889 * Never returns unless it fails or gets killed.
892 nfssvc_iod(struct thread
*td
)
896 struct nfsmount
*nmp
;
900 * Assign my position or return error if too many already running
903 for (i
= 0; i
< NFS_MAXASYNCDAEMON
; i
++)
904 if (nfs_asyncdaemon
[i
] == 0) {
905 nfs_asyncdaemon
[i
]++;
913 * Just loop around doin our stuff until SIGKILL
916 while (((nmp
= nfs_iodmount
[myiod
]) == NULL
917 || TAILQ_EMPTY(&nmp
->nm_bioq
))
921 nfs_iodwant
[myiod
] = td
;
922 nfs_iodmount
[myiod
] = NULL
;
923 error
= tsleep((caddr_t
)&nfs_iodwant
[myiod
],
924 PCATCH
, "nfsidl", 0);
927 nfs_asyncdaemon
[myiod
] = 0;
930 nfs_iodwant
[myiod
] = NULL
;
931 nfs_iodmount
[myiod
] = NULL
;
935 while ((bio
= TAILQ_FIRST(&nmp
->nm_bioq
)) != NULL
) {
937 * Take one off the front of the list. The BIO's
938 * block number is normalized for DEV_BSIZE.
940 TAILQ_REMOVE(&nmp
->nm_bioq
, bio
, bio_act
);
942 if (nmp
->nm_bioqwant
&& nmp
->nm_bioqlen
<= nfs_numasync
) {
943 nmp
->nm_bioqwant
= FALSE
;
944 wakeup(&nmp
->nm_bioq
);
946 nfs_doio((struct vnode
*)bio
->bio_driver_info
, bio
, NULL
);
948 * If there are more than one iod on this mount, then defect
949 * so that the iods can be shared out fairly between the mounts
951 if (nfs_defect
&& nmp
->nm_bioqiods
> 1) {
953 ("nfssvc_iod: iod %d defecting from mount %p\n",
955 nfs_iodmount
[myiod
] = NULL
;
965 * Get an authorization string for the uid by having the mount_nfs sitting
966 * on this mount point porpous out of the kernel and do it.
969 nfs_getauth(struct nfsmount
*nmp
, struct nfsreq
*rep
,
970 struct ucred
*cred
, char **auth_str
, int *auth_len
, char *verf_str
,
971 int *verf_len
, NFSKERBKEY_T key
/* return session key */)
975 while ((nmp
->nm_state
& NFSSTA_WAITAUTH
) == 0) {
976 nmp
->nm_state
|= NFSSTA_WANTAUTH
;
977 (void) tsleep((caddr_t
)&nmp
->nm_authtype
, 0,
979 error
= nfs_sigintr(nmp
, rep
, rep
->r_td
);
981 nmp
->nm_state
&= ~NFSSTA_WANTAUTH
;
985 nmp
->nm_state
&= ~(NFSSTA_WAITAUTH
| NFSSTA_WANTAUTH
);
986 nmp
->nm_authstr
= *auth_str
= (char *)kmalloc(RPCAUTH_MAXSIZ
, M_TEMP
, M_WAITOK
);
987 nmp
->nm_authlen
= RPCAUTH_MAXSIZ
;
988 nmp
->nm_verfstr
= verf_str
;
989 nmp
->nm_verflen
= *verf_len
;
990 nmp
->nm_authuid
= cred
->cr_uid
;
991 wakeup((caddr_t
)&nmp
->nm_authstr
);
994 * And wait for mount_nfs to do its stuff.
996 while ((nmp
->nm_state
& NFSSTA_HASAUTH
) == 0 && error
== 0) {
997 (void) tsleep((caddr_t
)&nmp
->nm_authlen
, 0,
999 error
= nfs_sigintr(nmp
, rep
, rep
->r_td
);
1001 if (nmp
->nm_state
& NFSSTA_AUTHERR
) {
1002 nmp
->nm_state
&= ~NFSSTA_AUTHERR
;
1006 kfree((caddr_t
)*auth_str
, M_TEMP
);
1008 *auth_len
= nmp
->nm_authlen
;
1009 *verf_len
= nmp
->nm_verflen
;
1010 bcopy((caddr_t
)nmp
->nm_key
, (caddr_t
)key
, sizeof (key
));
1012 nmp
->nm_state
&= ~NFSSTA_HASAUTH
;
1013 nmp
->nm_state
|= NFSSTA_WAITAUTH
;
1014 if (nmp
->nm_state
& NFSSTA_WANTAUTH
) {
1015 nmp
->nm_state
&= ~NFSSTA_WANTAUTH
;
1016 wakeup((caddr_t
)&nmp
->nm_authtype
);
1022 * Get a nickname authenticator and verifier.
1025 nfs_getnickauth(struct nfsmount
*nmp
, struct ucred
*cred
, char **auth_str
,
1026 int *auth_len
, char *verf_str
, int verf_len
)
1028 struct nfsuid
*nuidp
;
1029 u_int32_t
*nickp
, *verfp
;
1030 struct timeval ktvin
, ktvout
;
1033 if (verf_len
< (4 * NFSX_UNSIGNED
))
1034 panic("nfs_getnickauth verf too small");
1036 for (nuidp
= NMUIDHASH(nmp
, cred
->cr_uid
)->lh_first
;
1037 nuidp
!= 0; nuidp
= nuidp
->nu_hash
.le_next
) {
1038 if (nuidp
->nu_cr
.cr_uid
== cred
->cr_uid
)
1041 if (!nuidp
|| nuidp
->nu_expire
< time_second
)
1045 * Move to the end of the lru list (end of lru == most recently used).
1047 TAILQ_REMOVE(&nmp
->nm_uidlruhead
, nuidp
, nu_lru
);
1048 TAILQ_INSERT_TAIL(&nmp
->nm_uidlruhead
, nuidp
, nu_lru
);
1050 nickp
= (u_int32_t
*)kmalloc(2 * NFSX_UNSIGNED
, M_TEMP
, M_WAITOK
);
1051 *nickp
++ = txdr_unsigned(RPCAKN_NICKNAME
);
1052 *nickp
= txdr_unsigned(nuidp
->nu_nickname
);
1053 *auth_str
= (char *)nickp
;
1054 *auth_len
= 2 * NFSX_UNSIGNED
;
1057 * Now we must encrypt the verifier and package it up.
1059 verfp
= (u_int32_t
*)verf_str
;
1060 *verfp
++ = txdr_unsigned(RPCAKN_NICKNAME
);
1061 if (time_second
> nuidp
->nu_timestamp
.tv_sec
||
1062 (time_second
== nuidp
->nu_timestamp
.tv_sec
&&
1063 time_second
> nuidp
->nu_timestamp
.tv_usec
))
1064 getmicrotime(&nuidp
->nu_timestamp
);
1066 nuidp
->nu_timestamp
.tv_usec
++;
1067 ktvin
.tv_sec
= txdr_unsigned(nuidp
->nu_timestamp
.tv_sec
);
1068 ktvin
.tv_usec
= txdr_unsigned(nuidp
->nu_timestamp
.tv_usec
);
1071 * Now encrypt the timestamp verifier in ecb mode using the session
1078 *verfp
++ = ktvout
.tv_sec
;
1079 *verfp
++ = ktvout
.tv_usec
;
1085 * Save the current nickname in a hash list entry on the mount point.
1088 nfs_savenickauth(struct nfsmount
*nmp
, struct ucred
*cred
, int len
,
1089 NFSKERBKEY_T key
, struct mbuf
**mdp
, char **dposp
,
1092 struct nfsuid
*nuidp
;
1095 struct mbuf
*md
= *mdp
;
1096 struct timeval ktvin
, ktvout
;
1098 char *dpos
= *dposp
, *cp2
;
1099 int deltasec
, error
= 0;
1101 if (len
== (3 * NFSX_UNSIGNED
)) {
1102 nfsm_dissect(tl
, u_int32_t
*, 3 * NFSX_UNSIGNED
);
1103 ktvin
.tv_sec
= *tl
++;
1104 ktvin
.tv_usec
= *tl
++;
1105 nick
= fxdr_unsigned(u_int32_t
, *tl
);
1108 * Decrypt the timestamp in ecb mode.
1113 ktvout
.tv_sec
= fxdr_unsigned(long, ktvout
.tv_sec
);
1114 ktvout
.tv_usec
= fxdr_unsigned(long, ktvout
.tv_usec
);
1115 deltasec
= time_second
- ktvout
.tv_sec
;
1117 deltasec
= -deltasec
;
1119 * If ok, add it to the hash list for the mount point.
1121 if (deltasec
<= NFS_KERBCLOCKSKEW
) {
1122 if (nmp
->nm_numuids
< nuidhash_max
) {
1124 nuidp
= (struct nfsuid
*)
1125 kmalloc(sizeof (struct nfsuid
), M_NFSUID
,
1128 nuidp
= TAILQ_FIRST(&nmp
->nm_uidlruhead
);
1129 LIST_REMOVE(nuidp
, nu_hash
);
1130 TAILQ_REMOVE(&nmp
->nm_uidlruhead
, nuidp
,
1134 nuidp
->nu_cr
.cr_uid
= cred
->cr_uid
;
1135 nuidp
->nu_expire
= time_second
+ NFS_KERBTTL
;
1136 nuidp
->nu_timestamp
= ktvout
;
1137 nuidp
->nu_nickname
= nick
;
1138 bcopy(key
, nuidp
->nu_key
, sizeof (key
));
1139 TAILQ_INSERT_TAIL(&nmp
->nm_uidlruhead
, nuidp
,
1141 LIST_INSERT_HEAD(NMUIDHASH(nmp
, cred
->cr_uid
),
1145 nfsm_adv(nfsm_rndup(len
));