2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1989, 1993
31 * The Regents of the University of California. All rights reserved.
33 * This code is derived from software contributed to Berkeley by
34 * Rick Macklem at The University of Guelph.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95
65 * FreeBSD-Id: nfs_syscalls.c,v 1.32 1997/11/07 08:53:25 phk Exp $
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 /* XXX CSM 11/25/97 FreeBSD's generated syscall prototypes */
72 #include <sys/sysproto.h>
74 #include <sys/kernel.h>
75 #include <sys/file_internal.h>
76 #include <sys/filedesc.h>
78 #include <sys/vnode_internal.h>
79 #include <sys/mount_internal.h>
80 #include <sys/proc_internal.h> /* for fdflags */
81 #include <sys/kauth.h>
82 #include <sys/sysctl.h>
85 #include <sys/malloc.h>
86 #include <sys/kpi_mbuf.h>
87 #include <sys/socket.h>
88 #include <sys/socketvar.h>
89 #include <sys/domain.h>
90 #include <sys/protosw.h>
91 #include <sys/fcntl.h>
92 #include <sys/lockf.h>
93 #include <sys/syslog.h>
95 #include <sys/sysproto.h>
96 #include <sys/kpi_socket.h>
97 #include <libkern/OSAtomic.h>
99 #include <bsm/audit_kernel.h>
101 #include <netinet/in.h>
102 #include <netinet/tcp.h>
104 #include <netiso/iso.h>
106 #include <nfs/xdr_subs.h>
107 #include <nfs/rpcv2.h>
108 #include <nfs/nfsproto.h>
110 #include <nfs/nfsm_subs.h>
111 #include <nfs/nfsrvcache.h>
112 #include <nfs/nfsmount.h>
113 #include <nfs/nfsnode.h>
114 #include <nfs/nfsrtt.h>
115 #include <nfs/nfs_lock.h>
117 extern void unix_syscall_return(int);
120 extern int (*nfsrv3_procs
[NFS_NPROCS
])(struct nfsrv_descript
*nd
,
121 struct nfssvc_sock
*slp
,
124 extern int nfs_numasync
;
125 extern int nfs_ioddelwri
;
127 extern struct nfsstats nfsstats
;
128 extern int nfsrvw_procrastinate
;
129 extern int nfsrvw_procrastinate_v3
;
131 struct nfssvc_sock
*nfs_udpsock
, *nfs_cltpsock
;
132 static int nuidhash_max
= NFS_MAXUIDHASH
;
134 static void nfsrv_zapsock(struct nfssvc_sock
*slp
);
135 static int nfssvc_iod(proc_t
);
136 static int nfskerb_clientd(struct nfsmount
*, struct nfsd_cargs
*, int, user_addr_t
, proc_t
);
138 static int nfs_asyncdaemon
[NFS_MAXASYNCDAEMON
];
141 int nfsd_waiting
= 0;
142 static struct nfsdrt nfsdrt
;
144 static void nfsd_rt(int sotype
, struct nfsrv_descript
*nd
, int cacherep
);
145 static int nfssvc_addsock(socket_t
, mbuf_t
, proc_t
);
146 static int nfssvc_nfsd(struct nfsd_srvargs
*,user_addr_t
, proc_t
);
147 static int nfssvc_export(user_addr_t
, proc_t
);
149 static int nfs_privport
= 0;
150 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
152 SYSCTL_INT(_vfs_nfs
, NFS_NFSPRIVPORT
, nfs_privport
, CTLFLAG_RW
, &nfs_privport
, 0, "");
153 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, gatherdelay
, CTLFLAG_RW
, &nfsrvw_procrastinate
, 0, "");
154 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, gatherdelay_v3
, CTLFLAG_RW
, &nfsrvw_procrastinate_v3
, 0, "");
158 * NFS server system calls
159 * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
163 * Get file handle system call
166 getfh(proc_t p
, struct getfh_args
*uap
, __unused
int *retval
)
169 struct nfs_filehandle nfh
;
172 struct vfs_context context
;
173 char path
[MAXPATHLEN
], *ptr
;
175 struct nfs_exportfs
*nxfs
;
176 struct nfs_export
*nx
;
179 context
.vc_ucred
= kauth_cred_get();
184 error
= proc_suser(p
);
188 error
= copyinstr(uap
->fname
, path
, MAXPATHLEN
, (size_t *)&pathlen
);
192 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
,
193 UIO_SYSSPACE
, path
, &context
);
201 // find exportfs that matches f_mntonname
202 lck_rw_lock_shared(&nfs_export_rwlock
);
203 ptr
= vnode_mount(vp
)->mnt_vfsstat
.f_mntonname
;
204 LIST_FOREACH(nxfs
, &nfs_exports
, nxfs_next
) {
205 if (!strcmp(nxfs
->nxfs_path
, ptr
))
208 if (!nxfs
|| strncmp(nxfs
->nxfs_path
, path
, strlen(nxfs
->nxfs_path
))) {
212 // find export that best matches remainder of path
213 ptr
= path
+ strlen(nxfs
->nxfs_path
);
214 while (*ptr
&& (*ptr
== '/'))
216 LIST_FOREACH(nx
, &nxfs
->nxfs_exports
, nx_next
) {
217 int len
= strlen(nx
->nx_path
);
218 if (len
== 0) // we've hit the export entry for the root directory
220 if (!strncmp(nx
->nx_path
, ptr
, len
))
228 bzero(&nfh
, sizeof(nfh
));
229 nfh
.nfh_xh
.nxh_version
= htonl(NFS_FH_VERSION
);
230 nfh
.nfh_xh
.nxh_fsid
= htonl(nxfs
->nxfs_id
);
231 nfh
.nfh_xh
.nxh_expid
= htonl(nx
->nx_id
);
232 nfh
.nfh_xh
.nxh_flags
= 0;
233 nfh
.nfh_xh
.nxh_reserved
= 0;
234 nfh
.nfh_len
= NFS_MAX_FID_SIZE
;
235 error
= VFS_VPTOFH(vp
, &nfh
.nfh_len
, &nfh
.nfh_fid
[0], NULL
);
236 if (nfh
.nfh_len
> (int)NFS_MAX_FID_SIZE
)
238 nfh
.nfh_xh
.nxh_fidlen
= nfh
.nfh_len
;
239 nfh
.nfh_len
+= sizeof(nfh
.nfh_xh
);
242 lck_rw_done(&nfs_export_rwlock
);
246 error
= copyout((caddr_t
)&nfh
, uap
->fhp
, sizeof(nfh
));
250 #endif /* NFS_NOSERVER */
252 extern struct fileops vnops
;
255 * syscall for the rpc.lockd to use to translate a NFS file handle into
256 * an open descriptor.
258 * warning: do not remove the suser() call or this becomes one giant
263 struct fhopen_args
*uap
,
267 struct nfs_filehandle nfh
;
268 struct nfs_export
*nx
;
269 struct nfs_export_options
*nxo
;
271 struct fileproc
*fp
, *nfp
;
272 int fmode
, error
, type
;
274 struct vfs_context context
;
275 kauth_action_t action
;
278 context
.vc_ucred
= kauth_cred_proc_ref(p
);
283 error
= suser(context
.vc_ucred
, 0);
285 kauth_cred_unref(&context
.vc_ucred
);
289 fmode
= FFLAGS(uap
->flags
);
290 /* why not allow a non-read/write open for our lockd? */
291 if (((fmode
& (FREAD
| FWRITE
)) == 0) || (fmode
& O_CREAT
)) {
292 kauth_cred_unref(&context
.vc_ucred
);
296 error
= copyin(uap
->u_fhp
, &nfh
.nfh_len
, sizeof(nfh
.nfh_len
));
298 kauth_cred_unref(&context
.vc_ucred
);
301 if ((nfh
.nfh_len
< (int)sizeof(struct nfs_exphandle
)) ||
302 (nfh
.nfh_len
> (int)NFS_MAX_FH_SIZE
)) {
303 kauth_cred_unref(&context
.vc_ucred
);
306 error
= copyin(uap
->u_fhp
, &nfh
, sizeof(nfh
.nfh_len
) + nfh
.nfh_len
);
308 kauth_cred_unref(&context
.vc_ucred
);
312 lck_rw_lock_shared(&nfs_export_rwlock
);
313 /* now give me my vnode, it gets returned to me with a reference */
314 error
= nfsrv_fhtovp(&nfh
, NULL
, TRUE
, &vp
, &nx
, &nxo
);
315 lck_rw_done(&nfs_export_rwlock
);
317 kauth_cred_unref(&context
.vc_ucred
);
322 * From now on we have to make sure not
323 * to forget about the vnode.
324 * Any error that causes an abort must vnode_put(vp).
325 * Just set error = err and 'goto bad;'.
331 if (vnode_vtype(vp
) == VSOCK
) {
336 /* disallow write operations on directories */
337 if (vnode_isdir(vp
) && (fmode
& (FWRITE
| O_TRUNC
))) {
342 /* compute action to be authorized */
345 action
|= KAUTH_VNODE_READ_DATA
;
346 if (fmode
& (FWRITE
| O_TRUNC
))
347 action
|= KAUTH_VNODE_WRITE_DATA
;
348 if ((error
= vnode_authorize(vp
, NULL
, action
, &context
)) != 0)
351 if ((error
= VNOP_OPEN(vp
, fmode
, &context
)))
353 if ((error
= vnode_ref_ext(vp
, fmode
)))
357 * end of vn_open code
360 // starting here... error paths should call vn_close/vnode_put
361 if ((error
= falloc(p
, &nfp
, &indx
)) != 0) {
362 vn_close(vp
, fmode
& FMASK
, context
.vc_ucred
, p
);
367 fp
->f_fglob
->fg_flag
= fmode
& FMASK
;
368 fp
->f_fglob
->fg_type
= DTYPE_VNODE
;
369 fp
->f_fglob
->fg_ops
= &vnops
;
370 fp
->f_fglob
->fg_data
= (caddr_t
)vp
;
372 // XXX do we really need to support this with fhopen()?
373 if (fmode
& (O_EXLOCK
| O_SHLOCK
)) {
374 lf
.l_whence
= SEEK_SET
;
377 if (fmode
& O_EXLOCK
)
382 if ((fmode
& FNONBLOCK
) == 0)
384 if ((error
= VNOP_ADVLOCK(vp
, (caddr_t
)fp
->f_fglob
, F_SETLK
, &lf
, type
, &context
))) {
385 vn_close(vp
, fp
->f_fglob
->fg_flag
, fp
->f_fglob
->fg_cred
, p
);
386 fp_free(p
, indx
, fp
);
387 kauth_cred_unref(&context
.vc_ucred
);
390 fp
->f_fglob
->fg_flag
|= FHASLOCK
;
396 *fdflags(p
, indx
) &= ~UF_RESERVED
;
397 fp_drop(p
, indx
, fp
, 1);
401 kauth_cred_unref(&context
.vc_ucred
);
406 kauth_cred_unref(&context
.vc_ucred
);
411 * Nfs server psuedo system call for the nfsd's
412 * Based on the flag value it either:
413 * - adds a socket to the selection list
414 * - remains in the kernel as an nfsd
415 * - remains in the kernel as an nfsiod
418 nfssvc(proc_t p
, struct nfssvc_args
*uap
, __unused
int *retval
)
423 struct user_nfsd_args user_nfsdarg
;
424 struct nfsd_srvargs nfsd_srvargs
, *nsd
= &nfsd_srvargs
;
425 struct nfsd_cargs ncd
;
427 struct nfssvc_sock
*slp
;
428 struct nfsuid
*nuidp
;
429 struct nfsmount
*nmp
;
432 struct vfs_context context
;
433 struct ucred temp_cred
;
434 #endif /* NFS_NOSERVER */
437 AUDIT_ARG(cmd
, uap
->flag
);
442 error
= proc_suser(p
);
445 if (uap
->flag
& NFSSVC_BIOD
)
446 error
= nfssvc_iod(p
);
450 #else /* !NFS_NOSERVER */
451 else if (uap
->flag
& NFSSVC_MNTD
) {
454 context
.vc_ucred
= kauth_cred_get();
456 error
= copyin(uap
->argp
, (caddr_t
)&ncd
, sizeof (ncd
));
460 NDINIT(&nd
, LOOKUP
, FOLLOW
| LOCKLEAF
| AUDITVNPATH1
,
461 (proc_is64bit(p
) ? UIO_USERSPACE64
: UIO_USERSPACE32
),
462 CAST_USER_ADDR_T(ncd
.ncd_dirp
), &context
);
468 if (vnode_isvroot(nd
.ni_vp
) == 0)
470 nmp
= VFSTONFS(vnode_mount(nd
.ni_vp
));
475 if ((nmp
->nm_state
& NFSSTA_MNTD
) &&
476 (uap
->flag
& NFSSVC_GOTAUTH
) == 0)
478 nmp
->nm_state
|= NFSSTA_MNTD
;
479 error
= nfskerb_clientd(nmp
, &ncd
, uap
->flag
, uap
->argp
, p
);
480 } else if (uap
->flag
& NFSSVC_ADDSOCK
) {
481 if (IS_64BIT_PROCESS(p
)) {
482 error
= copyin(uap
->argp
, (caddr_t
)&user_nfsdarg
, sizeof(user_nfsdarg
));
484 struct nfsd_args tmp_args
;
485 error
= copyin(uap
->argp
, (caddr_t
)&tmp_args
, sizeof(tmp_args
));
487 user_nfsdarg
.sock
= tmp_args
.sock
;
488 user_nfsdarg
.name
= CAST_USER_ADDR_T(tmp_args
.name
);
489 user_nfsdarg
.namelen
= tmp_args
.namelen
;
495 error
= file_socket(user_nfsdarg
.sock
, &so
);
498 /* Get the client address for connected sockets. */
499 if (user_nfsdarg
.name
== USER_ADDR_NULL
|| user_nfsdarg
.namelen
== 0) {
502 error
= sockargs(&nam
, user_nfsdarg
.name
, user_nfsdarg
.namelen
, MBUF_TYPE_SONAME
);
504 /* drop the iocount file_socket() grabbed on the file descriptor */
505 file_drop(user_nfsdarg
.sock
);
510 * nfssvc_addsock() will grab a retain count on the socket
511 * to keep the socket from being closed when nfsd closes its
512 * file descriptor for it.
514 error
= nfssvc_addsock(so
, nam
, p
);
515 /* drop the iocount file_socket() grabbed on the file descriptor */
516 file_drop(user_nfsdarg
.sock
);
517 } else if (uap
->flag
& NFSSVC_NFSD
) {
518 error
= copyin(uap
->argp
, (caddr_t
)nsd
, sizeof (*nsd
));
522 if ((uap
->flag
& NFSSVC_AUTHIN
) && ((nfsd
= nsd
->nsd_nfsd
)) &&
523 (nfsd
->nfsd_slp
->ns_flag
& SLP_VALID
)) {
524 slp
= nfsd
->nfsd_slp
;
527 * First check to see if another nfsd has already
528 * added this credential.
530 for (nuidp
= NUIDHASH(slp
,nsd
->nsd_cr
.cr_uid
)->lh_first
;
531 nuidp
!= 0; nuidp
= nuidp
->nu_hash
.le_next
) {
532 if (kauth_cred_getuid(nuidp
->nu_cr
) == nsd
->nsd_cr
.cr_uid
&&
533 (!nfsd
->nfsd_nd
->nd_nam2
||
534 netaddr_match(NU_NETFAM(nuidp
),
535 &nuidp
->nu_haddr
, nfsd
->nfsd_nd
->nd_nam2
)))
539 nfsrv_setcred(nuidp
->nu_cr
,&temp_cred
);
540 kauth_cred_unref(&nfsd
->nfsd_nd
->nd_cr
);
541 nfsd
->nfsd_nd
->nd_cr
= kauth_cred_create(&temp_cred
);
542 nfsd
->nfsd_nd
->nd_flag
|= ND_KERBFULL
;
547 if (slp
->ns_numuids
< nuidhash_max
) {
549 nuidp
= (struct nfsuid
*)
550 _MALLOC_ZONE(sizeof (struct nfsuid
),
553 nuidp
= (struct nfsuid
*)0;
554 if ((slp
->ns_flag
& SLP_VALID
) == 0) {
556 FREE_ZONE((caddr_t
)nuidp
,
557 sizeof (struct nfsuid
), M_NFSUID
);
561 if (nuidp
== (struct nfsuid
*)0) {
562 nuidp
= slp
->ns_uidlruhead
.tqh_first
;
565 LIST_REMOVE(nuidp
, nu_hash
);
566 TAILQ_REMOVE(&slp
->ns_uidlruhead
, nuidp
,
568 if (nuidp
->nu_flag
& NU_NAM
)
569 mbuf_freem(nuidp
->nu_nam
);
570 kauth_cred_unref(&nuidp
->nu_cr
);
574 if (nsd
->nsd_cr
.cr_ngroups
> NGROUPS
)
575 nsd
->nsd_cr
.cr_ngroups
= NGROUPS
;
577 nfsrv_setcred(&nsd
->nsd_cr
, &temp_cred
);
578 nuidp
->nu_cr
= kauth_cred_create(&temp_cred
);
581 FREE_ZONE(nuidp
, sizeof(struct nfsuid
), M_NFSUID
);
585 nuidp
->nu_timestamp
= nsd
->nsd_timestamp
;
587 nuidp
->nu_expire
= now
.tv_sec
+ nsd
->nsd_ttl
;
589 * and save the session key in nu_key.
591 bcopy(nsd
->nsd_key
, nuidp
->nu_key
,
592 sizeof (nsd
->nsd_key
));
593 if (nfsd
->nfsd_nd
->nd_nam2
) {
594 struct sockaddr_in
*saddr
;
596 saddr
= mbuf_data(nfsd
->nfsd_nd
->nd_nam2
);
597 switch (saddr
->sin_family
) {
599 nuidp
->nu_flag
|= NU_INETADDR
;
601 saddr
->sin_addr
.s_addr
;
605 nuidp
->nu_flag
|= NU_NAM
;
606 error
= mbuf_copym(nfsd
->nfsd_nd
->nd_nam2
, 0,
607 MBUF_COPYALL
, MBUF_WAITOK
,
610 kauth_cred_unref(&nuidp
->nu_cr
);
611 FREE_ZONE(nuidp
, sizeof(struct nfsuid
), M_NFSUID
);
618 TAILQ_INSERT_TAIL(&slp
->ns_uidlruhead
, nuidp
,
620 LIST_INSERT_HEAD(NUIDHASH(slp
, nsd
->nsd_uid
),
622 nfsrv_setcred(nuidp
->nu_cr
,&temp_cred
);
623 kauth_cred_unref(&nfsd
->nfsd_nd
->nd_cr
);
624 nfsd
->nfsd_nd
->nd_cr
= kauth_cred_create(&temp_cred
);
625 nfsd
->nfsd_nd
->nd_flag
|= ND_KERBFULL
;
629 if ((uap
->flag
& NFSSVC_AUTHINFAIL
) && (nfsd
= nsd
->nsd_nfsd
))
630 nfsd
->nfsd_flag
|= NFSD_AUTHFAIL
;
631 error
= nfssvc_nfsd(nsd
, uap
->argp
, p
);
632 } else if (uap
->flag
& NFSSVC_EXPORT
) {
633 error
= nfssvc_export(uap
->argp
, p
);
637 #endif /* NFS_NOSERVER */
638 if (error
== EINTR
|| error
== ERESTART
)
644 * NFSKERB client helper daemon.
645 * Gets authorization strings for "kerb" mounts.
649 struct nfsmount
*nmp
,
650 struct nfsd_cargs
*ncd
,
655 struct nfsuid
*nuidp
, *nnuidp
;
661 * First initialize some variables
666 * If an authorization string is being passed in, get it.
668 if ((flag
& NFSSVC_GOTAUTH
) && (nmp
->nm_state
& NFSSTA_MOUNTED
) &&
669 ((nmp
->nm_state
& NFSSTA_WAITAUTH
) == 0)) {
670 if (nmp
->nm_state
& NFSSTA_HASAUTH
)
672 if ((flag
& NFSSVC_AUTHINFAIL
) == 0) {
673 if (ncd
->ncd_authlen
<= nmp
->nm_authlen
&&
674 ncd
->ncd_verflen
<= nmp
->nm_verflen
&&
675 !copyin(CAST_USER_ADDR_T(ncd
->ncd_authstr
),nmp
->nm_authstr
,ncd
->ncd_authlen
)&&
676 !copyin(CAST_USER_ADDR_T(ncd
->ncd_verfstr
),nmp
->nm_verfstr
,ncd
->ncd_verflen
)){
677 nmp
->nm_authtype
= ncd
->ncd_authtype
;
678 nmp
->nm_authlen
= ncd
->ncd_authlen
;
679 nmp
->nm_verflen
= ncd
->ncd_verflen
;
681 nmp
->nm_key
= ncd
->ncd_key
;
684 nmp
->nm_state
|= NFSSTA_AUTHERR
;
686 nmp
->nm_state
|= NFSSTA_AUTHERR
;
687 nmp
->nm_state
|= NFSSTA_HASAUTH
;
688 wakeup((caddr_t
)&nmp
->nm_authlen
);
690 nmp
->nm_state
|= NFSSTA_WAITAUTH
;
694 * Loop every second updating queue until there is a termination sig.
696 while (nmp
->nm_state
& NFSSTA_MOUNTED
) {
697 /* Get an authorization string, if required. */
698 if ((nmp
->nm_state
& (NFSSTA_WAITAUTH
| NFSSTA_HASAUTH
)) == 0) {
699 ncd
->ncd_authuid
= nmp
->nm_authuid
;
700 if (copyout((caddr_t
)ncd
, argp
, sizeof (struct nfsd_cargs
)))
701 nmp
->nm_state
|= NFSSTA_WAITAUTH
;
705 /* Wait a bit (no pun) and do it again. */
706 if ((nmp
->nm_state
& NFSSTA_MOUNTED
) &&
707 (nmp
->nm_state
& (NFSSTA_WAITAUTH
| NFSSTA_HASAUTH
))) {
708 error
= tsleep((caddr_t
)&nmp
->nm_authstr
, PSOCK
| PCATCH
,
709 "nfskrbtimr", hz
/ 3);
710 if (error
== EINTR
|| error
== ERESTART
)
711 dounmount(nmp
->nm_mountp
, 0, NULL
, p
);
716 * Finally, we can free up the mount structure.
718 for (nuidp
= nmp
->nm_uidlruhead
.tqh_first
; nuidp
!= 0; nuidp
= nnuidp
) {
719 nnuidp
= nuidp
->nu_lru
.tqe_next
;
720 LIST_REMOVE(nuidp
, nu_hash
);
721 TAILQ_REMOVE(&nmp
->nm_uidlruhead
, nuidp
, nu_lru
);
722 kauth_cred_unref(&nuidp
->nu_cr
);
723 FREE_ZONE((caddr_t
)nuidp
, sizeof (struct nfsuid
), M_NFSUID
);
726 * Loop through outstanding request list and remove dangling
727 * references to defunct nfsmount struct
729 for (rp
= nfs_reqq
.tqh_first
; rp
; rp
= rp
->r_chain
.tqe_next
)
730 if (rp
->r_nmp
== nmp
)
731 rp
->r_nmp
= (struct nfsmount
*)0;
732 /* Need to wake up any rcvlock waiters so they notice the unmount. */
733 if (nmp
->nm_state
& NFSSTA_WANTRCV
) {
734 nmp
->nm_state
&= ~NFSSTA_WANTRCV
;
735 wakeup(&nmp
->nm_state
);
737 FREE_ZONE((caddr_t
)nmp
, sizeof (struct nfsmount
), M_NFSMNT
);
738 if (error
== EWOULDBLOCK
)
745 * Adds a socket to the list for servicing by nfsds.
754 struct nfssvc_sock
*slp
;
755 struct nfssvc_sock
*tslp
= NULL
;
756 int error
, sodomain
, sotype
, soprotocol
, on
= 1;
757 struct timeval timeo
;
759 /* make sure mbuf constants are set up */
763 sock_gettype(so
, &sodomain
, &sotype
, &soprotocol
);
766 * Add it to the list, as required.
768 if (soprotocol
== IPPROTO_UDP
) {
770 if (!tslp
|| (tslp
->ns_flag
& SLP_VALID
)) {
775 } else if (soprotocol
== ISOPROTO_CLTP
) {
777 if (!tslp
|| (tslp
->ns_flag
& SLP_VALID
)) {
783 /* reserve buffer space for 2 maximally-sized packets */
785 if (sotype
== SOCK_STREAM
)
786 siz
+= sizeof (u_long
);
788 if (siz
> NFS_MAXSOCKBUF
)
789 siz
= NFS_MAXSOCKBUF
;
790 if ((error
= sock_setsockopt(so
, SOL_SOCKET
, SO_SNDBUF
, &siz
, sizeof(siz
))) ||
791 (error
= sock_setsockopt(so
, SOL_SOCKET
, SO_RCVBUF
, &siz
, sizeof(siz
)))) {
797 * Set protocol specific options { for now TCP only } and
798 * reserve some space. For datagram sockets, this can get called
799 * repeatedly for the same socket, but that isn't harmful.
801 if (sotype
== SOCK_STREAM
) {
802 sock_setsockopt(so
, SOL_SOCKET
, SO_KEEPALIVE
, &on
, sizeof(on
));
804 if (sodomain
== AF_INET
&& soprotocol
== IPPROTO_TCP
) {
805 sock_setsockopt(so
, IPPROTO_TCP
, TCP_NODELAY
, &on
, sizeof(on
));
808 sock_nointerrupt(so
, 0);
812 error
= sock_setsockopt(so
, SOL_SOCKET
, SO_RCVTIMEO
, &timeo
, sizeof(timeo
));
813 error
= sock_setsockopt(so
, SOL_SOCKET
, SO_SNDTIMEO
, &timeo
, sizeof(timeo
));
817 lck_mtx_lock(nfsd_mutex
);
819 MALLOC(slp
, struct nfssvc_sock
*, sizeof(struct nfssvc_sock
),
825 bzero((caddr_t
)slp
, sizeof (struct nfssvc_sock
));
826 lck_rw_init(&slp
->ns_rwlock
, nfs_slp_rwlock_group
, nfs_slp_lock_attr
);
827 lck_mtx_init(&slp
->ns_wgmutex
, nfs_slp_mutex_group
, nfs_slp_lock_attr
);
828 TAILQ_INIT(&slp
->ns_uidlruhead
);
829 lck_mtx_lock(nfsd_mutex
);
830 TAILQ_INSERT_TAIL(&nfssvc_sockhead
, slp
, ns_chain
);
833 sock_retain(so
); /* grab a retain count on the socket */
835 slp
->ns_sotype
= sotype
;
839 so
->so_upcallarg
= (caddr_t
)slp
;
840 so
->so_upcall
= nfsrv_rcv
;
841 so
->so_rcv
.sb_flags
|= SB_UPCALL
; /* required for freebsd merge */
842 socket_unlock(so
, 1);
844 slp
->ns_flag
= SLP_VALID
| SLP_NEEDQ
;
847 lck_mtx_unlock(nfsd_mutex
);
853 * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
854 * until it is killed by a signal.
857 nfssvc_nfsd(nsd
, argp
, p
)
858 struct nfsd_srvargs
*nsd
;
863 struct nfssvc_sock
*slp
;
864 struct nfsd
*nfsd
= nsd
->nsd_nfsd
;
865 struct nfsrv_descript
*nd
= NULL
;
866 int error
= 0, cacherep
, writes_todo
;
867 int siz
, procrastinate
;
870 boolean_t funnel_state
;
876 if (nfsd
== (struct nfsd
*)0) {
877 MALLOC(nfsd
, struct nfsd
*, sizeof(struct nfsd
), M_NFSD
, M_WAITOK
);
880 nsd
->nsd_nfsd
= nfsd
;
881 bzero((caddr_t
)nfsd
, sizeof (struct nfsd
));
882 nfsd
->nfsd_procp
= p
;
883 lck_mtx_lock(nfsd_mutex
);
884 TAILQ_INSERT_TAIL(&nfsd_head
, nfsd
, nfsd_chain
);
886 lck_mtx_unlock(nfsd_mutex
);
889 funnel_state
= thread_funnel_set(kernel_flock
, FALSE
);
892 * Loop getting rpc requests until SIGKILL.
895 if ((nfsd
->nfsd_flag
& NFSD_REQINPROG
) == 0) {
896 lck_mtx_lock(nfsd_mutex
);
897 while ((nfsd
->nfsd_slp
== NULL
) && !(nfsd_head_flag
& NFSD_CHECKSLP
)) {
898 nfsd
->nfsd_flag
|= NFSD_WAITING
;
900 error
= msleep(nfsd
, nfsd_mutex
, PSOCK
| PCATCH
, "nfsd", 0);
903 lck_mtx_unlock(nfsd_mutex
);
907 if ((nfsd
->nfsd_slp
== NULL
) && (nfsd_head_flag
& NFSD_CHECKSLP
)) {
908 TAILQ_FOREACH(slp
, &nfssvc_sockhead
, ns_chain
) {
909 lck_rw_lock_shared(&slp
->ns_rwlock
);
910 if ((slp
->ns_flag
& (SLP_VALID
| SLP_DOREC
))
911 == (SLP_VALID
| SLP_DOREC
)) {
912 if (lck_rw_lock_shared_to_exclusive(&slp
->ns_rwlock
)) {
913 /* upgrade failed and we lost the lock; take exclusive and recheck */
914 lck_rw_lock_exclusive(&slp
->ns_rwlock
);
915 if ((slp
->ns_flag
& (SLP_VALID
| SLP_DOREC
))
916 != (SLP_VALID
| SLP_DOREC
)) {
917 /* flags no longer set, so skip this socket */
918 lck_rw_done(&slp
->ns_rwlock
);
922 slp
->ns_flag
&= ~SLP_DOREC
;
924 nfsd
->nfsd_slp
= slp
;
925 lck_rw_done(&slp
->ns_rwlock
);
928 lck_rw_done(&slp
->ns_rwlock
);
931 nfsd_head_flag
&= ~NFSD_CHECKSLP
;
933 lck_mtx_unlock(nfsd_mutex
);
934 if ((slp
= nfsd
->nfsd_slp
) == NULL
)
936 lck_rw_lock_exclusive(&slp
->ns_rwlock
);
937 if (slp
->ns_flag
& SLP_VALID
) {
938 if ((slp
->ns_flag
& (SLP_NEEDQ
|SLP_DISCONN
)) == SLP_NEEDQ
) {
939 slp
->ns_flag
&= ~SLP_NEEDQ
;
940 nfsrv_rcv_locked(slp
->ns_so
, slp
, MBUF_WAITOK
);
942 if (slp
->ns_flag
& SLP_DISCONN
)
944 error
= nfsrv_dorec(slp
, nfsd
, &nd
);
946 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 +
947 (u_quad_t
)now
.tv_usec
;
948 if (error
&& slp
->ns_wgtime
&& (slp
->ns_wgtime
<= cur_usec
)) {
954 nfsd
->nfsd_flag
|= NFSD_REQINPROG
;
956 lck_rw_done(&slp
->ns_rwlock
);
959 slp
= nfsd
->nfsd_slp
;
961 if (error
|| (slp
->ns_flag
& SLP_VALID
) == 0) {
964 mbuf_freem(nd
->nd_nam2
);
965 if (IS_VALID_CRED(nd
->nd_cr
))
966 kauth_cred_unref(&nd
->nd_cr
);
967 FREE_ZONE((caddr_t
)nd
,
968 sizeof *nd
, M_NFSRVDESC
);
971 nfsd
->nfsd_slp
= NULL
;
972 nfsd
->nfsd_flag
&= ~NFSD_REQINPROG
;
977 microuptime(&nd
->nd_starttime
);
979 nd
->nd_nam
= nd
->nd_nam2
;
981 nd
->nd_nam
= slp
->ns_nam
;
984 * Check to see if authorization is needed.
986 if (nfsd
->nfsd_flag
& NFSD_NEEDAUTH
) {
987 nfsd
->nfsd_flag
&= ~NFSD_NEEDAUTH
;
988 nsd
->nsd_haddr
= ((struct sockaddr_in
*)mbuf_data(nd
->nd_nam
))->sin_addr
.s_addr
;
989 nsd
->nsd_authlen
= nfsd
->nfsd_authlen
;
990 nsd
->nsd_verflen
= nfsd
->nfsd_verflen
;
991 if (!copyout(nfsd
->nfsd_authstr
,CAST_USER_ADDR_T(nsd
->nsd_authstr
),
992 nfsd
->nfsd_authlen
) &&
993 !copyout(nfsd
->nfsd_verfstr
, CAST_USER_ADDR_T(nsd
->nsd_verfstr
),
994 nfsd
->nfsd_verflen
) &&
995 !copyout((caddr_t
)nsd
, argp
, sizeof (*nsd
))) {
996 thread_funnel_set(kernel_flock
, funnel_state
);
999 cacherep
= RC_DROPIT
;
1001 cacherep
= nfsrv_getcache(nd
, slp
, &mreq
);
1003 if (nfsd
->nfsd_flag
& NFSD_AUTHFAIL
) {
1004 nfsd
->nfsd_flag
&= ~NFSD_AUTHFAIL
;
1005 nd
->nd_procnum
= NFSPROC_NOOP
;
1006 nd
->nd_repstat
= (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
1008 } else if (nfs_privport
) {
1009 /* Check if source port is privileged */
1011 struct sockaddr
*nam
= mbuf_data(nd
->nd_nam
);
1012 struct sockaddr_in
*sin
;
1014 sin
= (struct sockaddr_in
*)nam
;
1015 port
= ntohs(sin
->sin_port
);
1016 if (port
>= IPPORT_RESERVED
&&
1017 nd
->nd_procnum
!= NFSPROC_NULL
) {
1018 char strbuf
[MAX_IPv4_STR_LEN
];
1019 nd
->nd_procnum
= NFSPROC_NOOP
;
1020 nd
->nd_repstat
= (NFSERR_AUTHERR
| AUTH_TOOWEAK
);
1022 printf("NFS request from unprivileged port (%s:%d)\n",
1023 inet_ntop(AF_INET
, &sin
->sin_addr
, strbuf
, sizeof(strbuf
)),
1031 * Loop to get all the write rpc relies that have been
1032 * gathered together.
1037 if (nd
&& (nd
->nd_flag
& ND_NFSV3
))
1038 procrastinate
= nfsrvw_procrastinate_v3
;
1040 procrastinate
= nfsrvw_procrastinate
;
1041 lck_rw_lock_shared(&nfs_export_rwlock
);
1042 if (writes_todo
|| ((nd
->nd_procnum
== NFSPROC_WRITE
) && (procrastinate
> 0)))
1043 error
= nfsrv_writegather(&nd
, slp
, nfsd
->nfsd_procp
, &mreq
);
1045 error
= (*(nfsrv3_procs
[nd
->nd_procnum
]))(nd
, slp
, nfsd
->nfsd_procp
, &mreq
);
1046 lck_rw_done(&nfs_export_rwlock
);
1050 OSAddAtomic(1, (SInt32
*)&nfsstats
.srv_errs
);
1051 nfsrv_updatecache(nd
, FALSE
, mreq
);
1053 mbuf_freem(nd
->nd_nam2
);
1058 OSAddAtomic(1, (SInt32
*)&nfsstats
.srvrpccnt
[nd
->nd_procnum
]);
1059 nfsrv_updatecache(nd
, TRUE
, mreq
);
1068 if (siz
<= 0 || siz
> NFS_MAXPACKET
) {
1069 printf("mbuf siz=%d\n",siz
);
1070 panic("Bad nfs svc reply");
1073 mbuf_pkthdr_setlen(m
, siz
);
1074 error
= mbuf_pkthdr_setrcvif(m
, NULL
);
1076 panic("nfsd setrcvif failed: %d", error
);
1078 * For stream protocols, prepend a Sun RPC
1081 if (slp
->ns_sotype
== SOCK_STREAM
) {
1082 error
= mbuf_prepend(&m
, NFSX_UNSIGNED
, MBUF_WAITOK
);
1084 *(u_long
*)mbuf_data(m
) = htonl(0x80000000 | siz
);
1087 if (slp
->ns_flag
& SLP_VALID
) {
1088 error
= nfs_send(slp
->ns_so
, nd
->nd_nam2
, m
, NULL
);
1098 nfsd_rt(slp
->ns_sotype
, nd
, cacherep
);
1100 mbuf_freem(nd
->nd_nam2
);
1104 mbuf_freem(nd
->nd_mrep
);
1107 if (error
== EPIPE
) {
1108 lck_rw_lock_exclusive(&slp
->ns_rwlock
);
1110 lck_rw_done(&slp
->ns_rwlock
);
1112 if (error
== EINTR
|| error
== ERESTART
) {
1113 if (IS_VALID_CRED(nd
->nd_cr
))
1114 kauth_cred_unref(&nd
->nd_cr
);
1115 FREE_ZONE((caddr_t
)nd
, sizeof *nd
, M_NFSRVDESC
);
1116 nfsrv_slpderef(slp
);
1122 nfsd_rt(slp
->ns_sotype
, nd
, cacherep
);
1123 mbuf_freem(nd
->nd_mrep
);
1124 mbuf_freem(nd
->nd_nam2
);
1125 nd
->nd_mrep
= nd
->nd_nam2
= NULL
;
1130 mbuf_freem(nd
->nd_mrep
);
1132 mbuf_freem(nd
->nd_nam2
);
1133 if (IS_VALID_CRED(nd
->nd_cr
))
1134 kauth_cred_unref(&nd
->nd_cr
);
1135 FREE_ZONE((caddr_t
)nd
, sizeof *nd
, M_NFSRVDESC
);
1140 * Check to see if there are outstanding writes that
1141 * need to be serviced.
1144 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 +
1145 (u_quad_t
)now
.tv_usec
;
1146 if (slp
->ns_wgtime
&& (slp
->ns_wgtime
<= cur_usec
)) {
1152 } while (writes_todo
);
1153 lck_rw_lock_exclusive(&slp
->ns_rwlock
);
1154 if (nfsrv_dorec(slp
, nfsd
, &nd
)) {
1155 lck_rw_done(&slp
->ns_rwlock
);
1156 nfsd
->nfsd_flag
&= ~NFSD_REQINPROG
;
1157 nfsd
->nfsd_slp
= NULL
;
1158 nfsrv_slpderef(slp
);
1160 lck_rw_done(&slp
->ns_rwlock
);
1164 thread_funnel_set(kernel_flock
, funnel_state
);
1165 lck_mtx_lock(nfsd_mutex
);
1166 TAILQ_REMOVE(&nfsd_head
, nfsd
, nfsd_chain
);
1168 nsd
->nsd_nfsd
= (struct nfsd
*)0;
1169 if (--nfs_numnfsd
== 0)
1170 nfsrv_init(TRUE
); /* Reinitialize everything */
1171 lck_mtx_unlock(nfsd_mutex
);
1176 nfssvc_export(user_addr_t argp
, proc_t p
)
1178 int error
= 0, is_64bit
;
1179 struct user_nfs_export_args unxa
;
1180 struct vfs_context context
;
1182 context
.vc_proc
= p
;
1183 context
.vc_ucred
= kauth_cred_get();
1184 is_64bit
= IS_64BIT_PROCESS(p
);
1186 /* copy in pointers to path and export args */
1188 error
= copyin(argp
, (caddr_t
)&unxa
, sizeof(unxa
));
1190 struct nfs_export_args tnxa
;
1191 error
= copyin(argp
, (caddr_t
)&tnxa
, sizeof(tnxa
));
1193 /* munge into LP64 version of nfs_export_args structure */
1194 unxa
.nxa_fsid
= tnxa
.nxa_fsid
;
1195 unxa
.nxa_expid
= tnxa
.nxa_expid
;
1196 unxa
.nxa_fspath
= CAST_USER_ADDR_T(tnxa
.nxa_fspath
);
1197 unxa
.nxa_exppath
= CAST_USER_ADDR_T(tnxa
.nxa_exppath
);
1198 unxa
.nxa_flags
= tnxa
.nxa_flags
;
1199 unxa
.nxa_netcount
= tnxa
.nxa_netcount
;
1200 unxa
.nxa_nets
= CAST_USER_ADDR_T(tnxa
.nxa_nets
);
1206 error
= nfsrv_export(&unxa
, &context
);
1211 #endif /* NFS_NOSERVER */
1214 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
1216 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, defect
, CTLFLAG_RW
, &nfs_defect
, 0, "");
1220 nfsclnt(proc_t p
, struct nfsclnt_args
*uap
, __unused
int *retval
)
1222 struct lockd_ans la
;
1225 if (uap
->flag
== NFSCLNT_LOCKDWAIT
) {
1226 return (nfslockdwait(p
));
1228 if (uap
->flag
== NFSCLNT_LOCKDANS
) {
1229 error
= copyin(uap
->argp
, &la
, sizeof(la
));
1230 return (error
!= 0 ? error
: nfslockdans(p
, &la
));
1232 if (uap
->flag
== NFSCLNT_LOCKDFD
)
1233 return (nfslockdfd(p
, CAST_DOWN(int, uap
->argp
)));
1238 static int nfssvc_iod_continue(int);
1241 * Asynchronous I/O daemons for client nfs.
1242 * They do read-ahead and write-behind operations on the block I/O cache.
1243 * Never returns unless it fails or gets killed.
1246 nfssvc_iod(__unused proc_t p
)
1248 register int i
, myiod
;
1252 * Assign my position or return error if too many already running
1255 for (i
= 0; i
< NFS_MAXASYNCDAEMON
; i
++)
1256 if (nfs_asyncdaemon
[i
] == 0) {
1257 nfs_asyncdaemon
[i
]++;
1265 /* stuff myiod into uthread to get off local stack for continuation */
1267 ut
= (struct uthread
*)get_bsdthread_info(current_thread());
1268 ut
->uu_state
.uu_nfs_myiod
= myiod
; /* squirrel away for continuation */
1270 nfssvc_iod_continue(0);
1276 * Continuation for Asynchronous I/O daemons for client nfs.
1279 nfssvc_iod_continue(int error
)
1281 register struct nfsbuf
*bp
;
1282 register int i
, myiod
;
1283 struct nfsmount
*nmp
;
1289 * real myiod is stored in uthread, recover it
1291 ut
= (struct uthread
*)get_bsdthread_info(current_thread());
1292 myiod
= ut
->uu_state
.uu_nfs_myiod
;
1293 p
= current_proc(); // XXX
1296 * Just loop around doin our stuff until SIGKILL
1297 * - actually we don't loop with continuations...
1299 lck_mtx_lock(nfs_iod_mutex
);
1301 while (((nmp
= nfs_iodmount
[myiod
]) == NULL
1302 || nmp
->nm_bufq
.tqh_first
== NULL
)
1303 && error
== 0 && nfs_ioddelwri
== 0) {
1306 nfs_iodwant
[myiod
] = p
; // XXX this doesn't need to be a proc_t
1307 nfs_iodmount
[myiod
] = NULL
;
1308 error
= msleep0((caddr_t
)&nfs_iodwant
[myiod
], nfs_iod_mutex
,
1309 PWAIT
| PCATCH
| PDROP
, "nfsidl", 0, nfssvc_iod_continue
);
1310 lck_mtx_lock(nfs_iod_mutex
);
1312 if (error
&& !exiterror
&& nmp
&& (nmp
->nm_bufqiods
== 1) &&
1313 !TAILQ_EMPTY(&nmp
->nm_bufq
)) {
1315 * Finish processing the queued buffers before exitting.
1316 * Decrement the iod count now to make sure nfs_asyncio()
1317 * doesn't keep queueing up more work.
1324 nfs_asyncdaemon
[myiod
] = 0;
1325 if (nmp
&& !exiterror
)
1327 nfs_iodwant
[myiod
] = NULL
;
1328 nfs_iodmount
[myiod
] = NULL
;
1329 lck_mtx_unlock(nfs_iod_mutex
);
1331 if (error
== EINTR
|| error
== ERESTART
)
1333 unix_syscall_return(error
);
1336 while ((bp
= TAILQ_FIRST(&nmp
->nm_bufq
)) != NULL
) {
1337 /* Take one off the front of the list */
1338 TAILQ_REMOVE(&nmp
->nm_bufq
, bp
, nb_free
);
1339 bp
->nb_free
.tqe_next
= NFSNOLIST
;
1341 if (nmp
->nm_bufqwant
&& nmp
->nm_bufqlen
< 2 * nfs_numasync
) {
1342 nmp
->nm_bufqwant
= FALSE
;
1343 lck_mtx_unlock(nfs_iod_mutex
);
1344 wakeup(&nmp
->nm_bufq
);
1346 lck_mtx_unlock(nfs_iod_mutex
);
1349 SET(bp
->nb_flags
, NB_IOD
);
1350 if (ISSET(bp
->nb_flags
, NB_READ
))
1351 nfs_doio(bp
, bp
->nb_rcred
, NULL
);
1353 nfs_doio(bp
, bp
->nb_wcred
, NULL
);
1355 lck_mtx_lock(nfs_iod_mutex
);
1357 * If there are more than one iod on this mount, then defect
1358 * so that the iods can be shared out fairly between the mounts
1360 if (!exiterror
&& nfs_defect
&& nmp
->nm_bufqiods
> 1) {
1361 nfs_iodmount
[myiod
] = NULL
;
1367 lck_mtx_unlock(nfs_iod_mutex
);
1369 if (nfs_ioddelwri
) {
1372 lck_mtx_lock(nfs_buf_mutex
);
1373 while (i
< 8 && (bp
= TAILQ_FIRST(&nfsbufdelwri
)) != NULL
) {
1374 struct nfsnode
*np
= VTONFS(bp
->nb_vp
);
1375 nfs_buf_remfree(bp
);
1377 while ((error
= nfs_buf_acquire(bp
, 0, 0, 0)) == EAGAIN
);
1378 nfs_buf_refrele(bp
);
1382 /* buffer is no longer valid */
1386 if (ISSET(bp
->nb_flags
, NB_NEEDCOMMIT
))
1387 nfs_buf_check_write_verifier(np
, bp
);
1388 if (ISSET(bp
->nb_flags
, NB_NEEDCOMMIT
)) {
1389 /* put buffer at end of delwri list */
1390 TAILQ_INSERT_TAIL(&nfsbufdelwri
, bp
, nb_free
);
1393 lck_mtx_unlock(nfs_buf_mutex
);
1394 nfs_flushcommits(np
->n_vnode
, NULL
, 1);
1396 SET(bp
->nb_flags
, (NB_ASYNC
| NB_IOD
));
1397 lck_mtx_unlock(nfs_buf_mutex
);
1401 lck_mtx_lock(nfs_buf_mutex
);
1403 lck_mtx_unlock(nfs_buf_mutex
);
1406 lck_mtx_lock(nfs_iod_mutex
);
1413 * Shut down a socket associated with an nfssvc_sock structure.
1414 * Should be called with the send lock set, if required.
1415 * The trick here is to increment the sref at the start, so that the nfsds
1416 * will stop using it and clear ns_flag at the end so that it will not be
1417 * reassigned during cleanup.
1420 nfsrv_zapsock(struct nfssvc_sock
*slp
)
1424 if ((slp
->ns_flag
& SLP_VALID
) == 0)
1426 slp
->ns_flag
&= ~SLP_ALLFLAGS
;
1433 * Attempt to deter future upcalls, but leave the
1434 * upcall info in place to avoid a race with the
1438 so
->so_rcv
.sb_flags
&= ~SB_UPCALL
;
1439 socket_unlock(so
, 1);
1441 sock_shutdown(so
, SHUT_RDWR
);
1445 * Get an authorization string for the uid by having the mount_nfs sitting
1446 * on this mount point porpous out of the kernel and do it.
1449 nfs_getauth(nmp
, rep
, cred
, auth_str
, auth_len
, verf_str
, verf_len
, key
)
1450 register struct nfsmount
*nmp
;
1457 NFSKERBKEY_T key
; /* return session key */
1461 while ((nmp
->nm_state
& NFSSTA_WAITAUTH
) == 0) {
1462 nmp
->nm_state
|= NFSSTA_WANTAUTH
;
1463 (void) tsleep((caddr_t
)&nmp
->nm_authtype
, PSOCK
,
1464 "nfsauth1", 2 * hz
);
1465 error
= nfs_sigintr(nmp
, rep
, rep
->r_procp
);
1467 nmp
->nm_state
&= ~NFSSTA_WANTAUTH
;
1471 nmp
->nm_state
&= ~NFSSTA_WANTAUTH
;
1472 MALLOC(*auth_str
, char *, RPCAUTH_MAXSIZ
, M_TEMP
, M_WAITOK
);
1475 nmp
->nm_authstr
= *auth_str
;
1476 nmp
->nm_authlen
= RPCAUTH_MAXSIZ
;
1477 nmp
->nm_verfstr
= verf_str
;
1478 nmp
->nm_verflen
= *verf_len
;
1479 nmp
->nm_authuid
= kauth_cred_getuid(cred
);
1480 nmp
->nm_state
&= ~NFSSTA_WAITAUTH
;
1481 wakeup((caddr_t
)&nmp
->nm_authstr
);
1484 * And wait for mount_nfs to do its stuff.
1486 while ((nmp
->nm_state
& NFSSTA_HASAUTH
) == 0 && error
== 0) {
1487 (void) tsleep((caddr_t
)&nmp
->nm_authlen
, PSOCK
,
1488 "nfsauth2", 2 * hz
);
1489 error
= nfs_sigintr(nmp
, rep
, rep
->r_procp
);
1491 if (nmp
->nm_state
& NFSSTA_AUTHERR
) {
1492 nmp
->nm_state
&= ~NFSSTA_AUTHERR
;
1496 FREE(*auth_str
, M_TEMP
);
1498 *auth_len
= nmp
->nm_authlen
;
1499 *verf_len
= nmp
->nm_verflen
;
1500 bcopy((caddr_t
)nmp
->nm_key
, (caddr_t
)key
, sizeof (key
));
1502 nmp
->nm_state
&= ~NFSSTA_HASAUTH
;
1503 nmp
->nm_state
|= NFSSTA_WAITAUTH
;
1504 if (nmp
->nm_state
& NFSSTA_WANTAUTH
) {
1505 nmp
->nm_state
&= ~NFSSTA_WANTAUTH
;
1506 wakeup((caddr_t
)&nmp
->nm_authtype
);
1512 * Get a nickname authenticator and verifier.
1516 struct nfsmount
*nmp
,
1521 __unused
int verf_len
)
1523 register struct nfsuid
*nuidp
;
1524 register u_long
*nickp
, *verfp
;
1525 struct timeval ktvin
, ktvout
, now
;
1528 if (verf_len
< (4 * NFSX_UNSIGNED
))
1529 panic("nfs_getnickauth verf too small");
1531 for (nuidp
= NMUIDHASH(nmp
, kauth_cred_getuid(cred
))->lh_first
;
1532 nuidp
!= 0; nuidp
= nuidp
->nu_hash
.le_next
) {
1533 if (kauth_cred_getuid(nuidp
->nu_cr
) == kauth_cred_getuid(cred
))
1537 if (!nuidp
|| nuidp
->nu_expire
< now
.tv_sec
)
1540 MALLOC(nickp
, u_long
*, 2 * NFSX_UNSIGNED
, M_TEMP
, M_WAITOK
);
1545 * Move to the end of the lru list (end of lru == most recently used).
1547 TAILQ_REMOVE(&nmp
->nm_uidlruhead
, nuidp
, nu_lru
);
1548 TAILQ_INSERT_TAIL(&nmp
->nm_uidlruhead
, nuidp
, nu_lru
);
1550 *nickp
++ = txdr_unsigned(RPCAKN_NICKNAME
);
1551 *nickp
= txdr_unsigned(nuidp
->nu_nickname
);
1552 *auth_str
= (char *)nickp
;
1553 *auth_len
= 2 * NFSX_UNSIGNED
;
1556 * Now we must encrypt the verifier and package it up.
1558 verfp
= (u_long
*)verf_str
;
1559 *verfp
++ = txdr_unsigned(RPCAKN_NICKNAME
);
1561 if (now
.tv_sec
> nuidp
->nu_timestamp
.tv_sec
||
1562 (now
.tv_sec
== nuidp
->nu_timestamp
.tv_sec
&&
1563 now
.tv_usec
> nuidp
->nu_timestamp
.tv_usec
))
1564 nuidp
->nu_timestamp
= now
;
1566 nuidp
->nu_timestamp
.tv_usec
++;
1567 ktvin
.tv_sec
= txdr_unsigned(nuidp
->nu_timestamp
.tv_sec
);
1568 ktvin
.tv_usec
= txdr_unsigned(nuidp
->nu_timestamp
.tv_usec
);
1571 * Now encrypt the timestamp verifier in ecb mode using the session
1578 *verfp
++ = ktvout
.tv_sec
;
1579 *verfp
++ = ktvout
.tv_usec
;
1585 * Save the current nickname in a hash list entry on the mount point.
1588 nfs_savenickauth(nmp
, cred
, len
, key
, mdp
, dposp
, mrep
)
1589 register struct nfsmount
*nmp
;
1597 register struct nfsuid
*nuidp
;
1598 register u_long
*tl
;
1601 struct timeval ktvin
, ktvout
, now
;
1603 char *dpos
= *dposp
, *cp2
;
1604 int deltasec
, error
= 0;
1606 if (len
== (3 * NFSX_UNSIGNED
)) {
1607 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
1608 ktvin
.tv_sec
= *tl
++;
1609 ktvin
.tv_usec
= *tl
++;
1610 nick
= fxdr_unsigned(u_long
, *tl
);
1613 * Decrypt the timestamp in ecb mode.
1618 ktvout
.tv_sec
= fxdr_unsigned(long, ktvout
.tv_sec
);
1619 ktvout
.tv_usec
= fxdr_unsigned(long, ktvout
.tv_usec
);
1621 deltasec
= now
.tv_sec
- ktvout
.tv_sec
;
1623 deltasec
= -deltasec
;
1625 * If ok, add it to the hash list for the mount point.
1627 if (deltasec
<= NFS_KERBCLOCKSKEW
) {
1628 if (nmp
->nm_numuids
< nuidhash_max
) {
1630 MALLOC_ZONE(nuidp
, struct nfsuid
*,
1631 sizeof (struct nfsuid
),
1632 M_NFSUID
, M_WAITOK
);
1637 nuidp
= nmp
->nm_uidlruhead
.tqh_first
;
1642 LIST_REMOVE(nuidp
, nu_hash
);
1643 TAILQ_REMOVE(&nmp
->nm_uidlruhead
, nuidp
, nu_lru
);
1644 kauth_cred_unref(&nuidp
->nu_cr
);
1647 kauth_cred_ref(cred
);
1648 nuidp
->nu_cr
= cred
;
1649 nuidp
->nu_expire
= now
.tv_sec
+ NFS_KERBTTL
;
1650 nuidp
->nu_timestamp
= ktvout
;
1651 nuidp
->nu_nickname
= nick
;
1652 bcopy(key
, nuidp
->nu_key
, sizeof (key
));
1653 TAILQ_INSERT_TAIL(&nmp
->nm_uidlruhead
, nuidp
, nu_lru
);
1654 LIST_INSERT_HEAD(NMUIDHASH(nmp
, kauth_cred_getuid(cred
)),
1658 nfsm_adv(nfsm_rndup(len
));
1665 #ifndef NFS_NOSERVER
1668 * cleanup and release a server socket structure.
1671 nfsrv_slpfree(struct nfssvc_sock
*slp
)
1673 struct nfsuid
*nuidp
, *nnuidp
;
1674 struct nfsrv_descript
*nwp
, *nnwp
;
1677 sock_release(slp
->ns_so
);
1681 mbuf_free(slp
->ns_nam
);
1683 mbuf_freem(slp
->ns_raw
);
1685 mbuf_freem(slp
->ns_rec
);
1686 slp
->ns_nam
= slp
->ns_raw
= slp
->ns_rec
= NULL
;
1688 for (nuidp
= slp
->ns_uidlruhead
.tqh_first
; nuidp
!= 0;
1690 nnuidp
= nuidp
->nu_lru
.tqe_next
;
1691 LIST_REMOVE(nuidp
, nu_hash
);
1692 TAILQ_REMOVE(&slp
->ns_uidlruhead
, nuidp
, nu_lru
);
1693 if (nuidp
->nu_flag
& NU_NAM
)
1694 mbuf_freem(nuidp
->nu_nam
);
1695 kauth_cred_unref(&nuidp
->nu_cr
);
1696 FREE_ZONE((caddr_t
)nuidp
,
1697 sizeof (struct nfsuid
), M_NFSUID
);
1700 for (nwp
= slp
->ns_tq
.lh_first
; nwp
; nwp
= nnwp
) {
1701 nnwp
= nwp
->nd_tq
.le_next
;
1702 LIST_REMOVE(nwp
, nd_tq
);
1703 if (IS_VALID_CRED(nwp
->nd_cr
))
1704 kauth_cred_unref(&nwp
->nd_cr
);
1705 FREE_ZONE((caddr_t
)nwp
, sizeof *nwp
, M_NFSRVDESC
);
1707 LIST_INIT(&slp
->ns_tq
);
1709 lck_rw_destroy(&slp
->ns_rwlock
, nfs_slp_rwlock_group
);
1710 lck_mtx_destroy(&slp
->ns_wgmutex
, nfs_slp_mutex_group
);
1711 FREE(slp
, M_NFSSVC
);
1715 * Derefence a server socket structure. If it has no more references and
1716 * is no longer valid, you can throw it away.
1719 nfsrv_slpderef(struct nfssvc_sock
*slp
)
1723 lck_mtx_lock(nfsd_mutex
);
1724 lck_rw_lock_exclusive(&slp
->ns_rwlock
);
1726 if (slp
->ns_sref
|| (slp
->ns_flag
& SLP_VALID
)) {
1727 lck_rw_done(&slp
->ns_rwlock
);
1728 lck_mtx_unlock(nfsd_mutex
);
1732 /* queue the socket up for deletion */
1734 slp
->ns_timestamp
= now
.tv_sec
;
1735 TAILQ_REMOVE(&nfssvc_sockhead
, slp
, ns_chain
);
1736 TAILQ_INSERT_TAIL(&nfssvc_deadsockhead
, slp
, ns_chain
);
1737 lck_rw_done(&slp
->ns_rwlock
);
1738 if (slp
== nfs_udpsock
)
1741 else if (slp
== nfs_cltpsock
)
1742 nfs_cltpsock
= NULL
;
1744 lck_mtx_unlock(nfsd_mutex
);
1749 * Initialize the data structures for the server.
1750 * Handshake with any new nfsds starting up to avoid any chance of
1754 nfsrv_init(terminating
)
1757 struct nfssvc_sock
*slp
, *nslp
;
1762 for (slp
= TAILQ_FIRST(&nfssvc_sockhead
); slp
!= 0; slp
= nslp
) {
1763 nslp
= TAILQ_NEXT(slp
, ns_chain
);
1764 if (slp
->ns_flag
& SLP_VALID
) {
1765 lck_rw_lock_exclusive(&slp
->ns_rwlock
);
1767 lck_rw_done(&slp
->ns_rwlock
);
1769 /* queue the socket up for deletion */
1770 slp
->ns_timestamp
= now
.tv_sec
;
1771 TAILQ_REMOVE(&nfssvc_sockhead
, slp
, ns_chain
);
1772 TAILQ_INSERT_TAIL(&nfssvc_deadsockhead
, slp
, ns_chain
);
1773 if (slp
== nfs_udpsock
)
1776 else if (slp
== nfs_cltpsock
)
1777 nfs_cltpsock
= NULL
;
1780 nfsrv_cleancache(); /* And clear out server cache */
1781 /* XXX Revisit when enabling WebNFS */
1782 #ifdef WEBNFS_ENABLED
1784 nfs_pub
.np_valid
= 0;
1790 TAILQ_INIT(&nfssvc_sockhead
);
1791 TAILQ_INIT(&nfssvc_deadsockhead
);
1792 TAILQ_INIT(&nfsd_head
);
1793 nfsd_head_flag
&= ~NFSD_CHECKSLP
;
1796 MALLOC(nfs_udpsock
, struct nfssvc_sock
*, sizeof(struct nfssvc_sock
),
1797 M_NFSSVC
, M_WAITOK
);
1799 bzero((caddr_t
)nfs_udpsock
, sizeof (struct nfssvc_sock
));
1800 lck_rw_init(&nfs_udpsock
->ns_rwlock
, nfs_slp_rwlock_group
, nfs_slp_lock_attr
);
1801 lck_mtx_init(&nfs_udpsock
->ns_wgmutex
, nfs_slp_mutex_group
, nfs_slp_lock_attr
);
1802 TAILQ_INIT(&nfs_udpsock
->ns_uidlruhead
);
1803 TAILQ_INSERT_HEAD(&nfssvc_sockhead
, nfs_udpsock
, ns_chain
);
1805 printf("nfsrv_init() failed to allocate UDP socket\n");
1809 MALLOC(nfs_cltpsock
, struct nfssvc_sock
*, sizeof(struct nfssvc_sock
),
1810 M_NFSSVC
, M_WAITOK
);
1812 bzero((caddr_t
)nfs_cltpsock
, sizeof (struct nfssvc_sock
));
1813 lck_rw_init(&nfs_cltpsock
->ns_rwlock
, nfs_slp_rwlock_group
, nfs_slp_lock_attr
);
1814 lck_mtx_init(&nfs_cltpsock
->ns_wgmutex
, nfs_slp_mutex_group
, nfs_slp_lock_attr
);
1815 TAILQ_INIT(&nfs_cltpsock
->ns_uidlruhead
);
1816 TAILQ_INSERT_TAIL(&nfssvc_sockhead
, nfs_cltpsock
, ns_chain
);
1818 printf("nfsrv_init() failed to allocate CLTP socket\n");
1824 * Add entries to the server monitor log.
1827 nfsd_rt(sotype
, nd
, cacherep
)
1829 register struct nfsrv_descript
*nd
;
1832 register struct drt
*rt
;
1835 rt
= &nfsdrt
.drt
[nfsdrt
.pos
];
1836 if (cacherep
== RC_DOIT
)
1838 else if (cacherep
== RC_REPLY
)
1839 rt
->flag
= DRT_CACHEREPLY
;
1841 rt
->flag
= DRT_CACHEDROP
;
1842 if (sotype
== SOCK_STREAM
)
1843 rt
->flag
|= DRT_TCP
;
1844 else if (nd
->nd_flag
& ND_NFSV3
)
1845 rt
->flag
|= DRT_NFSV3
;
1846 rt
->proc
= nd
->nd_procnum
;
1847 if (((struct sockaddr
*)mbuf_data(nd
->nd_nam
))->sa_family
== AF_INET
)
1848 rt
->ipadr
= ((struct sockaddr_in
*)mbuf_data(nd
->nd_nam
))->sin_addr
.s_addr
;
1850 rt
->ipadr
= INADDR_ANY
;
1852 rt
->resptime
= ((now
.tv_sec
- nd
->nd_starttime
.tv_sec
) * 1000000) +
1853 (now
.tv_usec
- nd
->nd_starttime
.tv_usec
);
1854 microtime(&rt
->tstamp
); // XXX unused
1855 nfsdrt
.pos
= (nfsdrt
.pos
+ 1) % NFSRTTLOGSIZ
;
1857 #endif /* NFS_NOSERVER */