2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
27 * Copyright (c) 1989, 1993
28 * The Regents of the University of California. All rights reserved.
30 * This code is derived from software contributed to Berkeley by
31 * Rick Macklem at The University of Guelph.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95
62 * FreeBSD-Id: nfs_syscalls.c,v 1.32 1997/11/07 08:53:25 phk Exp $
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 /* XXX CSM 11/25/97 FreeBSD's generated syscall prototypes */
69 #include <sys/sysproto.h>
71 #include <sys/kernel.h>
73 #include <sys/filedesc.h>
75 #include <sys/vnode.h>
76 #include <sys/mount.h>
78 #include <sys/sysctl.h>
80 #include <sys/malloc.h>
83 #include <sys/socket.h>
84 #include <sys/socketvar.h>
85 #include <sys/domain.h>
86 #include <sys/protosw.h>
87 #include <sys/namei.h>
88 #include <sys/syslog.h>
90 #include <machine/spl.h>
92 #include <netinet/in.h>
93 #include <netinet/tcp.h>
95 #include <netiso/iso.h>
97 #include <nfs/xdr_subs.h>
98 #include <nfs/rpcv2.h>
99 #include <nfs/nfsproto.h>
101 #include <nfs/nfsm_subs.h>
102 #include <nfs/nfsrvcache.h>
103 #include <nfs/nfsmount.h>
104 #include <nfs/nfsnode.h>
105 #include <nfs/nqnfs.h>
106 #include <nfs/nfsrtt.h>
110 extern int (*nfsrv3_procs
[NFS_NPROCS
]) __P((struct nfsrv_descript
*nd
,
111 struct nfssvc_sock
*slp
,
113 struct mbuf
**mreqp
));
114 extern int nfs_numasync
;
115 extern time_t nqnfsstarttime
;
116 extern int nqsrv_writeslack
;
118 extern struct nfsstats nfsstats
;
119 extern int nfsrvw_procrastinate
;
120 extern int nfsrvw_procrastinate_v3
;
121 struct nfssvc_sock
*nfs_udpsock
, *nfs_cltpsock
;
122 static int nuidhash_max
= NFS_MAXUIDHASH
;
124 static void nfsrv_zapsock
__P((struct nfssvc_sock
*slp
));
125 static int nfssvc_iod
__P((struct proc
*));
130 static int nfs_asyncdaemon
[NFS_MAXASYNCDAEMON
];
133 int nfsd_waiting
= 0;
134 static struct nfsdrt nfsdrt
;
135 static int nfs_numnfsd
= 0;
136 static int notstarted
= 1;
137 static int modify_flag
= 0;
138 static void nfsd_rt
__P((int sotype
, struct nfsrv_descript
*nd
,
140 static int nfssvc_addsock
__P((struct file
*, struct mbuf
*,
142 static int nfssvc_nfsd
__P((struct nfsd_srvargs
*,caddr_t
,struct proc
*));
144 static int nfs_privport
= 0;
145 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
147 SYSCTL_INT(_vfs_nfs
, NFS_NFSPRIVPORT
, nfs_privport
, CTLFLAG_RW
, &nfs_privport
, 0, "");
148 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, gatherdelay
, CTLFLAG_RW
, &nfsrvw_procrastinate
, 0, "");
149 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, gatherdelay_v3
, CTLFLAG_RW
, &nfsrvw_procrastinate_v3
, 0, "");
153 * NFS server system calls
154 * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
158 * Get file handle system call
160 #ifndef _SYS_SYSPROTO_H_
169 register struct getfh_args
*uap
;
171 register struct vnode
*vp
;
179 error
= suser(p
->p_ucred
, &p
->p_acflag
);
182 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
, uap
->fname
, p
);
187 bzero((caddr_t
)&fh
, sizeof(fh
));
188 fh
.fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
189 error
= VFS_VPTOFH(vp
, &fh
.fh_fid
);
193 error
= copyout((caddr_t
)&fh
, (caddr_t
)uap
->fhp
, sizeof (fh
));
197 #endif /* NFS_NOSERVER */
199 * Nfs server psuedo system call for the nfsd's
200 * Based on the flag value it either:
201 * - adds a socket to the selection list
202 * - remains in the kernel as an nfsd
203 * - remains in the kernel as an nfsiod
205 #ifndef _SYS_SYSPROTO_H_
214 register struct nfssvc_args
*uap
;
220 struct nfsd_args nfsdarg
;
221 struct nfsd_srvargs nfsd_srvargs
, *nsd
= &nfsd_srvargs
;
222 struct nfsd_cargs ncd
;
224 struct nfssvc_sock
*slp
;
225 struct nfsuid
*nuidp
;
226 struct nfsmount
*nmp
;
227 #endif /* NFS_NOSERVER */
233 error
= suser(p
->p_ucred
, &p
->p_acflag
);
236 while (nfssvc_sockhead_flag
& SLP_INIT
) {
237 nfssvc_sockhead_flag
|= SLP_WANTINIT
;
238 (void) tsleep((caddr_t
)&nfssvc_sockhead
, PSOCK
, "nfsd init", 0);
240 if (uap
->flag
& NFSSVC_BIOD
)
241 error
= nfssvc_iod(p
);
245 #else /* !NFS_NOSERVER */
246 else if (uap
->flag
& NFSSVC_MNTD
) {
247 error
= copyin(uap
->argp
, (caddr_t
)&ncd
, sizeof (ncd
));
250 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
, UIO_USERSPACE
,
255 if ((nd
.ni_vp
->v_flag
& VROOT
) == 0)
257 nmp
= VFSTONFS(nd
.ni_vp
->v_mount
);
262 /* disable split funnels now */
263 thread_funnel_merge(kernel_flock
, network_flock
);
265 if ((nmp
->nm_flag
& NFSMNT_MNTD
) &&
266 (uap
->flag
& NFSSVC_GOTAUTH
) == 0)
268 nmp
->nm_flag
|= NFSMNT_MNTD
;
269 error
= nqnfs_clientd(nmp
, p
->p_ucred
, &ncd
, uap
->flag
,
271 } else if (uap
->flag
& NFSSVC_ADDSOCK
) {
272 error
= copyin(uap
->argp
, (caddr_t
)&nfsdarg
, sizeof(nfsdarg
));
275 error
= getsock(p
->p_fd
, nfsdarg
.sock
, &fp
);
279 * Get the client address for connected sockets.
281 if (nfsdarg
.name
== NULL
|| nfsdarg
.namelen
== 0)
282 nam
= (struct mbuf
*)0;
284 error
= sockargs(&nam
, nfsdarg
.name
, nfsdarg
.namelen
,
289 error
= nfssvc_addsock(fp
, nam
, p
);
291 error
= copyin(uap
->argp
, (caddr_t
)nsd
, sizeof (*nsd
));
295 /* disable split funnels now */
296 thread_funnel_merge(kernel_flock
, network_flock
);
298 if ((uap
->flag
& NFSSVC_AUTHIN
) && ((nfsd
= nsd
->nsd_nfsd
)) &&
299 (nfsd
->nfsd_slp
->ns_flag
& SLP_VALID
)) {
300 slp
= nfsd
->nfsd_slp
;
303 * First check to see if another nfsd has already
304 * added this credential.
306 for (nuidp
= NUIDHASH(slp
,nsd
->nsd_cr
.cr_uid
)->lh_first
;
307 nuidp
!= 0; nuidp
= nuidp
->nu_hash
.le_next
) {
308 if (nuidp
->nu_cr
.cr_uid
== nsd
->nsd_cr
.cr_uid
&&
309 (!nfsd
->nfsd_nd
->nd_nam2
||
310 netaddr_match(NU_NETFAM(nuidp
),
311 &nuidp
->nu_haddr
, nfsd
->nfsd_nd
->nd_nam2
)))
315 nfsrv_setcred(&nuidp
->nu_cr
,&nfsd
->nfsd_nd
->nd_cr
);
316 nfsd
->nfsd_nd
->nd_flag
|= ND_KERBFULL
;
321 if (slp
->ns_numuids
< nuidhash_max
) {
323 nuidp
= (struct nfsuid
*)
324 _MALLOC_ZONE(sizeof (struct nfsuid
),
327 nuidp
= (struct nfsuid
*)0;
328 if ((slp
->ns_flag
& SLP_VALID
) == 0) {
330 _FREE_ZONE((caddr_t
)nuidp
,
331 sizeof (struct nfsuid
), M_NFSUID
);
333 if (nuidp
== (struct nfsuid
*)0) {
334 nuidp
= slp
->ns_uidlruhead
.tqh_first
;
335 LIST_REMOVE(nuidp
, nu_hash
);
336 TAILQ_REMOVE(&slp
->ns_uidlruhead
, nuidp
,
338 if (nuidp
->nu_flag
& NU_NAM
)
339 m_freem(nuidp
->nu_nam
);
342 nuidp
->nu_cr
= nsd
->nsd_cr
;
343 if (nuidp
->nu_cr
.cr_ngroups
> NGROUPS
)
344 nuidp
->nu_cr
.cr_ngroups
= NGROUPS
;
345 nuidp
->nu_cr
.cr_ref
= 1;
346 nuidp
->nu_timestamp
= nsd
->nsd_timestamp
;
347 nuidp
->nu_expire
= time
.tv_sec
+ nsd
->nsd_ttl
;
349 * and save the session key in nu_key.
351 bcopy(nsd
->nsd_key
, nuidp
->nu_key
,
352 sizeof (nsd
->nsd_key
));
353 if (nfsd
->nfsd_nd
->nd_nam2
) {
354 struct sockaddr_in
*saddr
;
356 saddr
= mtod(nfsd
->nfsd_nd
->nd_nam2
,
357 struct sockaddr_in
*);
358 switch (saddr
->sin_family
) {
360 nuidp
->nu_flag
|= NU_INETADDR
;
362 saddr
->sin_addr
.s_addr
;
366 nuidp
->nu_flag
|= NU_NAM
;
367 nuidp
->nu_nam
= m_copym(
368 nfsd
->nfsd_nd
->nd_nam2
, 0,
373 TAILQ_INSERT_TAIL(&slp
->ns_uidlruhead
, nuidp
,
375 LIST_INSERT_HEAD(NUIDHASH(slp
, nsd
->nsd_uid
),
377 nfsrv_setcred(&nuidp
->nu_cr
,
378 &nfsd
->nfsd_nd
->nd_cr
);
379 nfsd
->nfsd_nd
->nd_flag
|= ND_KERBFULL
;
383 if ((uap
->flag
& NFSSVC_AUTHINFAIL
) && (nfsd
= nsd
->nsd_nfsd
))
384 nfsd
->nfsd_flag
|= NFSD_AUTHFAIL
;
385 error
= nfssvc_nfsd(nsd
, uap
->argp
, p
);
387 #endif /* NFS_NOSERVER */
388 if (error
== EINTR
|| error
== ERESTART
)
395 * Adds a socket to the list for servicing by nfsds.
398 nfssvc_addsock(fp
, mynam
, p
)
403 register struct mbuf
*m
;
405 register struct nfssvc_sock
*slp
;
406 register struct socket
*so
;
407 struct nfssvc_sock
*tslp
;
410 so
= (struct socket
*)fp
->f_data
;
411 tslp
= (struct nfssvc_sock
*)0;
413 * Add it to the list, as required.
415 thread_funnel_switch(KERNEL_FUNNEL
, NETWORK_FUNNEL
);
416 if (so
->so_proto
->pr_protocol
== IPPROTO_UDP
) {
418 if (tslp
->ns_flag
& SLP_VALID
) {
420 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
424 } else if (so
->so_proto
->pr_protocol
== ISOPROTO_CLTP
) {
426 if (tslp
->ns_flag
& SLP_VALID
) {
428 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
433 if (so
->so_type
== SOCK_STREAM
)
434 siz
= NFS_MAXPACKET
+ sizeof (u_long
);
437 error
= soreserve(so
, siz
, siz
);
440 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
445 * Set protocol specific options { for now TCP only } and
446 * reserve some space. For datagram sockets, this can get called
447 * repeatedly for the same socket, but that isn't harmful.
449 if (so
->so_type
== SOCK_STREAM
) {
453 bzero(&sopt
, sizeof sopt
);
454 sopt
.sopt_level
= SOL_SOCKET
;
455 sopt
.sopt_name
= SO_KEEPALIVE
;
456 sopt
.sopt_val
= &val
;
457 sopt
.sopt_valsize
= sizeof val
;
461 if (so
->so_proto
->pr_domain
->dom_family
== AF_INET
&&
462 so
->so_proto
->pr_protocol
== IPPROTO_TCP
) {
466 bzero(&sopt
, sizeof sopt
);
467 sopt
.sopt_level
= IPPROTO_TCP
;
468 sopt
.sopt_name
= TCP_NODELAY
;
469 sopt
.sopt_val
= &val
;
470 sopt
.sopt_valsize
= sizeof val
;
475 so
->so_rcv
.sb_flags
&= ~SB_NOINTR
;
476 so
->so_rcv
.sb_timeo
= 0;
477 so
->so_snd
.sb_flags
&= ~SB_NOINTR
;
478 so
->so_snd
.sb_timeo
= 0;
479 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
483 MALLOC(slp
, struct nfssvc_sock
*, sizeof(struct nfssvc_sock
),
485 bzero((caddr_t
)slp
, sizeof (struct nfssvc_sock
));
486 TAILQ_INIT(&slp
->ns_uidlruhead
);
487 TAILQ_INSERT_TAIL(&nfssvc_sockhead
, slp
, ns_chain
);
493 thread_funnel_switch(KERNEL_FUNNEL
, NETWORK_FUNNEL
);
495 so
->so_upcallarg
= (caddr_t
)slp
;
496 so
->so_upcall
= nfsrv_rcv
;
497 so
->so_rcv
.sb_flags
|= SB_UPCALL
; /* required for freebsd merge */
498 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
499 slp
->ns_flag
= (SLP_VALID
| SLP_NEEDQ
);
506 * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
507 * until it is killed by a signal.
510 nfssvc_nfsd(nsd
, argp
, p
)
511 struct nfsd_srvargs
*nsd
;
515 register struct mbuf
*m
;
517 register struct nfssvc_sock
*slp
;
518 register struct socket
*so
;
519 register int *solockp
;
520 struct nfsd
*nfsd
= nsd
->nsd_nfsd
;
521 struct nfsrv_descript
*nd
= NULL
;
523 int error
= 0, cacherep
, s
, sotype
, writes_todo
;
526 extern void nfs_aio_thread_init();
533 if (nfsd
== (struct nfsd
*)0) {
534 MALLOC(nfsd
, struct nfsd
*, sizeof(struct nfsd
), M_NFSD
, M_WAITOK
);
535 nsd
->nsd_nfsd
= nfsd
;
536 bzero((caddr_t
)nfsd
, sizeof (struct nfsd
));
537 nfsd
->nfsd_procp
= p
;
538 TAILQ_INSERT_TAIL(&nfsd_head
, nfsd
, nfsd_chain
);
540 nfs_aio_thread_init();
543 * Loop getting rpc requests until SIGKILL.
546 if ((nfsd
->nfsd_flag
& NFSD_REQINPROG
) == 0) {
547 while (nfsd
->nfsd_slp
== (struct nfssvc_sock
*)0 &&
548 (nfsd_head_flag
& NFSD_CHECKSLP
) == 0) {
549 nfsd
->nfsd_flag
|= NFSD_WAITING
;
551 error
= tsleep((caddr_t
)nfsd
, PSOCK
| PCATCH
,
557 if (nfsd
->nfsd_slp
== (struct nfssvc_sock
*)0 &&
558 (nfsd_head_flag
& NFSD_CHECKSLP
) != 0) {
559 for (slp
= nfssvc_sockhead
.tqh_first
; slp
!= 0;
560 slp
= slp
->ns_chain
.tqe_next
) {
561 if ((slp
->ns_flag
& (SLP_VALID
| SLP_DOREC
))
562 == (SLP_VALID
| SLP_DOREC
)) {
563 slp
->ns_flag
&= ~SLP_DOREC
;
565 nfsd
->nfsd_slp
= slp
;
570 nfsd_head_flag
&= ~NFSD_CHECKSLP
;
572 if ((slp
= nfsd
->nfsd_slp
) == (struct nfssvc_sock
*)0)
574 if (slp
->ns_flag
& SLP_VALID
) {
575 if (slp
->ns_flag
& SLP_DISCONN
)
577 else if (slp
->ns_flag
& SLP_NEEDQ
) {
578 slp
->ns_flag
&= ~SLP_NEEDQ
;
579 (void) nfs_sndlock(&slp
->ns_solock
,
581 thread_funnel_switch(KERNEL_FUNNEL
, NETWORK_FUNNEL
);
582 nfsrv_rcv(slp
->ns_so
, (caddr_t
)slp
,
584 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
585 nfs_sndunlock(&slp
->ns_solock
);
587 error
= nfsrv_dorec(slp
, nfsd
, &nd
);
588 cur_usec
= (u_quad_t
)time
.tv_sec
* 1000000 +
589 (u_quad_t
)time
.tv_usec
;
590 if (error
&& slp
->ns_tq
.lh_first
&&
591 slp
->ns_tq
.lh_first
->nd_time
<= cur_usec
) {
597 nfsd
->nfsd_flag
|= NFSD_REQINPROG
;
601 slp
= nfsd
->nfsd_slp
;
603 if (error
|| (slp
->ns_flag
& SLP_VALID
) == 0) {
605 _FREE_ZONE((caddr_t
)nd
,
606 sizeof *nd
, M_NFSRVDESC
);
609 nfsd
->nfsd_slp
= (struct nfssvc_sock
*)0;
610 nfsd
->nfsd_flag
&= ~NFSD_REQINPROG
;
616 sotype
= so
->so_type
;
617 if (so
->so_proto
->pr_flags
& PR_CONNREQUIRED
)
618 solockp
= &slp
->ns_solock
;
622 nd
->nd_starttime
= time
;
624 nd
->nd_nam
= nd
->nd_nam2
;
626 nd
->nd_nam
= slp
->ns_nam
;
629 * Check to see if authorization is needed.
631 if (nfsd
->nfsd_flag
& NFSD_NEEDAUTH
) {
632 nfsd
->nfsd_flag
&= ~NFSD_NEEDAUTH
;
633 nsd
->nsd_haddr
= mtod(nd
->nd_nam
,
634 struct sockaddr_in
*)->sin_addr
.s_addr
;
635 nsd
->nsd_authlen
= nfsd
->nfsd_authlen
;
636 nsd
->nsd_verflen
= nfsd
->nfsd_verflen
;
637 if (!copyout(nfsd
->nfsd_authstr
,nsd
->nsd_authstr
,
638 nfsd
->nfsd_authlen
) &&
639 !copyout(nfsd
->nfsd_verfstr
, nsd
->nsd_verfstr
,
640 nfsd
->nfsd_verflen
) &&
641 !copyout((caddr_t
)nsd
, argp
, sizeof (*nsd
)))
643 cacherep
= RC_DROPIT
;
645 cacherep
= nfsrv_getcache(nd
, slp
, &mreq
);
648 * Check for just starting up for NQNFS and send
649 * fake "try again later" replies to the NQNFS clients.
651 if (notstarted
&& nqnfsstarttime
<= time
.tv_sec
) {
653 nqnfsstarttime
= time
.tv_sec
+ nqsrv_writeslack
;
659 if ((nd
->nd_flag
& ND_NQNFS
) == 0)
660 cacherep
= RC_DROPIT
;
661 else if (nd
->nd_procnum
!= NFSPROC_WRITE
) {
662 nd
->nd_procnum
= NFSPROC_NOOP
;
663 nd
->nd_repstat
= NQNFS_TRYLATER
;
667 } else if (nfsd
->nfsd_flag
& NFSD_AUTHFAIL
) {
668 nfsd
->nfsd_flag
&= ~NFSD_AUTHFAIL
;
669 nd
->nd_procnum
= NFSPROC_NOOP
;
670 nd
->nd_repstat
= (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
672 } else if (nfs_privport
) {
673 /* Check if source port is privileged */
675 struct sockaddr
*nam
= nd
->nd_nam
;
676 struct sockaddr_in
*sin
;
678 sin
= (struct sockaddr_in
*)nam
;
679 port
= ntohs(sin
->sin_port
);
680 if (port
>= IPPORT_RESERVED
&&
681 nd
->nd_procnum
!= NFSPROC_NULL
) {
682 nd
->nd_procnum
= NFSPROC_NOOP
;
683 nd
->nd_repstat
= (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
685 printf("NFS request from unprivileged port (%s:%d)\n",
686 (char *)(inet_ntoa(sin
->sin_addr
)), port
);
693 * Loop to get all the write rpc relies that have been
699 if (nd
&& (nd
->nd_flag
& ND_NFSV3
))
700 procrastinate
= nfsrvw_procrastinate_v3
;
702 procrastinate
= nfsrvw_procrastinate
;
703 if (writes_todo
|| (nd
->nd_procnum
== NFSPROC_WRITE
&&
704 procrastinate
> 0 && !notstarted
))
705 error
= nfsrv_writegather(&nd
, slp
,
706 nfsd
->nfsd_procp
, &mreq
);
708 error
= (*(nfsrv3_procs
[nd
->nd_procnum
]))(nd
,
709 slp
, nfsd
->nfsd_procp
, &mreq
);
713 if (nd
->nd_procnum
!= NQNFSPROC_VACATED
)
715 nfsrv_updatecache(nd
, FALSE
, mreq
);
717 m_freem(nd
->nd_nam2
);
720 nfsstats
.srvrpccnt
[nd
->nd_procnum
]++;
721 nfsrv_updatecache(nd
, TRUE
, mreq
);
722 nd
->nd_mrep
= (struct mbuf
*)0;
730 if (siz
<= 0 || siz
> NFS_MAXPACKET
) {
731 printf("mbuf siz=%d\n",siz
);
732 panic("Bad nfs svc reply");
735 m
->m_pkthdr
.len
= siz
;
736 m
->m_pkthdr
.rcvif
= (struct ifnet
*)0;
738 * For stream protocols, prepend a Sun RPC
741 if (sotype
== SOCK_STREAM
) {
742 M_PREPEND(m
, NFSX_UNSIGNED
, M_WAIT
);
743 *mtod(m
, u_long
*) = htonl(0x80000000 | siz
);
746 (void) nfs_sndlock(solockp
, (struct nfsreq
*)0);
747 if (slp
->ns_flag
& SLP_VALID
)
748 error
= nfs_send(so
, nd
->nd_nam2
, m
, NULL
);
754 nfsd_rt(sotype
, nd
, cacherep
);
756 MFREE(nd
->nd_nam2
, m
);
758 m_freem(nd
->nd_mrep
);
762 nfs_sndunlock(solockp
);
763 if (error
== EINTR
|| error
== ERESTART
) {
764 _FREE_ZONE((caddr_t
)nd
,
765 sizeof *nd
, M_NFSRVDESC
);
773 nfsd_rt(sotype
, nd
, cacherep
);
774 m_freem(nd
->nd_mrep
);
775 m_freem(nd
->nd_nam2
);
779 FREE_ZONE((caddr_t
)nd
, sizeof *nd
, M_NFSRVDESC
);
784 * Check to see if there are outstanding writes that
785 * need to be serviced.
787 cur_usec
= (u_quad_t
)time
.tv_sec
* 1000000 +
788 (u_quad_t
)time
.tv_usec
;
790 if (slp
->ns_tq
.lh_first
&&
791 slp
->ns_tq
.lh_first
->nd_time
<= cur_usec
) {
797 } while (writes_todo
);
799 if (nfsrv_dorec(slp
, nfsd
, &nd
)) {
800 nfsd
->nfsd_flag
&= ~NFSD_REQINPROG
;
801 nfsd
->nfsd_slp
= NULL
;
806 TAILQ_REMOVE(&nfsd_head
, nfsd
, nfsd_chain
);
808 _FREE((caddr_t
)nfsd
, M_NFSD
);
809 nsd
->nsd_nfsd
= (struct nfsd
*)0;
810 if (--nfs_numnfsd
== 0)
811 nfsrv_init(TRUE
); /* Reinitialize everything */
814 #endif /* NFS_NOSERVER */
817 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
819 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, defect
, CTLFLAG_RW
, &nfs_defect
, 0, "");
822 static int nfssvc_iod_continue(int);
825 * Asynchronous I/O daemons for client nfs.
826 * They do read-ahead and write-behind operations on the block I/O cache.
827 * Never returns unless it fails or gets killed.
833 register struct buf
*bp
;
834 register int i
, myiod
;
835 struct nfsmount
*nmp
;
840 * Assign my position or return error if too many already running
843 for (i
= 0; i
< NFS_MAXASYNCDAEMON
; i
++)
844 if (nfs_asyncdaemon
[i
] == 0) {
845 nfs_asyncdaemon
[i
]++;
853 /* stuff myiod into uthread to get off local stack for
856 ut
= (struct uthread
*)get_bsdthread_info(current_act());
857 ut
->uu_state
.uu_nfs_myiod
= myiod
; /* squirrel away for continuation */
859 nfssvc_iod_continue(0);
865 * Continuation for Asynchronous I/O daemons for client nfs.
868 nfssvc_iod_continue(error
)
870 register struct buf
*bp
;
871 register int i
, myiod
;
872 struct nfsmount
*nmp
;
877 * real myiod is stored in uthread, recover it
879 ut
= (struct uthread
*)get_bsdthread_info(current_act());
880 myiod
= ut
->uu_state
.uu_nfs_myiod
;
884 * Just loop around doin our stuff until SIGKILL
885 * - actually we don't loop with continuations...
888 while (((nmp
= nfs_iodmount
[myiod
]) == NULL
889 || nmp
->nm_bufq
.tqh_first
== NULL
)
893 nfs_iodwant
[myiod
] = p
;
894 nfs_iodmount
[myiod
] = NULL
;
895 error
= tsleep0((caddr_t
)&nfs_iodwant
[myiod
],
896 PWAIT
| PCATCH
, "nfsidl", 0, nfssvc_iod_continue
);
900 nfs_asyncdaemon
[myiod
] = 0;
901 if (nmp
) nmp
->nm_bufqiods
--;
902 nfs_iodwant
[myiod
] = NULL
;
903 nfs_iodmount
[myiod
] = NULL
;
905 if (error
== EINTR
|| error
== ERESTART
)
907 unix_syscall_return(error
);
909 while ((bp
= nmp
->nm_bufq
.tqh_first
) != NULL
) {
910 /* Take one off the front of the list */
911 TAILQ_REMOVE(&nmp
->nm_bufq
, bp
, b_freelist
);
913 if (nmp
->nm_bufqwant
&& nmp
->nm_bufqlen
< 2 * nfs_numasync
) {
914 nmp
->nm_bufqwant
= FALSE
;
915 wakeup(&nmp
->nm_bufq
);
917 if (ISSET(bp
->b_flags
, B_READ
))
918 (void) nfs_doio(bp
, bp
->b_rcred
, (struct proc
*)0);
920 (void) nfs_doio(bp
, bp
->b_wcred
, (struct proc
*)0);
923 * If there are more than one iod on this mount, then defect
924 * so that the iods can be shared out fairly between the mounts
926 if (nfs_defect
&& nmp
->nm_bufqiods
> 1) {
928 ("nfssvc_iod: iod %d defecting from mount %p\n",
930 nfs_iodmount
[myiod
] = NULL
;
939 * Shut down a socket associated with an nfssvc_sock structure.
940 * Should be called with the send lock set, if required.
941 * The trick here is to increment the sref at the start, so that the nfsds
942 * will stop using it and clear ns_flag at the end so that it will not be
943 * reassigned during cleanup.
947 register struct nfssvc_sock
*slp
;
949 register struct nfsuid
*nuidp
, *nnuidp
;
950 register struct nfsrv_descript
*nwp
, *nnwp
;
956 slp
->ns_flag
&= ~SLP_ALLFLAGS
;
959 slp
->ns_fp
= (struct file
*)0;
961 thread_funnel_switch(KERNEL_FUNNEL
, NETWORK_FUNNEL
);
962 so
->so_upcall
= NULL
;
963 so
->so_rcv
.sb_flags
&= ~SB_UPCALL
;
965 thread_funnel_switch(NETWORK_FUNNEL
, KERNEL_FUNNEL
);
966 closef(fp
, (struct proc
*)0);
968 MFREE(slp
->ns_nam
, m
);
969 m_freem(slp
->ns_raw
);
970 m_freem(slp
->ns_rec
);
971 for (nuidp
= slp
->ns_uidlruhead
.tqh_first
; nuidp
!= 0;
973 nnuidp
= nuidp
->nu_lru
.tqe_next
;
974 LIST_REMOVE(nuidp
, nu_hash
);
975 TAILQ_REMOVE(&slp
->ns_uidlruhead
, nuidp
, nu_lru
);
976 if (nuidp
->nu_flag
& NU_NAM
)
977 m_freem(nuidp
->nu_nam
);
978 _FREE_ZONE((caddr_t
)nuidp
,
979 sizeof (struct nfsuid
), M_NFSUID
);
982 for (nwp
= slp
->ns_tq
.lh_first
; nwp
; nwp
= nnwp
) {
983 nnwp
= nwp
->nd_tq
.le_next
;
984 LIST_REMOVE(nwp
, nd_tq
);
985 _FREE_ZONE((caddr_t
)nwp
, sizeof *nwp
, M_NFSRVDESC
);
987 LIST_INIT(&slp
->ns_tq
);
993 * Get an authorization string for the uid by having the mount_nfs sitting
994 * on this mount point porpous out of the kernel and do it.
997 nfs_getauth(nmp
, rep
, cred
, auth_str
, auth_len
, verf_str
, verf_len
, key
)
998 register struct nfsmount
*nmp
;
1005 NFSKERBKEY_T key
; /* return session key */
1009 while ((nmp
->nm_flag
& NFSMNT_WAITAUTH
) == 0) {
1010 nmp
->nm_flag
|= NFSMNT_WANTAUTH
;
1011 (void) tsleep((caddr_t
)&nmp
->nm_authtype
, PSOCK
,
1012 "nfsauth1", 2 * hz
);
1013 error
= nfs_sigintr(nmp
, rep
, rep
->r_procp
);
1015 nmp
->nm_flag
&= ~NFSMNT_WANTAUTH
;
1019 nmp
->nm_flag
&= ~(NFSMNT_WAITAUTH
| NFSMNT_WANTAUTH
);
1020 MALLOC(*auth_str
, char *, RPCAUTH_MAXSIZ
, M_TEMP
, M_WAITOK
);
1021 nmp
->nm_authstr
= *auth_str
;
1022 nmp
->nm_authlen
= RPCAUTH_MAXSIZ
;
1023 nmp
->nm_verfstr
= verf_str
;
1024 nmp
->nm_verflen
= *verf_len
;
1025 nmp
->nm_authuid
= cred
->cr_uid
;
1026 wakeup((caddr_t
)&nmp
->nm_authstr
);
1029 * And wait for mount_nfs to do its stuff.
1031 while ((nmp
->nm_flag
& NFSMNT_HASAUTH
) == 0 && error
== 0) {
1032 (void) tsleep((caddr_t
)&nmp
->nm_authlen
, PSOCK
,
1033 "nfsauth2", 2 * hz
);
1034 error
= nfs_sigintr(nmp
, rep
, rep
->r_procp
);
1036 if (nmp
->nm_flag
& NFSMNT_AUTHERR
) {
1037 nmp
->nm_flag
&= ~NFSMNT_AUTHERR
;
1041 _FREE((caddr_t
)*auth_str
, M_TEMP
);
1043 *auth_len
= nmp
->nm_authlen
;
1044 *verf_len
= nmp
->nm_verflen
;
1045 bcopy((caddr_t
)nmp
->nm_key
, (caddr_t
)key
, sizeof (key
));
1047 nmp
->nm_flag
&= ~NFSMNT_HASAUTH
;
1048 nmp
->nm_flag
|= NFSMNT_WAITAUTH
;
1049 if (nmp
->nm_flag
& NFSMNT_WANTAUTH
) {
1050 nmp
->nm_flag
&= ~NFSMNT_WANTAUTH
;
1051 wakeup((caddr_t
)&nmp
->nm_authtype
);
1057 * Get a nickname authenticator and verifier.
1060 nfs_getnickauth(nmp
, cred
, auth_str
, auth_len
, verf_str
, verf_len
)
1061 struct nfsmount
*nmp
;
1068 register struct nfsuid
*nuidp
;
1069 register u_long
*nickp
, *verfp
;
1070 struct timeval ktvin
, ktvout
;
1073 if (verf_len
< (4 * NFSX_UNSIGNED
))
1074 panic("nfs_getnickauth verf too small");
1076 for (nuidp
= NMUIDHASH(nmp
, cred
->cr_uid
)->lh_first
;
1077 nuidp
!= 0; nuidp
= nuidp
->nu_hash
.le_next
) {
1078 if (nuidp
->nu_cr
.cr_uid
== cred
->cr_uid
)
1081 if (!nuidp
|| nuidp
->nu_expire
< time
.tv_sec
)
1085 * Move to the end of the lru list (end of lru == most recently used).
1087 TAILQ_REMOVE(&nmp
->nm_uidlruhead
, nuidp
, nu_lru
);
1088 TAILQ_INSERT_TAIL(&nmp
->nm_uidlruhead
, nuidp
, nu_lru
);
1090 MALLOC(nickp
, u_long
*, 2 * NFSX_UNSIGNED
, M_TEMP
, M_WAITOK
);
1091 *nickp
++ = txdr_unsigned(RPCAKN_NICKNAME
);
1092 *nickp
= txdr_unsigned(nuidp
->nu_nickname
);
1093 *auth_str
= (char *)nickp
;
1094 *auth_len
= 2 * NFSX_UNSIGNED
;
1097 * Now we must encrypt the verifier and package it up.
1099 verfp
= (u_long
*)verf_str
;
1100 *verfp
++ = txdr_unsigned(RPCAKN_NICKNAME
);
1101 if (time
.tv_sec
> nuidp
->nu_timestamp
.tv_sec
||
1102 (time
.tv_sec
== nuidp
->nu_timestamp
.tv_sec
&&
1103 time
.tv_usec
> nuidp
->nu_timestamp
.tv_usec
))
1104 nuidp
->nu_timestamp
= time
;
1106 nuidp
->nu_timestamp
.tv_usec
++;
1107 ktvin
.tv_sec
= txdr_unsigned(nuidp
->nu_timestamp
.tv_sec
);
1108 ktvin
.tv_usec
= txdr_unsigned(nuidp
->nu_timestamp
.tv_usec
);
1111 * Now encrypt the timestamp verifier in ecb mode using the session
1118 *verfp
++ = ktvout
.tv_sec
;
1119 *verfp
++ = ktvout
.tv_usec
;
1125 * Save the current nickname in a hash list entry on the mount point.
1128 nfs_savenickauth(nmp
, cred
, len
, key
, mdp
, dposp
, mrep
)
1129 register struct nfsmount
*nmp
;
1137 register struct nfsuid
*nuidp
;
1138 register u_long
*tl
;
1140 struct mbuf
*md
= *mdp
;
1141 struct timeval ktvin
, ktvout
;
1143 char *dpos
= *dposp
, *cp2
;
1144 int deltasec
, error
= 0;
1146 if (len
== (3 * NFSX_UNSIGNED
)) {
1147 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
1148 ktvin
.tv_sec
= *tl
++;
1149 ktvin
.tv_usec
= *tl
++;
1150 nick
= fxdr_unsigned(u_long
, *tl
);
1153 * Decrypt the timestamp in ecb mode.
1158 ktvout
.tv_sec
= fxdr_unsigned(long, ktvout
.tv_sec
);
1159 ktvout
.tv_usec
= fxdr_unsigned(long, ktvout
.tv_usec
);
1160 deltasec
= time
.tv_sec
- ktvout
.tv_sec
;
1162 deltasec
= -deltasec
;
1164 * If ok, add it to the hash list for the mount point.
1166 if (deltasec
<= NFS_KERBCLOCKSKEW
) {
1167 if (nmp
->nm_numuids
< nuidhash_max
) {
1169 MALLOC_ZONE(nuidp
, struct nfsuid
*,
1170 sizeof (struct nfsuid
),
1171 M_NFSUID
, M_WAITOK
);
1173 nuidp
= nmp
->nm_uidlruhead
.tqh_first
;
1174 LIST_REMOVE(nuidp
, nu_hash
);
1175 TAILQ_REMOVE(&nmp
->nm_uidlruhead
, nuidp
,
1179 nuidp
->nu_cr
.cr_uid
= cred
->cr_uid
;
1180 nuidp
->nu_expire
= time
.tv_sec
+ NFS_KERBTTL
;
1181 nuidp
->nu_timestamp
= ktvout
;
1182 nuidp
->nu_nickname
= nick
;
1183 bcopy(key
, nuidp
->nu_key
, sizeof (key
));
1184 TAILQ_INSERT_TAIL(&nmp
->nm_uidlruhead
, nuidp
,
1186 LIST_INSERT_HEAD(NMUIDHASH(nmp
, cred
->cr_uid
),
1190 nfsm_adv(nfsm_rndup(len
));
1197 #ifndef NFS_NOSERVER
1200 * Derefence a server socket structure. If it has no more references and
1201 * is no longer valid, you can throw it away.
1205 register struct nfssvc_sock
*slp
;
1207 if (--(slp
->ns_sref
) == 0 && (slp
->ns_flag
& SLP_VALID
) == 0) {
1208 TAILQ_REMOVE(&nfssvc_sockhead
, slp
, ns_chain
);
1209 _FREE((caddr_t
)slp
, M_NFSSVC
);
1214 * Initialize the data structures for the server.
1215 * Handshake with any new nfsds starting up to avoid any chance of
1219 nfsrv_init(terminating
)
1222 register struct nfssvc_sock
*slp
, *nslp
;
1224 if (nfssvc_sockhead_flag
& SLP_INIT
)
1226 nfssvc_sockhead_flag
|= SLP_INIT
;
1228 for (slp
= nfssvc_sockhead
.tqh_first
; slp
!= 0; slp
= nslp
) {
1229 nslp
= slp
->ns_chain
.tqe_next
;
1230 if (slp
->ns_flag
& SLP_VALID
)
1232 TAILQ_REMOVE(&nfssvc_sockhead
, slp
, ns_chain
);
1233 _FREE((caddr_t
)slp
, M_NFSSVC
);
1235 nfsrv_cleancache(); /* And clear out server cache */
1236 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1239 nfs_pub
.np_valid
= 0;
1244 TAILQ_INIT(&nfssvc_sockhead
);
1245 nfssvc_sockhead_flag
&= ~SLP_INIT
;
1246 if (nfssvc_sockhead_flag
& SLP_WANTINIT
) {
1247 nfssvc_sockhead_flag
&= ~SLP_WANTINIT
;
1248 wakeup((caddr_t
)&nfssvc_sockhead
);
1251 TAILQ_INIT(&nfsd_head
);
1252 nfsd_head_flag
&= ~NFSD_CHECKSLP
;
1254 MALLOC(nfs_udpsock
, struct nfssvc_sock
*, sizeof(struct nfssvc_sock
),
1255 M_NFSSVC
, M_WAITOK
);
1256 bzero((caddr_t
)nfs_udpsock
, sizeof (struct nfssvc_sock
));
1257 TAILQ_INIT(&nfs_udpsock
->ns_uidlruhead
);
1258 TAILQ_INSERT_HEAD(&nfssvc_sockhead
, nfs_udpsock
, ns_chain
);
1260 MALLOC(nfs_cltpsock
, struct nfssvc_sock
*, sizeof(struct nfssvc_sock
),
1261 M_NFSSVC
, M_WAITOK
);
1262 bzero((caddr_t
)nfs_cltpsock
, sizeof (struct nfssvc_sock
));
1263 TAILQ_INIT(&nfs_cltpsock
->ns_uidlruhead
);
1264 TAILQ_INSERT_TAIL(&nfssvc_sockhead
, nfs_cltpsock
, ns_chain
);
1268 * Add entries to the server monitor log.
1271 nfsd_rt(sotype
, nd
, cacherep
)
1273 register struct nfsrv_descript
*nd
;
1276 register struct drt
*rt
;
1278 rt
= &nfsdrt
.drt
[nfsdrt
.pos
];
1279 if (cacherep
== RC_DOIT
)
1281 else if (cacherep
== RC_REPLY
)
1282 rt
->flag
= DRT_CACHEREPLY
;
1284 rt
->flag
= DRT_CACHEDROP
;
1285 if (sotype
== SOCK_STREAM
)
1286 rt
->flag
|= DRT_TCP
;
1287 if (nd
->nd_flag
& ND_NQNFS
)
1288 rt
->flag
|= DRT_NQNFS
;
1289 else if (nd
->nd_flag
& ND_NFSV3
)
1290 rt
->flag
|= DRT_NFSV3
;
1291 rt
->proc
= nd
->nd_procnum
;
1292 if (mtod(nd
->nd_nam
, struct sockaddr
*)->sa_family
== AF_INET
)
1293 rt
->ipadr
= mtod(nd
->nd_nam
, struct sockaddr_in
*)->sin_addr
.s_addr
;
1295 rt
->ipadr
= INADDR_ANY
;
1296 rt
->resptime
= ((time
.tv_sec
- nd
->nd_starttime
.tv_sec
) * 1000000) +
1297 (time
.tv_usec
- nd
->nd_starttime
.tv_usec
);
1299 nfsdrt
.pos
= (nfsdrt
.pos
+ 1) % NFSRTTLOGSIZ
;
1301 #endif /* NFS_NOSERVER */