]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
5d5c5d0d A |
2 | * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved. |
3 | * | |
8f6c56a5 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
8f6c56a5 A |
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. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
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 | |
8ad349bb | 24 | * limitations under the License. |
8f6c56a5 A |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
1c79356b A |
27 | */ |
28 | /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ | |
29 | /* | |
30 | * Copyright (c) 1989, 1993 | |
31 | * The Regents of the University of California. All rights reserved. | |
32 | * | |
33 | * This code is derived from software contributed to Berkeley by | |
34 | * Rick Macklem at The University of Guelph. | |
35 | * | |
36 | * Redistribution and use in source and binary forms, with or without | |
37 | * modification, are permitted provided that the following conditions | |
38 | * are met: | |
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. | |
51 | * | |
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 | |
62 | * SUCH DAMAGE. | |
63 | * | |
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 $ | |
66 | */ | |
67 | ||
68 | #include <sys/param.h> | |
69 | #include <sys/systm.h> | |
70 | /* XXX CSM 11/25/97 FreeBSD's generated syscall prototypes */ | |
71 | #ifdef notyet | |
72 | #include <sys/sysproto.h> | |
73 | #endif | |
74 | #include <sys/kernel.h> | |
91447636 | 75 | #include <sys/file_internal.h> |
1c79356b A |
76 | #include <sys/filedesc.h> |
77 | #include <sys/stat.h> | |
91447636 A |
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> | |
1c79356b | 82 | #include <sys/sysctl.h> |
55e303ae | 83 | #include <sys/ubc.h> |
1c79356b A |
84 | #include <sys/uio.h> |
85 | #include <sys/malloc.h> | |
91447636 | 86 | #include <sys/kpi_mbuf.h> |
1c79356b A |
87 | #include <sys/socket.h> |
88 | #include <sys/socketvar.h> | |
89 | #include <sys/domain.h> | |
90 | #include <sys/protosw.h> | |
55e303ae A |
91 | #include <sys/fcntl.h> |
92 | #include <sys/lockf.h> | |
1c79356b A |
93 | #include <sys/syslog.h> |
94 | #include <sys/user.h> | |
91447636 A |
95 | #include <sys/sysproto.h> |
96 | #include <sys/kpi_socket.h> | |
97 | #include <libkern/OSAtomic.h> | |
1c79356b | 98 | |
ccc36f2f A |
99 | #include <bsm/audit_kernel.h> |
100 | ||
1c79356b A |
101 | #include <netinet/in.h> |
102 | #include <netinet/tcp.h> | |
103 | #if ISO | |
104 | #include <netiso/iso.h> | |
105 | #endif | |
106 | #include <nfs/xdr_subs.h> | |
107 | #include <nfs/rpcv2.h> | |
108 | #include <nfs/nfsproto.h> | |
109 | #include <nfs/nfs.h> | |
110 | #include <nfs/nfsm_subs.h> | |
111 | #include <nfs/nfsrvcache.h> | |
112 | #include <nfs/nfsmount.h> | |
113 | #include <nfs/nfsnode.h> | |
1c79356b | 114 | #include <nfs/nfsrtt.h> |
55e303ae | 115 | #include <nfs/nfs_lock.h> |
1c79356b | 116 | |
91447636 A |
117 | extern void unix_syscall_return(int); |
118 | ||
1c79356b | 119 | /* Global defs. */ |
91447636 | 120 | extern int (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *nd, |
1c79356b | 121 | struct nfssvc_sock *slp, |
91447636 A |
122 | proc_t procp, |
123 | mbuf_t *mreqp); | |
1c79356b | 124 | extern int nfs_numasync; |
55e303ae | 125 | extern int nfs_ioddelwri; |
1c79356b A |
126 | extern int nfsrtton; |
127 | extern struct nfsstats nfsstats; | |
128 | extern int nfsrvw_procrastinate; | |
129 | extern int nfsrvw_procrastinate_v3; | |
91447636 | 130 | |
1c79356b A |
131 | struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock; |
132 | static int nuidhash_max = NFS_MAXUIDHASH; | |
133 | ||
91447636 A |
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); | |
1c79356b A |
137 | |
138 | static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON]; | |
139 | ||
140 | #ifndef NFS_NOSERVER | |
141 | int nfsd_waiting = 0; | |
142 | static struct nfsdrt nfsdrt; | |
91447636 A |
143 | int nfs_numnfsd = 0; |
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); | |
1c79356b A |
148 | |
149 | static int nfs_privport = 0; | |
150 | /* XXX CSM 11/25/97 Upgrade sysctl.h someday */ | |
151 | #ifdef notyet | |
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, ""); | |
155 | #endif | |
156 | ||
157 | /* | |
158 | * NFS server system calls | |
159 | * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c | |
160 | */ | |
161 | ||
162 | /* | |
163 | * Get file handle system call | |
164 | */ | |
1c79356b | 165 | int |
91447636 | 166 | getfh(proc_t p, struct getfh_args *uap, __unused int *retval) |
1c79356b | 167 | { |
91447636 A |
168 | vnode_t vp; |
169 | struct nfs_filehandle nfh; | |
1c79356b A |
170 | int error; |
171 | struct nameidata nd; | |
91447636 A |
172 | struct vfs_context context; |
173 | char path[MAXPATHLEN], *ptr; | |
174 | u_int pathlen; | |
175 | struct nfs_exportfs *nxfs; | |
176 | struct nfs_export *nx; | |
177 | ||
178 | context.vc_proc = p; | |
179 | context.vc_ucred = kauth_cred_get(); | |
1c79356b A |
180 | |
181 | /* | |
182 | * Must be super user | |
183 | */ | |
91447636 A |
184 | error = proc_suser(p); |
185 | if (error) | |
186 | return (error); | |
187 | ||
188 | error = copyinstr(uap->fname, path, MAXPATHLEN, (size_t *)&pathlen); | |
189 | if (error) | |
1c79356b | 190 | return (error); |
91447636 A |
191 | |
192 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, | |
193 | UIO_SYSSPACE, path, &context); | |
1c79356b A |
194 | error = namei(&nd); |
195 | if (error) | |
196 | return (error); | |
91447636 A |
197 | nameidone(&nd); |
198 | ||
1c79356b | 199 | vp = nd.ni_vp; |
91447636 A |
200 | |
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)) | |
206 | break; | |
207 | } | |
208 | if (!nxfs || strncmp(nxfs->nxfs_path, path, strlen(nxfs->nxfs_path))) { | |
209 | error = EINVAL; | |
210 | goto out; | |
211 | } | |
212 | // find export that best matches remainder of path | |
213 | ptr = path + strlen(nxfs->nxfs_path); | |
214 | while (*ptr && (*ptr == '/')) | |
215 | 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 | |
219 | break; | |
220 | if (!strncmp(nx->nx_path, ptr, len)) | |
221 | break; | |
222 | } | |
223 | if (!nx) { | |
224 | error = EINVAL; | |
225 | goto out; | |
226 | } | |
227 | ||
228 | bzero(&nfh, sizeof(nfh)); | |
4452a7af A |
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); | |
91447636 A |
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) | |
237 | error = EOVERFLOW; | |
238 | nfh.nfh_xh.nxh_fidlen = nfh.nfh_len; | |
239 | nfh.nfh_len += sizeof(nfh.nfh_xh); | |
240 | ||
241 | out: | |
242 | lck_rw_done(&nfs_export_rwlock); | |
243 | vnode_put(vp); | |
1c79356b A |
244 | if (error) |
245 | return (error); | |
91447636 | 246 | error = copyout((caddr_t)&nfh, uap->fhp, sizeof(nfh)); |
1c79356b A |
247 | return (error); |
248 | } | |
249 | ||
250 | #endif /* NFS_NOSERVER */ | |
55e303ae | 251 | |
91447636 A |
252 | extern struct fileops vnops; |
253 | ||
55e303ae A |
254 | /* |
255 | * syscall for the rpc.lockd to use to translate a NFS file handle into | |
256 | * an open descriptor. | |
257 | * | |
258 | * warning: do not remove the suser() call or this becomes one giant | |
259 | * security hole. | |
260 | */ | |
55e303ae | 261 | int |
91447636 A |
262 | fhopen( proc_t p, |
263 | struct fhopen_args *uap, | |
264 | register_t *retval) | |
55e303ae | 265 | { |
91447636 A |
266 | vnode_t vp; |
267 | struct nfs_filehandle nfh; | |
268 | struct nfs_export *nx; | |
269 | struct nfs_export_options *nxo; | |
55e303ae | 270 | struct flock lf; |
91447636 A |
271 | struct fileproc *fp, *nfp; |
272 | int fmode, error, type; | |
55e303ae | 273 | int indx; |
91447636 A |
274 | struct vfs_context context; |
275 | kauth_action_t action; | |
276 | ||
277 | context.vc_proc = p; | |
4452a7af | 278 | context.vc_ucred = kauth_cred_proc_ref(p); |
55e303ae A |
279 | |
280 | /* | |
281 | * Must be super user | |
282 | */ | |
4452a7af A |
283 | error = suser(context.vc_ucred, 0); |
284 | if (error) { | |
285 | kauth_cred_unref(&context.vc_ucred); | |
55e303ae | 286 | return (error); |
4452a7af | 287 | } |
55e303ae A |
288 | |
289 | fmode = FFLAGS(uap->flags); | |
290 | /* why not allow a non-read/write open for our lockd? */ | |
4452a7af A |
291 | if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT)) { |
292 | kauth_cred_unref(&context.vc_ucred); | |
55e303ae | 293 | return (EINVAL); |
4452a7af | 294 | } |
91447636 A |
295 | |
296 | error = copyin(uap->u_fhp, &nfh.nfh_len, sizeof(nfh.nfh_len)); | |
4452a7af A |
297 | if (error) { |
298 | kauth_cred_unref(&context.vc_ucred); | |
91447636 | 299 | return (error); |
4452a7af | 300 | } |
91447636 | 301 | if ((nfh.nfh_len < (int)sizeof(struct nfs_exphandle)) || |
4452a7af A |
302 | (nfh.nfh_len > (int)NFS_MAX_FH_SIZE)) { |
303 | kauth_cred_unref(&context.vc_ucred); | |
91447636 | 304 | return (EINVAL); |
4452a7af | 305 | } |
91447636 | 306 | error = copyin(uap->u_fhp, &nfh, sizeof(nfh.nfh_len) + nfh.nfh_len); |
4452a7af A |
307 | if (error) { |
308 | kauth_cred_unref(&context.vc_ucred); | |
55e303ae | 309 | return (error); |
4452a7af | 310 | } |
91447636 A |
311 | |
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); | |
4452a7af A |
316 | if (error) { |
317 | kauth_cred_unref(&context.vc_ucred); | |
55e303ae | 318 | return (error); |
4452a7af | 319 | } |
91447636 | 320 | |
55e303ae | 321 | /* |
91447636 A |
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;'. | |
55e303ae A |
326 | */ |
327 | ||
328 | /* | |
329 | * from vn_open | |
330 | */ | |
91447636 | 331 | if (vnode_vtype(vp) == VSOCK) { |
55e303ae A |
332 | error = EOPNOTSUPP; |
333 | goto bad; | |
334 | } | |
335 | ||
91447636 A |
336 | /* disallow write operations on directories */ |
337 | if (vnode_isdir(vp) && (fmode & (FWRITE | O_TRUNC))) { | |
338 | error = EISDIR; | |
55e303ae A |
339 | goto bad; |
340 | } | |
341 | ||
91447636 A |
342 | /* compute action to be authorized */ |
343 | action = 0; | |
344 | if (fmode & FREAD) | |
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) | |
349 | goto bad; | |
55e303ae | 350 | |
91447636 A |
351 | if ((error = VNOP_OPEN(vp, fmode, &context))) |
352 | goto bad; | |
353 | if ((error = vnode_ref_ext(vp, fmode))) | |
55e303ae A |
354 | goto bad; |
355 | ||
55e303ae A |
356 | /* |
357 | * end of vn_open code | |
358 | */ | |
359 | ||
91447636 | 360 | // starting here... error paths should call vn_close/vnode_put |
55e303ae | 361 | if ((error = falloc(p, &nfp, &indx)) != 0) { |
4452a7af | 362 | vn_close(vp, fmode & FMASK, context.vc_ucred, p); |
55e303ae A |
363 | goto bad; |
364 | } | |
365 | fp = nfp; | |
366 | ||
91447636 A |
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; | |
371 | ||
372 | // XXX do we really need to support this with fhopen()? | |
55e303ae A |
373 | if (fmode & (O_EXLOCK | O_SHLOCK)) { |
374 | lf.l_whence = SEEK_SET; | |
375 | lf.l_start = 0; | |
376 | lf.l_len = 0; | |
377 | if (fmode & O_EXLOCK) | |
378 | lf.l_type = F_WRLCK; | |
379 | else | |
380 | lf.l_type = F_RDLCK; | |
381 | type = F_FLOCK; | |
382 | if ((fmode & FNONBLOCK) == 0) | |
383 | type |= F_WAIT; | |
91447636 A |
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); | |
4452a7af | 387 | kauth_cred_unref(&context.vc_ucred); |
55e303ae A |
388 | return (error); |
389 | } | |
91447636 | 390 | fp->f_fglob->fg_flag |= FHASLOCK; |
55e303ae A |
391 | } |
392 | ||
91447636 A |
393 | vnode_put(vp); |
394 | ||
395 | proc_fdlock(p); | |
55e303ae | 396 | *fdflags(p, indx) &= ~UF_RESERVED; |
91447636 A |
397 | fp_drop(p, indx, fp, 1); |
398 | proc_fdunlock(p); | |
399 | ||
55e303ae | 400 | *retval = indx; |
4452a7af | 401 | kauth_cred_unref(&context.vc_ucred); |
55e303ae A |
402 | return (0); |
403 | ||
404 | bad: | |
91447636 | 405 | vnode_put(vp); |
4452a7af | 406 | kauth_cred_unref(&context.vc_ucred); |
55e303ae A |
407 | return (error); |
408 | } | |
409 | ||
1c79356b A |
410 | /* |
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 | |
416 | */ | |
1c79356b | 417 | int |
91447636 | 418 | nfssvc(proc_t p, struct nfssvc_args *uap, __unused int *retval) |
1c79356b A |
419 | { |
420 | #ifndef NFS_NOSERVER | |
421 | struct nameidata nd; | |
91447636 A |
422 | mbuf_t nam; |
423 | struct user_nfsd_args user_nfsdarg; | |
1c79356b A |
424 | struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; |
425 | struct nfsd_cargs ncd; | |
426 | struct nfsd *nfsd; | |
427 | struct nfssvc_sock *slp; | |
428 | struct nfsuid *nuidp; | |
429 | struct nfsmount *nmp; | |
55e303ae | 430 | struct timeval now; |
91447636 A |
431 | socket_t so; |
432 | struct vfs_context context; | |
433 | struct ucred temp_cred; | |
1c79356b A |
434 | #endif /* NFS_NOSERVER */ |
435 | int error; | |
436 | ||
ccc36f2f A |
437 | AUDIT_ARG(cmd, uap->flag); |
438 | ||
1c79356b A |
439 | /* |
440 | * Must be super user | |
441 | */ | |
91447636 | 442 | error = proc_suser(p); |
1c79356b A |
443 | if(error) |
444 | return (error); | |
1c79356b A |
445 | if (uap->flag & NFSSVC_BIOD) |
446 | error = nfssvc_iod(p); | |
447 | #ifdef NFS_NOSERVER | |
448 | else | |
449 | error = ENXIO; | |
450 | #else /* !NFS_NOSERVER */ | |
451 | else if (uap->flag & NFSSVC_MNTD) { | |
91447636 A |
452 | |
453 | context.vc_proc = p; | |
454 | context.vc_ucred = kauth_cred_get(); | |
455 | ||
1c79356b A |
456 | error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)); |
457 | if (error) | |
458 | return (error); | |
91447636 A |
459 | |
460 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, | |
461 | (proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32), | |
462 | CAST_USER_ADDR_T(ncd.ncd_dirp), &context); | |
1c79356b A |
463 | error = namei(&nd); |
464 | if (error) | |
465 | return (error); | |
91447636 A |
466 | nameidone(&nd); |
467 | ||
468 | if (vnode_isvroot(nd.ni_vp) == 0) | |
1c79356b | 469 | error = EINVAL; |
91447636 A |
470 | nmp = VFSTONFS(vnode_mount(nd.ni_vp)); |
471 | vnode_put(nd.ni_vp); | |
1c79356b A |
472 | if (error) |
473 | return (error); | |
474 | ||
55e303ae | 475 | if ((nmp->nm_state & NFSSTA_MNTD) && |
1c79356b A |
476 | (uap->flag & NFSSVC_GOTAUTH) == 0) |
477 | return (0); | |
55e303ae | 478 | nmp->nm_state |= NFSSTA_MNTD; |
91447636 | 479 | error = nfskerb_clientd(nmp, &ncd, uap->flag, uap->argp, p); |
1c79356b | 480 | } else if (uap->flag & NFSSVC_ADDSOCK) { |
91447636 A |
481 | if (IS_64BIT_PROCESS(p)) { |
482 | error = copyin(uap->argp, (caddr_t)&user_nfsdarg, sizeof(user_nfsdarg)); | |
483 | } else { | |
484 | struct nfsd_args tmp_args; | |
485 | error = copyin(uap->argp, (caddr_t)&tmp_args, sizeof(tmp_args)); | |
486 | if (error == 0) { | |
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; | |
490 | } | |
491 | } | |
1c79356b A |
492 | if (error) |
493 | return (error); | |
91447636 A |
494 | /* get the socket */ |
495 | error = file_socket(user_nfsdarg.sock, &so); | |
1c79356b A |
496 | if (error) |
497 | return (error); | |
91447636 A |
498 | /* Get the client address for connected sockets. */ |
499 | if (user_nfsdarg.name == USER_ADDR_NULL || user_nfsdarg.namelen == 0) { | |
500 | nam = NULL; | |
501 | } else { | |
502 | error = sockargs(&nam, user_nfsdarg.name, user_nfsdarg.namelen, MBUF_TYPE_SONAME); | |
503 | if (error) { | |
504 | /* drop the iocount file_socket() grabbed on the file descriptor */ | |
505 | file_drop(user_nfsdarg.sock); | |
1c79356b | 506 | return (error); |
91447636 | 507 | } |
1c79356b | 508 | } |
91447636 A |
509 | /* |
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. | |
513 | */ | |
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) { | |
1c79356b A |
518 | error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)); |
519 | if (error) | |
520 | return (error); | |
521 | ||
1c79356b A |
522 | if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) && |
523 | (nfsd->nfsd_slp->ns_flag & SLP_VALID)) { | |
524 | slp = nfsd->nfsd_slp; | |
525 | ||
526 | /* | |
527 | * First check to see if another nfsd has already | |
528 | * added this credential. | |
529 | */ | |
530 | for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first; | |
531 | nuidp != 0; nuidp = nuidp->nu_hash.le_next) { | |
91447636 | 532 | if (kauth_cred_getuid(nuidp->nu_cr) == nsd->nsd_cr.cr_uid && |
1c79356b A |
533 | (!nfsd->nfsd_nd->nd_nam2 || |
534 | netaddr_match(NU_NETFAM(nuidp), | |
535 | &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2))) | |
536 | break; | |
537 | } | |
538 | if (nuidp) { | |
4452a7af A |
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); | |
1c79356b A |
542 | nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; |
543 | } else { | |
544 | /* | |
545 | * Nope, so we will. | |
546 | */ | |
547 | if (slp->ns_numuids < nuidhash_max) { | |
548 | slp->ns_numuids++; | |
549 | nuidp = (struct nfsuid *) | |
550 | _MALLOC_ZONE(sizeof (struct nfsuid), | |
551 | M_NFSUID, M_WAITOK); | |
552 | } else | |
553 | nuidp = (struct nfsuid *)0; | |
554 | if ((slp->ns_flag & SLP_VALID) == 0) { | |
91447636 | 555 | if (nuidp) { |
55e303ae | 556 | FREE_ZONE((caddr_t)nuidp, |
1c79356b | 557 | sizeof (struct nfsuid), M_NFSUID); |
91447636 A |
558 | slp->ns_numuids--; |
559 | } | |
1c79356b A |
560 | } else { |
561 | if (nuidp == (struct nfsuid *)0) { | |
562 | nuidp = slp->ns_uidlruhead.tqh_first; | |
91447636 A |
563 | if (!nuidp) |
564 | return (ENOMEM); | |
1c79356b A |
565 | LIST_REMOVE(nuidp, nu_hash); |
566 | TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, | |
567 | nu_lru); | |
568 | if (nuidp->nu_flag & NU_NAM) | |
91447636 | 569 | mbuf_freem(nuidp->nu_nam); |
4452a7af | 570 | kauth_cred_unref(&nuidp->nu_cr); |
55e303ae | 571 | } |
1c79356b | 572 | nuidp->nu_flag = 0; |
91447636 A |
573 | |
574 | if (nsd->nsd_cr.cr_ngroups > NGROUPS) | |
575 | nsd->nsd_cr.cr_ngroups = NGROUPS; | |
576 | ||
577 | nfsrv_setcred(&nsd->nsd_cr, &temp_cred); | |
578 | nuidp->nu_cr = kauth_cred_create(&temp_cred); | |
579 | ||
580 | if (!nuidp->nu_cr) { | |
581 | FREE_ZONE(nuidp, sizeof(struct nfsuid), M_NFSUID); | |
582 | slp->ns_numuids--; | |
583 | return (ENOMEM); | |
584 | } | |
1c79356b | 585 | nuidp->nu_timestamp = nsd->nsd_timestamp; |
55e303ae A |
586 | microtime(&now); |
587 | nuidp->nu_expire = now.tv_sec + nsd->nsd_ttl; | |
1c79356b A |
588 | /* |
589 | * and save the session key in nu_key. | |
590 | */ | |
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; | |
595 | ||
91447636 | 596 | saddr = mbuf_data(nfsd->nfsd_nd->nd_nam2); |
1c79356b A |
597 | switch (saddr->sin_family) { |
598 | case AF_INET: | |
599 | nuidp->nu_flag |= NU_INETADDR; | |
600 | nuidp->nu_inetaddr = | |
601 | saddr->sin_addr.s_addr; | |
602 | break; | |
603 | case AF_ISO: | |
604 | default: | |
605 | nuidp->nu_flag |= NU_NAM; | |
91447636 A |
606 | error = mbuf_copym(nfsd->nfsd_nd->nd_nam2, 0, |
607 | MBUF_COPYALL, MBUF_WAITOK, | |
608 | &nuidp->nu_nam); | |
609 | if (error) { | |
4452a7af | 610 | kauth_cred_unref(&nuidp->nu_cr); |
91447636 A |
611 | FREE_ZONE(nuidp, sizeof(struct nfsuid), M_NFSUID); |
612 | slp->ns_numuids--; | |
613 | return (error); | |
614 | } | |
1c79356b A |
615 | break; |
616 | }; | |
617 | } | |
618 | TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp, | |
619 | nu_lru); | |
620 | LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid), | |
621 | nuidp, nu_hash); | |
4452a7af A |
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); | |
1c79356b A |
625 | nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; |
626 | } | |
627 | } | |
628 | } | |
629 | if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd)) | |
630 | nfsd->nfsd_flag |= NFSD_AUTHFAIL; | |
631 | error = nfssvc_nfsd(nsd, uap->argp, p); | |
91447636 A |
632 | } else if (uap->flag & NFSSVC_EXPORT) { |
633 | error = nfssvc_export(uap->argp, p); | |
634 | } else { | |
635 | error = EINVAL; | |
1c79356b A |
636 | } |
637 | #endif /* NFS_NOSERVER */ | |
638 | if (error == EINTR || error == ERESTART) | |
639 | error = 0; | |
640 | return (error); | |
641 | } | |
642 | ||
91447636 A |
643 | /* |
644 | * NFSKERB client helper daemon. | |
645 | * Gets authorization strings for "kerb" mounts. | |
646 | */ | |
647 | static int | |
648 | nfskerb_clientd( | |
649 | struct nfsmount *nmp, | |
650 | struct nfsd_cargs *ncd, | |
651 | int flag, | |
652 | user_addr_t argp, | |
653 | proc_t p) | |
654 | { | |
655 | struct nfsuid *nuidp, *nnuidp; | |
656 | int error = 0; | |
657 | struct nfsreq *rp; | |
658 | struct timeval now; | |
659 | ||
660 | /* | |
661 | * First initialize some variables | |
662 | */ | |
663 | microtime(&now); | |
664 | ||
665 | /* | |
666 | * If an authorization string is being passed in, get it. | |
667 | */ | |
668 | if ((flag & NFSSVC_GOTAUTH) && (nmp->nm_state & NFSSTA_MOUNTED) && | |
669 | ((nmp->nm_state & NFSSTA_WAITAUTH) == 0)) { | |
670 | if (nmp->nm_state & NFSSTA_HASAUTH) | |
671 | panic("cld kerb"); | |
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; | |
680 | #if NFSKERB | |
681 | nmp->nm_key = ncd->ncd_key; | |
682 | #endif | |
683 | } else | |
684 | nmp->nm_state |= NFSSTA_AUTHERR; | |
685 | } else | |
686 | nmp->nm_state |= NFSSTA_AUTHERR; | |
687 | nmp->nm_state |= NFSSTA_HASAUTH; | |
688 | wakeup((caddr_t)&nmp->nm_authlen); | |
689 | } else { | |
690 | nmp->nm_state |= NFSSTA_WAITAUTH; | |
691 | } | |
692 | ||
693 | /* | |
694 | * Loop every second updating queue until there is a termination sig. | |
695 | */ | |
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; | |
702 | else | |
703 | return (ENEEDAUTH); | |
704 | } | |
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) | |
4452a7af | 711 | dounmount(nmp->nm_mountp, 0, NULL, p); |
91447636 A |
712 | } |
713 | } | |
714 | ||
715 | /* | |
716 | * Finally, we can free up the mount structure. | |
717 | */ | |
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); | |
4452a7af | 722 | kauth_cred_unref(&nuidp->nu_cr); |
91447636 A |
723 | FREE_ZONE((caddr_t)nuidp, sizeof (struct nfsuid), M_NFSUID); |
724 | } | |
725 | /* | |
726 | * Loop through outstanding request list and remove dangling | |
727 | * references to defunct nfsmount struct | |
728 | */ | |
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); | |
736 | } | |
737 | FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT); | |
738 | if (error == EWOULDBLOCK) | |
739 | error = 0; | |
740 | return (error); | |
741 | } | |
742 | ||
1c79356b A |
743 | #ifndef NFS_NOSERVER |
744 | /* | |
745 | * Adds a socket to the list for servicing by nfsds. | |
746 | */ | |
747 | static int | |
91447636 A |
748 | nfssvc_addsock( |
749 | socket_t so, | |
750 | mbuf_t mynam, | |
751 | __unused proc_t p) | |
1c79356b | 752 | { |
91447636 A |
753 | int siz; |
754 | struct nfssvc_sock *slp; | |
755 | struct nfssvc_sock *tslp = NULL; | |
756 | int error, sodomain, sotype, soprotocol, on = 1; | |
757 | struct timeval timeo; | |
758 | ||
759 | /* make sure mbuf constants are set up */ | |
760 | if (!nfs_mbuf_mlen) | |
761 | nfs_mbuf_init(); | |
762 | ||
763 | sock_gettype(so, &sodomain, &sotype, &soprotocol); | |
764 | ||
1c79356b A |
765 | /* |
766 | * Add it to the list, as required. | |
767 | */ | |
91447636 | 768 | if (soprotocol == IPPROTO_UDP) { |
1c79356b | 769 | tslp = nfs_udpsock; |
91447636 A |
770 | if (!tslp || (tslp->ns_flag & SLP_VALID)) { |
771 | mbuf_freem(mynam); | |
1c79356b A |
772 | return (EPERM); |
773 | } | |
774 | #if ISO | |
91447636 | 775 | } else if (soprotocol == ISOPROTO_CLTP) { |
1c79356b | 776 | tslp = nfs_cltpsock; |
91447636 A |
777 | if (!tslp || (tslp->ns_flag & SLP_VALID)) { |
778 | mbuf_freem(mynam); | |
1c79356b A |
779 | return (EPERM); |
780 | } | |
781 | #endif /* ISO */ | |
782 | } | |
55e303ae A |
783 | /* reserve buffer space for 2 maximally-sized packets */ |
784 | siz = NFS_MAXPACKET; | |
91447636 | 785 | if (sotype == SOCK_STREAM) |
55e303ae A |
786 | siz += sizeof (u_long); |
787 | siz *= 2; | |
788 | if (siz > NFS_MAXSOCKBUF) | |
789 | siz = NFS_MAXSOCKBUF; | |
91447636 A |
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)))) { | |
792 | mbuf_freem(mynam); | |
1c79356b A |
793 | return (error); |
794 | } | |
795 | ||
796 | /* | |
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. | |
800 | */ | |
91447636 A |
801 | if (sotype == SOCK_STREAM) { |
802 | sock_setsockopt(so, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); | |
1c79356b | 803 | } |
91447636 A |
804 | if (sodomain == AF_INET && soprotocol == IPPROTO_TCP) { |
805 | sock_setsockopt(so, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); | |
1c79356b A |
806 | } |
807 | ||
91447636 A |
808 | sock_nointerrupt(so, 0); |
809 | ||
810 | timeo.tv_usec = 0; | |
811 | timeo.tv_sec = 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)); | |
814 | ||
815 | if (tslp) { | |
1c79356b | 816 | slp = tslp; |
91447636 A |
817 | lck_mtx_lock(nfsd_mutex); |
818 | } else { | |
1c79356b A |
819 | MALLOC(slp, struct nfssvc_sock *, sizeof(struct nfssvc_sock), |
820 | M_NFSSVC, M_WAITOK); | |
91447636 A |
821 | if (!slp) { |
822 | mbuf_freem(mynam); | |
823 | return (ENOMEM); | |
824 | } | |
1c79356b | 825 | bzero((caddr_t)slp, sizeof (struct nfssvc_sock)); |
91447636 A |
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); | |
1c79356b | 828 | TAILQ_INIT(&slp->ns_uidlruhead); |
91447636 | 829 | lck_mtx_lock(nfsd_mutex); |
1c79356b A |
830 | TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); |
831 | } | |
91447636 A |
832 | |
833 | sock_retain(so); /* grab a retain count on the socket */ | |
1c79356b | 834 | slp->ns_so = so; |
91447636 | 835 | slp->ns_sotype = sotype; |
1c79356b | 836 | slp->ns_nam = mynam; |
91447636 A |
837 | |
838 | socket_lock(so, 1); | |
1c79356b A |
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 */ | |
91447636 A |
842 | socket_unlock(so, 1); |
843 | ||
844 | slp->ns_flag = SLP_VALID | SLP_NEEDQ; | |
845 | ||
1c79356b | 846 | nfsrv_wakenfsd(slp); |
91447636 A |
847 | lck_mtx_unlock(nfsd_mutex); |
848 | ||
1c79356b A |
849 | return (0); |
850 | } | |
851 | ||
852 | /* | |
853 | * Called by nfssvc() for nfsds. Just loops around servicing rpc requests | |
854 | * until it is killed by a signal. | |
855 | */ | |
856 | static int | |
857 | nfssvc_nfsd(nsd, argp, p) | |
858 | struct nfsd_srvargs *nsd; | |
91447636 A |
859 | user_addr_t argp; |
860 | proc_t p; | |
1c79356b | 861 | { |
91447636 A |
862 | mbuf_t m, mreq; |
863 | struct nfssvc_sock *slp; | |
1c79356b A |
864 | struct nfsd *nfsd = nsd->nsd_nfsd; |
865 | struct nfsrv_descript *nd = NULL; | |
91447636 A |
866 | int error = 0, cacherep, writes_todo; |
867 | int siz, procrastinate; | |
1c79356b | 868 | u_quad_t cur_usec; |
55e303ae | 869 | struct timeval now; |
91447636 | 870 | boolean_t funnel_state; |
1c79356b A |
871 | |
872 | #ifndef nolint | |
873 | cacherep = RC_DOIT; | |
874 | writes_todo = 0; | |
875 | #endif | |
1c79356b A |
876 | if (nfsd == (struct nfsd *)0) { |
877 | MALLOC(nfsd, struct nfsd *, sizeof(struct nfsd), M_NFSD, M_WAITOK); | |
91447636 A |
878 | if (!nfsd) |
879 | return (ENOMEM); | |
1c79356b A |
880 | nsd->nsd_nfsd = nfsd; |
881 | bzero((caddr_t)nfsd, sizeof (struct nfsd)); | |
882 | nfsd->nfsd_procp = p; | |
91447636 | 883 | lck_mtx_lock(nfsd_mutex); |
1c79356b A |
884 | TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain); |
885 | nfs_numnfsd++; | |
91447636 | 886 | lck_mtx_unlock(nfsd_mutex); |
1c79356b | 887 | } |
91447636 A |
888 | |
889 | funnel_state = thread_funnel_set(kernel_flock, FALSE); | |
890 | ||
1c79356b A |
891 | /* |
892 | * Loop getting rpc requests until SIGKILL. | |
893 | */ | |
894 | for (;;) { | |
895 | if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) { | |
91447636 A |
896 | lck_mtx_lock(nfsd_mutex); |
897 | while ((nfsd->nfsd_slp == NULL) && !(nfsd_head_flag & NFSD_CHECKSLP)) { | |
1c79356b A |
898 | nfsd->nfsd_flag |= NFSD_WAITING; |
899 | nfsd_waiting++; | |
91447636 | 900 | error = msleep(nfsd, nfsd_mutex, PSOCK | PCATCH, "nfsd", 0); |
1c79356b | 901 | nfsd_waiting--; |
91447636 A |
902 | if (error) { |
903 | lck_mtx_unlock(nfsd_mutex); | |
1c79356b | 904 | goto done; |
91447636 | 905 | } |
1c79356b | 906 | } |
91447636 A |
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); | |
1c79356b A |
910 | if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) |
911 | == (SLP_VALID | SLP_DOREC)) { | |
91447636 A |
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); | |
919 | continue; | |
920 | } | |
921 | } | |
1c79356b A |
922 | slp->ns_flag &= ~SLP_DOREC; |
923 | slp->ns_sref++; | |
924 | nfsd->nfsd_slp = slp; | |
91447636 | 925 | lck_rw_done(&slp->ns_rwlock); |
1c79356b A |
926 | break; |
927 | } | |
91447636 | 928 | lck_rw_done(&slp->ns_rwlock); |
1c79356b A |
929 | } |
930 | if (slp == 0) | |
931 | nfsd_head_flag &= ~NFSD_CHECKSLP; | |
932 | } | |
91447636 A |
933 | lck_mtx_unlock(nfsd_mutex); |
934 | if ((slp = nfsd->nfsd_slp) == NULL) | |
1c79356b | 935 | continue; |
91447636 | 936 | lck_rw_lock_exclusive(&slp->ns_rwlock); |
1c79356b | 937 | if (slp->ns_flag & SLP_VALID) { |
743b1565 | 938 | if ((slp->ns_flag & (SLP_NEEDQ|SLP_DISCONN)) == SLP_NEEDQ) { |
91447636 A |
939 | slp->ns_flag &= ~SLP_NEEDQ; |
940 | nfsrv_rcv_locked(slp->ns_so, slp, MBUF_WAITOK); | |
941 | } | |
743b1565 A |
942 | if (slp->ns_flag & SLP_DISCONN) |
943 | nfsrv_zapsock(slp); | |
1c79356b | 944 | error = nfsrv_dorec(slp, nfsd, &nd); |
55e303ae A |
945 | microuptime(&now); |
946 | cur_usec = (u_quad_t)now.tv_sec * 1000000 + | |
947 | (u_quad_t)now.tv_usec; | |
91447636 | 948 | if (error && slp->ns_wgtime && (slp->ns_wgtime <= cur_usec)) { |
1c79356b A |
949 | error = 0; |
950 | cacherep = RC_DOIT; | |
951 | writes_todo = 1; | |
952 | } else | |
953 | writes_todo = 0; | |
954 | nfsd->nfsd_flag |= NFSD_REQINPROG; | |
955 | } | |
91447636 | 956 | lck_rw_done(&slp->ns_rwlock); |
1c79356b A |
957 | } else { |
958 | error = 0; | |
959 | slp = nfsd->nfsd_slp; | |
960 | } | |
961 | if (error || (slp->ns_flag & SLP_VALID) == 0) { | |
962 | if (nd) { | |
55e303ae | 963 | if (nd->nd_nam2) |
91447636 | 964 | mbuf_freem(nd->nd_nam2); |
4452a7af A |
965 | if (IS_VALID_CRED(nd->nd_cr)) |
966 | kauth_cred_unref(&nd->nd_cr); | |
55e303ae | 967 | FREE_ZONE((caddr_t)nd, |
1c79356b A |
968 | sizeof *nd, M_NFSRVDESC); |
969 | nd = NULL; | |
970 | } | |
91447636 | 971 | nfsd->nfsd_slp = NULL; |
1c79356b A |
972 | nfsd->nfsd_flag &= ~NFSD_REQINPROG; |
973 | nfsrv_slpderef(slp); | |
974 | continue; | |
975 | } | |
1c79356b | 976 | if (nd) { |
55e303ae | 977 | microuptime(&nd->nd_starttime); |
1c79356b A |
978 | if (nd->nd_nam2) |
979 | nd->nd_nam = nd->nd_nam2; | |
980 | else | |
981 | nd->nd_nam = slp->ns_nam; | |
982 | ||
983 | /* | |
984 | * Check to see if authorization is needed. | |
985 | */ | |
986 | if (nfsd->nfsd_flag & NFSD_NEEDAUTH) { | |
987 | nfsd->nfsd_flag &= ~NFSD_NEEDAUTH; | |
91447636 | 988 | nsd->nsd_haddr = ((struct sockaddr_in *)mbuf_data(nd->nd_nam))->sin_addr.s_addr; |
1c79356b A |
989 | nsd->nsd_authlen = nfsd->nfsd_authlen; |
990 | nsd->nsd_verflen = nfsd->nfsd_verflen; | |
91447636 | 991 | if (!copyout(nfsd->nfsd_authstr,CAST_USER_ADDR_T(nsd->nsd_authstr), |
1c79356b | 992 | nfsd->nfsd_authlen) && |
91447636 | 993 | !copyout(nfsd->nfsd_verfstr, CAST_USER_ADDR_T(nsd->nsd_verfstr), |
1c79356b | 994 | nfsd->nfsd_verflen) && |
91447636 A |
995 | !copyout((caddr_t)nsd, argp, sizeof (*nsd))) { |
996 | thread_funnel_set(kernel_flock, funnel_state); | |
1c79356b | 997 | return (ENEEDAUTH); |
91447636 | 998 | } |
1c79356b A |
999 | cacherep = RC_DROPIT; |
1000 | } else | |
1001 | cacherep = nfsrv_getcache(nd, slp, &mreq); | |
1002 | ||
91447636 | 1003 | if (nfsd->nfsd_flag & NFSD_AUTHFAIL) { |
1c79356b A |
1004 | nfsd->nfsd_flag &= ~NFSD_AUTHFAIL; |
1005 | nd->nd_procnum = NFSPROC_NOOP; | |
1006 | nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); | |
1007 | cacherep = RC_DOIT; | |
1008 | } else if (nfs_privport) { | |
1009 | /* Check if source port is privileged */ | |
1010 | u_short port; | |
91447636 | 1011 | struct sockaddr *nam = mbuf_data(nd->nd_nam); |
1c79356b A |
1012 | struct sockaddr_in *sin; |
1013 | ||
1014 | sin = (struct sockaddr_in *)nam; | |
1015 | port = ntohs(sin->sin_port); | |
1016 | if (port >= IPPORT_RESERVED && | |
1017 | nd->nd_procnum != NFSPROC_NULL) { | |
91447636 | 1018 | char strbuf[MAX_IPv4_STR_LEN]; |
1c79356b A |
1019 | nd->nd_procnum = NFSPROC_NOOP; |
1020 | nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); | |
1021 | cacherep = RC_DOIT; | |
1022 | printf("NFS request from unprivileged port (%s:%d)\n", | |
91447636 A |
1023 | inet_ntop(AF_INET, &sin->sin_addr, strbuf, sizeof(strbuf)), |
1024 | port); | |
1c79356b A |
1025 | } |
1026 | } | |
1027 | ||
1028 | } | |
1029 | ||
1030 | /* | |
1031 | * Loop to get all the write rpc relies that have been | |
1032 | * gathered together. | |
1033 | */ | |
1034 | do { | |
1035 | switch (cacherep) { | |
1036 | case RC_DOIT: | |
1037 | if (nd && (nd->nd_flag & ND_NFSV3)) | |
1038 | procrastinate = nfsrvw_procrastinate_v3; | |
1039 | else | |
1040 | procrastinate = nfsrvw_procrastinate; | |
91447636 A |
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); | |
1c79356b | 1044 | else |
91447636 A |
1045 | error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, slp, nfsd->nfsd_procp, &mreq); |
1046 | lck_rw_done(&nfs_export_rwlock); | |
1c79356b A |
1047 | if (mreq == NULL) |
1048 | break; | |
1049 | if (error) { | |
91447636 | 1050 | OSAddAtomic(1, (SInt32*)&nfsstats.srv_errs); |
1c79356b | 1051 | nfsrv_updatecache(nd, FALSE, mreq); |
55e303ae | 1052 | if (nd->nd_nam2) { |
91447636 | 1053 | mbuf_freem(nd->nd_nam2); |
55e303ae A |
1054 | nd->nd_nam2 = NULL; |
1055 | } | |
1c79356b A |
1056 | break; |
1057 | } | |
91447636 | 1058 | OSAddAtomic(1, (SInt32*)&nfsstats.srvrpccnt[nd->nd_procnum]); |
1c79356b | 1059 | nfsrv_updatecache(nd, TRUE, mreq); |
91447636 | 1060 | nd->nd_mrep = NULL; |
1c79356b A |
1061 | case RC_REPLY: |
1062 | m = mreq; | |
1063 | siz = 0; | |
1064 | while (m) { | |
91447636 A |
1065 | siz += mbuf_len(m); |
1066 | m = mbuf_next(m); | |
1c79356b A |
1067 | } |
1068 | if (siz <= 0 || siz > NFS_MAXPACKET) { | |
1069 | printf("mbuf siz=%d\n",siz); | |
1070 | panic("Bad nfs svc reply"); | |
1071 | } | |
1072 | m = mreq; | |
91447636 A |
1073 | mbuf_pkthdr_setlen(m, siz); |
1074 | error = mbuf_pkthdr_setrcvif(m, NULL); | |
1075 | if (error) | |
1076 | panic("nfsd setrcvif failed: %d", error); | |
1c79356b A |
1077 | /* |
1078 | * For stream protocols, prepend a Sun RPC | |
1079 | * Record Mark. | |
1080 | */ | |
91447636 A |
1081 | if (slp->ns_sotype == SOCK_STREAM) { |
1082 | error = mbuf_prepend(&m, NFSX_UNSIGNED, MBUF_WAITOK); | |
1083 | if (!error) | |
1084 | *(u_long*)mbuf_data(m) = htonl(0x80000000 | siz); | |
1c79356b | 1085 | } |
91447636 A |
1086 | if (!error) { |
1087 | if (slp->ns_flag & SLP_VALID) { | |
1088 | error = nfs_send(slp->ns_so, nd->nd_nam2, m, NULL); | |
1089 | } else { | |
1090 | error = EPIPE; | |
1091 | mbuf_freem(m); | |
1092 | } | |
1093 | } else { | |
1094 | mbuf_freem(m); | |
1c79356b | 1095 | } |
55e303ae | 1096 | mreq = NULL; |
1c79356b | 1097 | if (nfsrtton) |
91447636 | 1098 | nfsd_rt(slp->ns_sotype, nd, cacherep); |
55e303ae | 1099 | if (nd->nd_nam2) { |
91447636 | 1100 | mbuf_freem(nd->nd_nam2); |
55e303ae A |
1101 | nd->nd_nam2 = NULL; |
1102 | } | |
1103 | if (nd->nd_mrep) { | |
91447636 | 1104 | mbuf_freem(nd->nd_mrep); |
55e303ae A |
1105 | nd->nd_mrep = NULL; |
1106 | } | |
91447636 A |
1107 | if (error == EPIPE) { |
1108 | lck_rw_lock_exclusive(&slp->ns_rwlock); | |
1c79356b | 1109 | nfsrv_zapsock(slp); |
91447636 A |
1110 | lck_rw_done(&slp->ns_rwlock); |
1111 | } | |
1c79356b | 1112 | if (error == EINTR || error == ERESTART) { |
4452a7af A |
1113 | if (IS_VALID_CRED(nd->nd_cr)) |
1114 | kauth_cred_unref(&nd->nd_cr); | |
91447636 | 1115 | FREE_ZONE((caddr_t)nd, sizeof *nd, M_NFSRVDESC); |
1c79356b | 1116 | nfsrv_slpderef(slp); |
1c79356b A |
1117 | goto done; |
1118 | } | |
1119 | break; | |
1120 | case RC_DROPIT: | |
1121 | if (nfsrtton) | |
91447636 A |
1122 | nfsd_rt(slp->ns_sotype, nd, cacherep); |
1123 | mbuf_freem(nd->nd_mrep); | |
1124 | mbuf_freem(nd->nd_nam2); | |
55e303ae | 1125 | nd->nd_mrep = nd->nd_nam2 = NULL; |
1c79356b A |
1126 | break; |
1127 | }; | |
1128 | if (nd) { | |
55e303ae | 1129 | if (nd->nd_mrep) |
91447636 | 1130 | mbuf_freem(nd->nd_mrep); |
55e303ae | 1131 | if (nd->nd_nam2) |
91447636 | 1132 | mbuf_freem(nd->nd_nam2); |
4452a7af A |
1133 | if (IS_VALID_CRED(nd->nd_cr)) |
1134 | kauth_cred_unref(&nd->nd_cr); | |
1c79356b A |
1135 | FREE_ZONE((caddr_t)nd, sizeof *nd, M_NFSRVDESC); |
1136 | nd = NULL; | |
1137 | } | |
1138 | ||
1139 | /* | |
1140 | * Check to see if there are outstanding writes that | |
1141 | * need to be serviced. | |
1142 | */ | |
55e303ae A |
1143 | microuptime(&now); |
1144 | cur_usec = (u_quad_t)now.tv_sec * 1000000 + | |
1145 | (u_quad_t)now.tv_usec; | |
91447636 | 1146 | if (slp->ns_wgtime && (slp->ns_wgtime <= cur_usec)) { |
1c79356b A |
1147 | cacherep = RC_DOIT; |
1148 | writes_todo = 1; | |
91447636 | 1149 | } else { |
1c79356b | 1150 | writes_todo = 0; |
91447636 | 1151 | } |
1c79356b | 1152 | } while (writes_todo); |
91447636 | 1153 | lck_rw_lock_exclusive(&slp->ns_rwlock); |
1c79356b | 1154 | if (nfsrv_dorec(slp, nfsd, &nd)) { |
91447636 | 1155 | lck_rw_done(&slp->ns_rwlock); |
1c79356b A |
1156 | nfsd->nfsd_flag &= ~NFSD_REQINPROG; |
1157 | nfsd->nfsd_slp = NULL; | |
1158 | nfsrv_slpderef(slp); | |
91447636 A |
1159 | } else { |
1160 | lck_rw_done(&slp->ns_rwlock); | |
1161 | } | |
1c79356b A |
1162 | } |
1163 | done: | |
91447636 A |
1164 | thread_funnel_set(kernel_flock, funnel_state); |
1165 | lck_mtx_lock(nfsd_mutex); | |
1c79356b | 1166 | TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain); |
91447636 | 1167 | FREE(nfsd, M_NFSD); |
1c79356b A |
1168 | nsd->nsd_nfsd = (struct nfsd *)0; |
1169 | if (--nfs_numnfsd == 0) | |
1170 | nfsrv_init(TRUE); /* Reinitialize everything */ | |
91447636 | 1171 | lck_mtx_unlock(nfsd_mutex); |
1c79356b A |
1172 | return (error); |
1173 | } | |
91447636 A |
1174 | |
1175 | static int | |
1176 | nfssvc_export(user_addr_t argp, proc_t p) | |
1177 | { | |
1178 | int error = 0, is_64bit; | |
1179 | struct user_nfs_export_args unxa; | |
1180 | struct vfs_context context; | |
1181 | ||
1182 | context.vc_proc = p; | |
1183 | context.vc_ucred = kauth_cred_get(); | |
1184 | is_64bit = IS_64BIT_PROCESS(p); | |
1185 | ||
1186 | /* copy in pointers to path and export args */ | |
1187 | if (is_64bit) { | |
1188 | error = copyin(argp, (caddr_t)&unxa, sizeof(unxa)); | |
1189 | } else { | |
1190 | struct nfs_export_args tnxa; | |
1191 | error = copyin(argp, (caddr_t)&tnxa, sizeof(tnxa)); | |
1192 | if (error == 0) { | |
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); | |
1201 | } | |
1202 | } | |
1203 | if (error) | |
1204 | return (error); | |
1205 | ||
1206 | error = nfsrv_export(&unxa, &context); | |
1207 | ||
1208 | return (error); | |
1209 | } | |
1210 | ||
1c79356b A |
1211 | #endif /* NFS_NOSERVER */ |
1212 | ||
1213 | int nfs_defect = 0; | |
1214 | /* XXX CSM 11/25/97 Upgrade sysctl.h someday */ | |
1215 | #ifdef notyet | |
1216 | SYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, ""); | |
1217 | #endif | |
1218 | ||
55e303ae | 1219 | int |
91447636 | 1220 | nfsclnt(proc_t p, struct nfsclnt_args *uap, __unused int *retval) |
55e303ae A |
1221 | { |
1222 | struct lockd_ans la; | |
1223 | int error; | |
1224 | ||
1225 | if (uap->flag == NFSCLNT_LOCKDWAIT) { | |
1226 | return (nfslockdwait(p)); | |
1227 | } | |
1228 | if (uap->flag == NFSCLNT_LOCKDANS) { | |
1229 | error = copyin(uap->argp, &la, sizeof(la)); | |
1230 | return (error != 0 ? error : nfslockdans(p, &la)); | |
1231 | } | |
1232 | if (uap->flag == NFSCLNT_LOCKDFD) | |
91447636 | 1233 | return (nfslockdfd(p, CAST_DOWN(int, uap->argp))); |
55e303ae A |
1234 | return EINVAL; |
1235 | } | |
1236 | ||
1237 | ||
1c79356b A |
1238 | static int nfssvc_iod_continue(int); |
1239 | ||
1240 | /* | |
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. | |
1244 | */ | |
1245 | static int | |
91447636 | 1246 | nfssvc_iod(__unused proc_t p) |
1c79356b | 1247 | { |
1c79356b | 1248 | register int i, myiod; |
1c79356b A |
1249 | struct uthread *ut; |
1250 | ||
1251 | /* | |
1252 | * Assign my position or return error if too many already running | |
1253 | */ | |
1254 | myiod = -1; | |
1255 | for (i = 0; i < NFS_MAXASYNCDAEMON; i++) | |
1256 | if (nfs_asyncdaemon[i] == 0) { | |
1257 | nfs_asyncdaemon[i]++; | |
1258 | myiod = i; | |
1259 | break; | |
1260 | } | |
1261 | if (myiod == -1) | |
1262 | return (EBUSY); | |
1263 | nfs_numasync++; | |
1264 | ||
55e303ae | 1265 | /* stuff myiod into uthread to get off local stack for continuation */ |
1c79356b | 1266 | |
91447636 | 1267 | ut = (struct uthread *)get_bsdthread_info(current_thread()); |
1c79356b A |
1268 | ut->uu_state.uu_nfs_myiod = myiod; /* squirrel away for continuation */ |
1269 | ||
1270 | nfssvc_iod_continue(0); | |
1271 | /* NOTREACHED */ | |
91447636 | 1272 | return (0); |
1c79356b A |
1273 | } |
1274 | ||
1275 | /* | |
1276 | * Continuation for Asynchronous I/O daemons for client nfs. | |
1277 | */ | |
1278 | static int | |
91447636 | 1279 | nfssvc_iod_continue(int error) |
1c79356b | 1280 | { |
55e303ae | 1281 | register struct nfsbuf *bp; |
1c79356b A |
1282 | register int i, myiod; |
1283 | struct nfsmount *nmp; | |
1284 | struct uthread *ut; | |
91447636 | 1285 | proc_t p; |
8f6c56a5 | 1286 | int exiterror = 0; |
1c79356b A |
1287 | |
1288 | /* | |
1289 | * real myiod is stored in uthread, recover it | |
1290 | */ | |
91447636 | 1291 | ut = (struct uthread *)get_bsdthread_info(current_thread()); |
1c79356b | 1292 | myiod = ut->uu_state.uu_nfs_myiod; |
91447636 | 1293 | p = current_proc(); // XXX |
1c79356b A |
1294 | |
1295 | /* | |
1296 | * Just loop around doin our stuff until SIGKILL | |
55e303ae | 1297 | * - actually we don't loop with continuations... |
1c79356b | 1298 | */ |
91447636 | 1299 | lck_mtx_lock(nfs_iod_mutex); |
1c79356b A |
1300 | for (;;) { |
1301 | while (((nmp = nfs_iodmount[myiod]) == NULL | |
1302 | || nmp->nm_bufq.tqh_first == NULL) | |
55e303ae | 1303 | && error == 0 && nfs_ioddelwri == 0) { |
1c79356b A |
1304 | if (nmp) |
1305 | nmp->nm_bufqiods--; | |
91447636 | 1306 | nfs_iodwant[myiod] = p; // XXX this doesn't need to be a proc_t |
1c79356b | 1307 | nfs_iodmount[myiod] = NULL; |
91447636 A |
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); | |
1c79356b | 1311 | } |
8f6c56a5 A |
1312 | if (error && !exiterror && nmp && (nmp->nm_bufqiods == 1) && |
1313 | !TAILQ_EMPTY(&nmp->nm_bufq)) { | |
1314 | /* | |
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. | |
1318 | */ | |
1319 | nmp->nm_bufqiods--; | |
1320 | exiterror = error; | |
1321 | error = 0; | |
1322 | } | |
1c79356b A |
1323 | if (error) { |
1324 | nfs_asyncdaemon[myiod] = 0; | |
8f6c56a5 A |
1325 | if (nmp && !exiterror) |
1326 | nmp->nm_bufqiods--; | |
1c79356b A |
1327 | nfs_iodwant[myiod] = NULL; |
1328 | nfs_iodmount[myiod] = NULL; | |
91447636 | 1329 | lck_mtx_unlock(nfs_iod_mutex); |
1c79356b A |
1330 | nfs_numasync--; |
1331 | if (error == EINTR || error == ERESTART) | |
1332 | error = 0; | |
1c79356b | 1333 | unix_syscall_return(error); |
1c79356b | 1334 | } |
55e303ae | 1335 | if (nmp != NULL) { |
91447636 | 1336 | while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) { |
55e303ae A |
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; | |
1340 | nmp->nm_bufqlen--; | |
1341 | if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) { | |
1342 | nmp->nm_bufqwant = FALSE; | |
91447636 | 1343 | lck_mtx_unlock(nfs_iod_mutex); |
55e303ae | 1344 | wakeup(&nmp->nm_bufq); |
91447636 A |
1345 | } else { |
1346 | lck_mtx_unlock(nfs_iod_mutex); | |
55e303ae | 1347 | } |
91447636 A |
1348 | |
1349 | SET(bp->nb_flags, NB_IOD); | |
55e303ae | 1350 | if (ISSET(bp->nb_flags, NB_READ)) |
91447636 | 1351 | nfs_doio(bp, bp->nb_rcred, NULL); |
55e303ae | 1352 | else |
91447636 | 1353 | nfs_doio(bp, bp->nb_wcred, NULL); |
1c79356b | 1354 | |
91447636 | 1355 | lck_mtx_lock(nfs_iod_mutex); |
55e303ae A |
1356 | /* |
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 | |
1359 | */ | |
8f6c56a5 | 1360 | if (!exiterror && nfs_defect && nmp->nm_bufqiods > 1) { |
55e303ae A |
1361 | nfs_iodmount[myiod] = NULL; |
1362 | nmp->nm_bufqiods--; | |
1363 | break; | |
1364 | } | |
1365 | } | |
1366 | } | |
91447636 A |
1367 | lck_mtx_unlock(nfs_iod_mutex); |
1368 | ||
55e303ae A |
1369 | if (nfs_ioddelwri) { |
1370 | i = 0; | |
1371 | nfs_ioddelwri = 0; | |
91447636 | 1372 | lck_mtx_lock(nfs_buf_mutex); |
55e303ae A |
1373 | while (i < 8 && (bp = TAILQ_FIRST(&nfsbufdelwri)) != NULL) { |
1374 | struct nfsnode *np = VTONFS(bp->nb_vp); | |
1375 | nfs_buf_remfree(bp); | |
91447636 A |
1376 | nfs_buf_refget(bp); |
1377 | while ((error = nfs_buf_acquire(bp, 0, 0, 0)) == EAGAIN); | |
1378 | nfs_buf_refrele(bp); | |
1379 | if (error) | |
1380 | break; | |
1381 | if (!bp->nb_vp) { | |
1382 | /* buffer is no longer valid */ | |
1383 | nfs_buf_drop(bp); | |
1384 | continue; | |
1385 | } | |
8f6c56a5 A |
1386 | if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) |
1387 | nfs_buf_check_write_verifier(np, bp); | |
55e303ae A |
1388 | if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) { |
1389 | /* put buffer at end of delwri list */ | |
1390 | TAILQ_INSERT_TAIL(&nfsbufdelwri, bp, nb_free); | |
1391 | nfsbufdelwricnt++; | |
91447636 A |
1392 | nfs_buf_drop(bp); |
1393 | lck_mtx_unlock(nfs_buf_mutex); | |
1394 | nfs_flushcommits(np->n_vnode, NULL, 1); | |
55e303ae | 1395 | } else { |
91447636 A |
1396 | SET(bp->nb_flags, (NB_ASYNC | NB_IOD)); |
1397 | lck_mtx_unlock(nfs_buf_mutex); | |
55e303ae A |
1398 | nfs_buf_write(bp); |
1399 | } | |
1400 | i++; | |
91447636 | 1401 | lck_mtx_lock(nfs_buf_mutex); |
1c79356b | 1402 | } |
91447636 | 1403 | lck_mtx_unlock(nfs_buf_mutex); |
1c79356b | 1404 | } |
91447636 A |
1405 | |
1406 | lck_mtx_lock(nfs_iod_mutex); | |
8f6c56a5 A |
1407 | if (exiterror) |
1408 | error = exiterror; | |
1c79356b A |
1409 | } |
1410 | } | |
1411 | ||
1412 | /* | |
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. | |
1418 | */ | |
1419 | static void | |
91447636 | 1420 | nfsrv_zapsock(struct nfssvc_sock *slp) |
1c79356b | 1421 | { |
91447636 | 1422 | socket_t so; |
1c79356b | 1423 | |
91447636 A |
1424 | if ((slp->ns_flag & SLP_VALID) == 0) |
1425 | return; | |
1c79356b | 1426 | slp->ns_flag &= ~SLP_ALLFLAGS; |
91447636 A |
1427 | |
1428 | so = slp->ns_so; | |
1429 | if (so == NULL) | |
1430 | return; | |
1431 | ||
743b1565 A |
1432 | /* |
1433 | * Attempt to deter future upcalls, but leave the | |
1434 | * upcall info in place to avoid a race with the | |
1435 | * networking code. | |
1436 | */ | |
91447636 | 1437 | socket_lock(so, 1); |
91447636 A |
1438 | so->so_rcv.sb_flags &= ~SB_UPCALL; |
1439 | socket_unlock(so, 1); | |
743b1565 | 1440 | |
91447636 | 1441 | sock_shutdown(so, SHUT_RDWR); |
1c79356b A |
1442 | } |
1443 | ||
1444 | /* | |
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. | |
1447 | */ | |
1448 | int | |
1449 | nfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key) | |
1450 | register struct nfsmount *nmp; | |
1451 | struct nfsreq *rep; | |
91447636 | 1452 | kauth_cred_t cred; |
1c79356b A |
1453 | char **auth_str; |
1454 | int *auth_len; | |
1455 | char *verf_str; | |
1456 | int *verf_len; | |
1457 | NFSKERBKEY_T key; /* return session key */ | |
1458 | { | |
1459 | int error = 0; | |
1460 | ||
55e303ae A |
1461 | while ((nmp->nm_state & NFSSTA_WAITAUTH) == 0) { |
1462 | nmp->nm_state |= NFSSTA_WANTAUTH; | |
1c79356b A |
1463 | (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, |
1464 | "nfsauth1", 2 * hz); | |
1465 | error = nfs_sigintr(nmp, rep, rep->r_procp); | |
1466 | if (error) { | |
55e303ae | 1467 | nmp->nm_state &= ~NFSSTA_WANTAUTH; |
1c79356b A |
1468 | return (error); |
1469 | } | |
1470 | } | |
91447636 | 1471 | nmp->nm_state &= ~NFSSTA_WANTAUTH; |
1c79356b | 1472 | MALLOC(*auth_str, char *, RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); |
91447636 A |
1473 | if (!*auth_str) |
1474 | return (ENOMEM); | |
1c79356b A |
1475 | nmp->nm_authstr = *auth_str; |
1476 | nmp->nm_authlen = RPCAUTH_MAXSIZ; | |
1477 | nmp->nm_verfstr = verf_str; | |
1478 | nmp->nm_verflen = *verf_len; | |
91447636 A |
1479 | nmp->nm_authuid = kauth_cred_getuid(cred); |
1480 | nmp->nm_state &= ~NFSSTA_WAITAUTH; | |
1c79356b A |
1481 | wakeup((caddr_t)&nmp->nm_authstr); |
1482 | ||
1483 | /* | |
1484 | * And wait for mount_nfs to do its stuff. | |
1485 | */ | |
55e303ae | 1486 | while ((nmp->nm_state & NFSSTA_HASAUTH) == 0 && error == 0) { |
1c79356b A |
1487 | (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK, |
1488 | "nfsauth2", 2 * hz); | |
1489 | error = nfs_sigintr(nmp, rep, rep->r_procp); | |
1490 | } | |
55e303ae A |
1491 | if (nmp->nm_state & NFSSTA_AUTHERR) { |
1492 | nmp->nm_state &= ~NFSSTA_AUTHERR; | |
1c79356b A |
1493 | error = EAUTH; |
1494 | } | |
1495 | if (error) | |
91447636 | 1496 | FREE(*auth_str, M_TEMP); |
1c79356b A |
1497 | else { |
1498 | *auth_len = nmp->nm_authlen; | |
1499 | *verf_len = nmp->nm_verflen; | |
1500 | bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key)); | |
1501 | } | |
55e303ae A |
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; | |
1c79356b A |
1506 | wakeup((caddr_t)&nmp->nm_authtype); |
1507 | } | |
1508 | return (error); | |
1509 | } | |
1510 | ||
1511 | /* | |
1512 | * Get a nickname authenticator and verifier. | |
1513 | */ | |
1514 | int | |
91447636 A |
1515 | nfs_getnickauth( |
1516 | struct nfsmount *nmp, | |
1517 | kauth_cred_t cred, | |
1518 | char **auth_str, | |
1519 | int *auth_len, | |
1520 | char *verf_str, | |
1521 | __unused int verf_len) | |
1c79356b A |
1522 | { |
1523 | register struct nfsuid *nuidp; | |
1524 | register u_long *nickp, *verfp; | |
55e303ae | 1525 | struct timeval ktvin, ktvout, now; |
1c79356b A |
1526 | |
1527 | #if DIAGNOSTIC | |
1528 | if (verf_len < (4 * NFSX_UNSIGNED)) | |
1529 | panic("nfs_getnickauth verf too small"); | |
1530 | #endif | |
91447636 | 1531 | for (nuidp = NMUIDHASH(nmp, kauth_cred_getuid(cred))->lh_first; |
1c79356b | 1532 | nuidp != 0; nuidp = nuidp->nu_hash.le_next) { |
91447636 | 1533 | if (kauth_cred_getuid(nuidp->nu_cr) == kauth_cred_getuid(cred)) |
1c79356b A |
1534 | break; |
1535 | } | |
55e303ae A |
1536 | microtime(&now); |
1537 | if (!nuidp || nuidp->nu_expire < now.tv_sec) | |
1c79356b A |
1538 | return (EACCES); |
1539 | ||
91447636 A |
1540 | MALLOC(nickp, u_long *, 2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK); |
1541 | if (!nickp) | |
1542 | return (ENOMEM); | |
1543 | ||
1c79356b A |
1544 | /* |
1545 | * Move to the end of the lru list (end of lru == most recently used). | |
1546 | */ | |
1547 | TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); | |
1548 | TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); | |
1549 | ||
1c79356b A |
1550 | *nickp++ = txdr_unsigned(RPCAKN_NICKNAME); |
1551 | *nickp = txdr_unsigned(nuidp->nu_nickname); | |
1552 | *auth_str = (char *)nickp; | |
1553 | *auth_len = 2 * NFSX_UNSIGNED; | |
1554 | ||
1555 | /* | |
1556 | * Now we must encrypt the verifier and package it up. | |
1557 | */ | |
1558 | verfp = (u_long *)verf_str; | |
1559 | *verfp++ = txdr_unsigned(RPCAKN_NICKNAME); | |
55e303ae A |
1560 | microtime(&now); |
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; | |
1c79356b A |
1565 | else |
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); | |
1569 | ||
1570 | /* | |
1571 | * Now encrypt the timestamp verifier in ecb mode using the session | |
1572 | * key. | |
1573 | */ | |
1574 | #if NFSKERB | |
1575 | XXX | |
1576 | #endif | |
1577 | ||
1578 | *verfp++ = ktvout.tv_sec; | |
1579 | *verfp++ = ktvout.tv_usec; | |
1580 | *verfp = 0; | |
1581 | return (0); | |
1582 | } | |
1583 | ||
1584 | /* | |
1585 | * Save the current nickname in a hash list entry on the mount point. | |
1586 | */ | |
1587 | int | |
1588 | nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep) | |
1589 | register struct nfsmount *nmp; | |
91447636 | 1590 | kauth_cred_t cred; |
1c79356b A |
1591 | int len; |
1592 | NFSKERBKEY_T key; | |
91447636 | 1593 | mbuf_t *mdp; |
1c79356b | 1594 | char **dposp; |
91447636 | 1595 | mbuf_t mrep; |
1c79356b A |
1596 | { |
1597 | register struct nfsuid *nuidp; | |
1598 | register u_long *tl; | |
1599 | register long t1; | |
91447636 | 1600 | mbuf_t md = *mdp; |
55e303ae | 1601 | struct timeval ktvin, ktvout, now; |
1c79356b A |
1602 | u_long nick; |
1603 | char *dpos = *dposp, *cp2; | |
1604 | int deltasec, error = 0; | |
1605 | ||
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); | |
1611 | ||
1612 | /* | |
1613 | * Decrypt the timestamp in ecb mode. | |
1614 | */ | |
1615 | #if NFSKERB | |
1616 | XXX | |
1617 | #endif | |
1618 | ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec); | |
1619 | ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec); | |
55e303ae A |
1620 | microtime(&now); |
1621 | deltasec = now.tv_sec - ktvout.tv_sec; | |
1c79356b A |
1622 | if (deltasec < 0) |
1623 | deltasec = -deltasec; | |
1624 | /* | |
1625 | * If ok, add it to the hash list for the mount point. | |
1626 | */ | |
1627 | if (deltasec <= NFS_KERBCLOCKSKEW) { | |
1628 | if (nmp->nm_numuids < nuidhash_max) { | |
1629 | nmp->nm_numuids++; | |
1630 | MALLOC_ZONE(nuidp, struct nfsuid *, | |
1631 | sizeof (struct nfsuid), | |
1632 | M_NFSUID, M_WAITOK); | |
1633 | } else { | |
91447636 A |
1634 | nuidp = NULL; |
1635 | } | |
1636 | if (!nuidp) { | |
1c79356b | 1637 | nuidp = nmp->nm_uidlruhead.tqh_first; |
91447636 A |
1638 | if (!nuidp) { |
1639 | error = ENOMEM; | |
1640 | goto nfsmout; | |
1641 | } | |
1c79356b | 1642 | LIST_REMOVE(nuidp, nu_hash); |
91447636 | 1643 | TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); |
4452a7af | 1644 | kauth_cred_unref(&nuidp->nu_cr); |
1c79356b A |
1645 | } |
1646 | nuidp->nu_flag = 0; | |
91447636 A |
1647 | kauth_cred_ref(cred); |
1648 | nuidp->nu_cr = cred; | |
55e303ae | 1649 | nuidp->nu_expire = now.tv_sec + NFS_KERBTTL; |
1c79356b A |
1650 | nuidp->nu_timestamp = ktvout; |
1651 | nuidp->nu_nickname = nick; | |
1652 | bcopy(key, nuidp->nu_key, sizeof (key)); | |
91447636 A |
1653 | TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); |
1654 | LIST_INSERT_HEAD(NMUIDHASH(nmp, kauth_cred_getuid(cred)), | |
1c79356b A |
1655 | nuidp, nu_hash); |
1656 | } | |
1657 | } else | |
1658 | nfsm_adv(nfsm_rndup(len)); | |
1659 | nfsmout: | |
1660 | *mdp = md; | |
1661 | *dposp = dpos; | |
1662 | return (error); | |
1663 | } | |
1664 | ||
1665 | #ifndef NFS_NOSERVER | |
1666 | ||
1667 | /* | |
91447636 | 1668 | * cleanup and release a server socket structure. |
1c79356b | 1669 | */ |
743b1565 | 1670 | void |
91447636 | 1671 | nfsrv_slpfree(struct nfssvc_sock *slp) |
1c79356b | 1672 | { |
91447636 A |
1673 | struct nfsuid *nuidp, *nnuidp; |
1674 | struct nfsrv_descript *nwp, *nnwp; | |
1c79356b | 1675 | |
91447636 A |
1676 | if (slp->ns_so) { |
1677 | sock_release(slp->ns_so); | |
1678 | slp->ns_so = NULL; | |
1679 | } | |
1680 | if (slp->ns_nam) | |
1681 | mbuf_free(slp->ns_nam); | |
1682 | if (slp->ns_raw) | |
1683 | mbuf_freem(slp->ns_raw); | |
1684 | if (slp->ns_rec) | |
1685 | mbuf_freem(slp->ns_rec); | |
1686 | slp->ns_nam = slp->ns_raw = slp->ns_rec = NULL; | |
1687 | ||
1688 | for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0; | |
1689 | nuidp = nnuidp) { | |
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); | |
4452a7af | 1695 | kauth_cred_unref(&nuidp->nu_cr); |
91447636 A |
1696 | FREE_ZONE((caddr_t)nuidp, |
1697 | sizeof (struct nfsuid), M_NFSUID); | |
1698 | } | |
55e303ae | 1699 | |
91447636 A |
1700 | for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) { |
1701 | nnwp = nwp->nd_tq.le_next; | |
1702 | LIST_REMOVE(nwp, nd_tq); | |
4452a7af A |
1703 | if (IS_VALID_CRED(nwp->nd_cr)) |
1704 | kauth_cred_unref(&nwp->nd_cr); | |
91447636 | 1705 | FREE_ZONE((caddr_t)nwp, sizeof *nwp, M_NFSRVDESC); |
55e303ae | 1706 | } |
91447636 A |
1707 | LIST_INIT(&slp->ns_tq); |
1708 | ||
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); | |
55e303ae A |
1712 | } |
1713 | ||
1714 | /* | |
91447636 A |
1715 | * Derefence a server socket structure. If it has no more references and |
1716 | * is no longer valid, you can throw it away. | |
55e303ae A |
1717 | */ |
1718 | void | |
91447636 | 1719 | nfsrv_slpderef(struct nfssvc_sock *slp) |
55e303ae | 1720 | { |
743b1565 A |
1721 | struct timeval now; |
1722 | ||
91447636 A |
1723 | lck_mtx_lock(nfsd_mutex); |
1724 | lck_rw_lock_exclusive(&slp->ns_rwlock); | |
1725 | slp->ns_sref--; | |
1726 | if (slp->ns_sref || (slp->ns_flag & SLP_VALID)) { | |
1727 | lck_rw_done(&slp->ns_rwlock); | |
1728 | lck_mtx_unlock(nfsd_mutex); | |
1729 | return; | |
55e303ae | 1730 | } |
91447636 | 1731 | |
743b1565 A |
1732 | /* queue the socket up for deletion */ |
1733 | microuptime(&now); | |
1734 | slp->ns_timestamp = now.tv_sec; | |
91447636 | 1735 | TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); |
743b1565 A |
1736 | TAILQ_INSERT_TAIL(&nfssvc_deadsockhead, slp, ns_chain); |
1737 | lck_rw_done(&slp->ns_rwlock); | |
8ad349bb A |
1738 | if (slp == nfs_udpsock) |
1739 | nfs_udpsock = NULL; | |
1740 | #if ISO | |
1741 | else if (slp == nfs_cltpsock) | |
1742 | nfs_cltpsock = NULL; | |
1743 | #endif | |
91447636 | 1744 | lck_mtx_unlock(nfsd_mutex); |
55e303ae A |
1745 | } |
1746 | ||
91447636 | 1747 | |
1c79356b A |
1748 | /* |
1749 | * Initialize the data structures for the server. | |
1750 | * Handshake with any new nfsds starting up to avoid any chance of | |
1751 | * corruption. | |
1752 | */ | |
1753 | void | |
1754 | nfsrv_init(terminating) | |
1755 | int terminating; | |
1756 | { | |
91447636 | 1757 | struct nfssvc_sock *slp, *nslp; |
743b1565 | 1758 | struct timeval now; |
1c79356b | 1759 | |
1c79356b | 1760 | if (terminating) { |
743b1565 | 1761 | microuptime(&now); |
91447636 A |
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); | |
1c79356b | 1766 | nfsrv_zapsock(slp); |
91447636 A |
1767 | lck_rw_done(&slp->ns_rwlock); |
1768 | } | |
743b1565 A |
1769 | /* queue the socket up for deletion */ |
1770 | slp->ns_timestamp = now.tv_sec; | |
1c79356b | 1771 | TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); |
743b1565 | 1772 | TAILQ_INSERT_TAIL(&nfssvc_deadsockhead, slp, ns_chain); |
8ad349bb A |
1773 | if (slp == nfs_udpsock) |
1774 | nfs_udpsock = NULL; | |
1775 | #if ISO | |
1776 | else if (slp == nfs_cltpsock) | |
1777 | nfs_cltpsock = NULL; | |
1778 | #endif | |
1c79356b A |
1779 | } |
1780 | nfsrv_cleancache(); /* And clear out server cache */ | |
91447636 A |
1781 | /* XXX Revisit when enabling WebNFS */ |
1782 | #ifdef WEBNFS_ENABLED | |
1c79356b A |
1783 | } else |
1784 | nfs_pub.np_valid = 0; | |
1785 | #else | |
1786 | } | |
1787 | #endif | |
1788 | ||
8ad349bb A |
1789 | if (!terminating) { |
1790 | TAILQ_INIT(&nfssvc_sockhead); | |
1791 | TAILQ_INIT(&nfssvc_deadsockhead); | |
1792 | TAILQ_INIT(&nfsd_head); | |
1793 | nfsd_head_flag &= ~NFSD_CHECKSLP; | |
1794 | } | |
1c79356b A |
1795 | |
1796 | MALLOC(nfs_udpsock, struct nfssvc_sock *, sizeof(struct nfssvc_sock), | |
1797 | M_NFSSVC, M_WAITOK); | |
91447636 A |
1798 | if (nfs_udpsock) { |
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); | |
8ad349bb | 1801 | lck_mtx_init(&nfs_udpsock->ns_wgmutex, nfs_slp_mutex_group, nfs_slp_lock_attr); |
91447636 A |
1802 | TAILQ_INIT(&nfs_udpsock->ns_uidlruhead); |
1803 | TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); | |
1804 | } else { | |
1805 | printf("nfsrv_init() failed to allocate UDP socket\n"); | |
1806 | } | |
1c79356b | 1807 | |
91447636 | 1808 | #if ISO |
1c79356b A |
1809 | MALLOC(nfs_cltpsock, struct nfssvc_sock *, sizeof(struct nfssvc_sock), |
1810 | M_NFSSVC, M_WAITOK); | |
91447636 A |
1811 | if (nfs_cltpsock) { |
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); | |
8ad349bb | 1814 | lck_mtx_init(&nfs_cltpsock->ns_wgmutex, nfs_slp_mutex_group, nfs_slp_lock_attr); |
91447636 A |
1815 | TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead); |
1816 | TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); | |
1817 | } else { | |
1818 | printf("nfsrv_init() failed to allocate CLTP socket\n"); | |
1819 | } | |
1820 | #endif | |
1c79356b A |
1821 | } |
1822 | ||
1823 | /* | |
1824 | * Add entries to the server monitor log. | |
1825 | */ | |
1826 | static void | |
1827 | nfsd_rt(sotype, nd, cacherep) | |
1828 | int sotype; | |
1829 | register struct nfsrv_descript *nd; | |
1830 | int cacherep; | |
1831 | { | |
1832 | register struct drt *rt; | |
55e303ae | 1833 | struct timeval now; |
1c79356b A |
1834 | |
1835 | rt = &nfsdrt.drt[nfsdrt.pos]; | |
1836 | if (cacherep == RC_DOIT) | |
1837 | rt->flag = 0; | |
1838 | else if (cacherep == RC_REPLY) | |
1839 | rt->flag = DRT_CACHEREPLY; | |
1840 | else | |
1841 | rt->flag = DRT_CACHEDROP; | |
1842 | if (sotype == SOCK_STREAM) | |
1843 | rt->flag |= DRT_TCP; | |
1c79356b A |
1844 | else if (nd->nd_flag & ND_NFSV3) |
1845 | rt->flag |= DRT_NFSV3; | |
1846 | rt->proc = nd->nd_procnum; | |
91447636 A |
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; | |
1c79356b A |
1849 | else |
1850 | rt->ipadr = INADDR_ANY; | |
55e303ae A |
1851 | microuptime(&now); |
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 | |
1c79356b A |
1855 | nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ; |
1856 | } | |
1857 | #endif /* NFS_NOSERVER */ |