]>
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)); | |
21362eb3 A |
229 | nfh.nfh_xh.nxh_version = NFS_FH_VERSION; |
230 | nfh.nfh_xh.nxh_fsid = nxfs->nxfs_id; | |
231 | nfh.nfh_xh.nxh_expid = 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; |
21362eb3 | 274 | kauth_cred_t cred = proc_ucred(p); |
91447636 A |
275 | struct vfs_context context; |
276 | kauth_action_t action; | |
277 | ||
278 | context.vc_proc = p; | |
21362eb3 | 279 | context.vc_ucred = cred; |
55e303ae A |
280 | |
281 | /* | |
282 | * Must be super user | |
283 | */ | |
21362eb3 A |
284 | error = suser(cred, 0); |
285 | if (error) | |
55e303ae A |
286 | return (error); |
287 | ||
288 | fmode = FFLAGS(uap->flags); | |
289 | /* why not allow a non-read/write open for our lockd? */ | |
21362eb3 | 290 | if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT)) |
55e303ae | 291 | return (EINVAL); |
91447636 A |
292 | |
293 | error = copyin(uap->u_fhp, &nfh.nfh_len, sizeof(nfh.nfh_len)); | |
21362eb3 | 294 | if (error) |
91447636 A |
295 | return (error); |
296 | if ((nfh.nfh_len < (int)sizeof(struct nfs_exphandle)) || | |
21362eb3 | 297 | (nfh.nfh_len > (int)NFS_MAX_FH_SIZE)) |
91447636 A |
298 | return (EINVAL); |
299 | error = copyin(uap->u_fhp, &nfh, sizeof(nfh.nfh_len) + nfh.nfh_len); | |
21362eb3 | 300 | if (error) |
55e303ae | 301 | return (error); |
91447636 A |
302 | |
303 | lck_rw_lock_shared(&nfs_export_rwlock); | |
304 | /* now give me my vnode, it gets returned to me with a reference */ | |
305 | error = nfsrv_fhtovp(&nfh, NULL, TRUE, &vp, &nx, &nxo); | |
306 | lck_rw_done(&nfs_export_rwlock); | |
21362eb3 | 307 | if (error) |
55e303ae | 308 | return (error); |
91447636 | 309 | |
55e303ae | 310 | /* |
91447636 A |
311 | * From now on we have to make sure not |
312 | * to forget about the vnode. | |
313 | * Any error that causes an abort must vnode_put(vp). | |
314 | * Just set error = err and 'goto bad;'. | |
55e303ae A |
315 | */ |
316 | ||
317 | /* | |
318 | * from vn_open | |
319 | */ | |
91447636 | 320 | if (vnode_vtype(vp) == VSOCK) { |
55e303ae A |
321 | error = EOPNOTSUPP; |
322 | goto bad; | |
323 | } | |
324 | ||
91447636 A |
325 | /* disallow write operations on directories */ |
326 | if (vnode_isdir(vp) && (fmode & (FWRITE | O_TRUNC))) { | |
327 | error = EISDIR; | |
55e303ae A |
328 | goto bad; |
329 | } | |
330 | ||
91447636 A |
331 | /* compute action to be authorized */ |
332 | action = 0; | |
333 | if (fmode & FREAD) | |
334 | action |= KAUTH_VNODE_READ_DATA; | |
335 | if (fmode & (FWRITE | O_TRUNC)) | |
336 | action |= KAUTH_VNODE_WRITE_DATA; | |
337 | if ((error = vnode_authorize(vp, NULL, action, &context)) != 0) | |
338 | goto bad; | |
55e303ae | 339 | |
91447636 A |
340 | if ((error = VNOP_OPEN(vp, fmode, &context))) |
341 | goto bad; | |
342 | if ((error = vnode_ref_ext(vp, fmode))) | |
55e303ae A |
343 | goto bad; |
344 | ||
55e303ae A |
345 | /* |
346 | * end of vn_open code | |
347 | */ | |
348 | ||
91447636 | 349 | // starting here... error paths should call vn_close/vnode_put |
55e303ae | 350 | if ((error = falloc(p, &nfp, &indx)) != 0) { |
21362eb3 | 351 | vn_close(vp, fmode & FMASK, cred, p); |
55e303ae A |
352 | goto bad; |
353 | } | |
354 | fp = nfp; | |
355 | ||
91447636 A |
356 | fp->f_fglob->fg_flag = fmode & FMASK; |
357 | fp->f_fglob->fg_type = DTYPE_VNODE; | |
358 | fp->f_fglob->fg_ops = &vnops; | |
359 | fp->f_fglob->fg_data = (caddr_t)vp; | |
360 | ||
361 | // XXX do we really need to support this with fhopen()? | |
55e303ae A |
362 | if (fmode & (O_EXLOCK | O_SHLOCK)) { |
363 | lf.l_whence = SEEK_SET; | |
364 | lf.l_start = 0; | |
365 | lf.l_len = 0; | |
366 | if (fmode & O_EXLOCK) | |
367 | lf.l_type = F_WRLCK; | |
368 | else | |
369 | lf.l_type = F_RDLCK; | |
370 | type = F_FLOCK; | |
371 | if ((fmode & FNONBLOCK) == 0) | |
372 | type |= F_WAIT; | |
91447636 A |
373 | if ((error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_SETLK, &lf, type, &context))) { |
374 | vn_close(vp, fp->f_fglob->fg_flag, fp->f_fglob->fg_cred, p); | |
375 | fp_free(p, indx, fp); | |
55e303ae A |
376 | return (error); |
377 | } | |
91447636 | 378 | fp->f_fglob->fg_flag |= FHASLOCK; |
55e303ae A |
379 | } |
380 | ||
91447636 A |
381 | vnode_put(vp); |
382 | ||
383 | proc_fdlock(p); | |
55e303ae | 384 | *fdflags(p, indx) &= ~UF_RESERVED; |
91447636 A |
385 | fp_drop(p, indx, fp, 1); |
386 | proc_fdunlock(p); | |
387 | ||
55e303ae A |
388 | *retval = indx; |
389 | return (0); | |
390 | ||
391 | bad: | |
91447636 | 392 | vnode_put(vp); |
55e303ae A |
393 | return (error); |
394 | } | |
395 | ||
1c79356b A |
396 | /* |
397 | * Nfs server psuedo system call for the nfsd's | |
398 | * Based on the flag value it either: | |
399 | * - adds a socket to the selection list | |
400 | * - remains in the kernel as an nfsd | |
401 | * - remains in the kernel as an nfsiod | |
402 | */ | |
1c79356b | 403 | int |
91447636 | 404 | nfssvc(proc_t p, struct nfssvc_args *uap, __unused int *retval) |
1c79356b A |
405 | { |
406 | #ifndef NFS_NOSERVER | |
407 | struct nameidata nd; | |
91447636 A |
408 | mbuf_t nam; |
409 | struct user_nfsd_args user_nfsdarg; | |
1c79356b A |
410 | struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs; |
411 | struct nfsd_cargs ncd; | |
412 | struct nfsd *nfsd; | |
413 | struct nfssvc_sock *slp; | |
414 | struct nfsuid *nuidp; | |
415 | struct nfsmount *nmp; | |
55e303ae | 416 | struct timeval now; |
91447636 A |
417 | socket_t so; |
418 | struct vfs_context context; | |
419 | struct ucred temp_cred; | |
1c79356b A |
420 | #endif /* NFS_NOSERVER */ |
421 | int error; | |
422 | ||
ccc36f2f A |
423 | AUDIT_ARG(cmd, uap->flag); |
424 | ||
1c79356b A |
425 | /* |
426 | * Must be super user | |
427 | */ | |
91447636 | 428 | error = proc_suser(p); |
1c79356b A |
429 | if(error) |
430 | return (error); | |
1c79356b A |
431 | if (uap->flag & NFSSVC_BIOD) |
432 | error = nfssvc_iod(p); | |
433 | #ifdef NFS_NOSERVER | |
434 | else | |
435 | error = ENXIO; | |
436 | #else /* !NFS_NOSERVER */ | |
437 | else if (uap->flag & NFSSVC_MNTD) { | |
91447636 A |
438 | |
439 | context.vc_proc = p; | |
440 | context.vc_ucred = kauth_cred_get(); | |
441 | ||
1c79356b A |
442 | error = copyin(uap->argp, (caddr_t)&ncd, sizeof (ncd)); |
443 | if (error) | |
444 | return (error); | |
91447636 A |
445 | |
446 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, | |
447 | (proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32), | |
448 | CAST_USER_ADDR_T(ncd.ncd_dirp), &context); | |
1c79356b A |
449 | error = namei(&nd); |
450 | if (error) | |
451 | return (error); | |
91447636 A |
452 | nameidone(&nd); |
453 | ||
454 | if (vnode_isvroot(nd.ni_vp) == 0) | |
1c79356b | 455 | error = EINVAL; |
91447636 A |
456 | nmp = VFSTONFS(vnode_mount(nd.ni_vp)); |
457 | vnode_put(nd.ni_vp); | |
1c79356b A |
458 | if (error) |
459 | return (error); | |
460 | ||
55e303ae | 461 | if ((nmp->nm_state & NFSSTA_MNTD) && |
1c79356b A |
462 | (uap->flag & NFSSVC_GOTAUTH) == 0) |
463 | return (0); | |
55e303ae | 464 | nmp->nm_state |= NFSSTA_MNTD; |
91447636 | 465 | error = nfskerb_clientd(nmp, &ncd, uap->flag, uap->argp, p); |
1c79356b | 466 | } else if (uap->flag & NFSSVC_ADDSOCK) { |
91447636 A |
467 | if (IS_64BIT_PROCESS(p)) { |
468 | error = copyin(uap->argp, (caddr_t)&user_nfsdarg, sizeof(user_nfsdarg)); | |
469 | } else { | |
470 | struct nfsd_args tmp_args; | |
471 | error = copyin(uap->argp, (caddr_t)&tmp_args, sizeof(tmp_args)); | |
472 | if (error == 0) { | |
473 | user_nfsdarg.sock = tmp_args.sock; | |
474 | user_nfsdarg.name = CAST_USER_ADDR_T(tmp_args.name); | |
475 | user_nfsdarg.namelen = tmp_args.namelen; | |
476 | } | |
477 | } | |
1c79356b A |
478 | if (error) |
479 | return (error); | |
91447636 A |
480 | /* get the socket */ |
481 | error = file_socket(user_nfsdarg.sock, &so); | |
1c79356b A |
482 | if (error) |
483 | return (error); | |
91447636 A |
484 | /* Get the client address for connected sockets. */ |
485 | if (user_nfsdarg.name == USER_ADDR_NULL || user_nfsdarg.namelen == 0) { | |
486 | nam = NULL; | |
487 | } else { | |
488 | error = sockargs(&nam, user_nfsdarg.name, user_nfsdarg.namelen, MBUF_TYPE_SONAME); | |
489 | if (error) { | |
490 | /* drop the iocount file_socket() grabbed on the file descriptor */ | |
491 | file_drop(user_nfsdarg.sock); | |
1c79356b | 492 | return (error); |
91447636 | 493 | } |
1c79356b | 494 | } |
91447636 A |
495 | /* |
496 | * nfssvc_addsock() will grab a retain count on the socket | |
497 | * to keep the socket from being closed when nfsd closes its | |
498 | * file descriptor for it. | |
499 | */ | |
500 | error = nfssvc_addsock(so, nam, p); | |
501 | /* drop the iocount file_socket() grabbed on the file descriptor */ | |
502 | file_drop(user_nfsdarg.sock); | |
503 | } else if (uap->flag & NFSSVC_NFSD) { | |
1c79356b A |
504 | error = copyin(uap->argp, (caddr_t)nsd, sizeof (*nsd)); |
505 | if (error) | |
506 | return (error); | |
507 | ||
1c79356b A |
508 | if ((uap->flag & NFSSVC_AUTHIN) && ((nfsd = nsd->nsd_nfsd)) && |
509 | (nfsd->nfsd_slp->ns_flag & SLP_VALID)) { | |
510 | slp = nfsd->nfsd_slp; | |
511 | ||
512 | /* | |
513 | * First check to see if another nfsd has already | |
514 | * added this credential. | |
515 | */ | |
516 | for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first; | |
517 | nuidp != 0; nuidp = nuidp->nu_hash.le_next) { | |
91447636 | 518 | if (kauth_cred_getuid(nuidp->nu_cr) == nsd->nsd_cr.cr_uid && |
1c79356b A |
519 | (!nfsd->nfsd_nd->nd_nam2 || |
520 | netaddr_match(NU_NETFAM(nuidp), | |
521 | &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2))) | |
522 | break; | |
523 | } | |
524 | if (nuidp) { | |
21362eb3 | 525 | nfsrv_setcred(nuidp->nu_cr,nfsd->nfsd_nd->nd_cr); |
1c79356b A |
526 | nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; |
527 | } else { | |
528 | /* | |
529 | * Nope, so we will. | |
530 | */ | |
531 | if (slp->ns_numuids < nuidhash_max) { | |
532 | slp->ns_numuids++; | |
533 | nuidp = (struct nfsuid *) | |
534 | _MALLOC_ZONE(sizeof (struct nfsuid), | |
535 | M_NFSUID, M_WAITOK); | |
536 | } else | |
537 | nuidp = (struct nfsuid *)0; | |
538 | if ((slp->ns_flag & SLP_VALID) == 0) { | |
91447636 | 539 | if (nuidp) { |
55e303ae | 540 | FREE_ZONE((caddr_t)nuidp, |
1c79356b | 541 | sizeof (struct nfsuid), M_NFSUID); |
91447636 A |
542 | slp->ns_numuids--; |
543 | } | |
1c79356b A |
544 | } else { |
545 | if (nuidp == (struct nfsuid *)0) { | |
546 | nuidp = slp->ns_uidlruhead.tqh_first; | |
91447636 A |
547 | if (!nuidp) |
548 | return (ENOMEM); | |
1c79356b A |
549 | LIST_REMOVE(nuidp, nu_hash); |
550 | TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, | |
551 | nu_lru); | |
552 | if (nuidp->nu_flag & NU_NAM) | |
91447636 | 553 | mbuf_freem(nuidp->nu_nam); |
21362eb3 | 554 | kauth_cred_rele(nuidp->nu_cr); |
55e303ae | 555 | } |
1c79356b | 556 | nuidp->nu_flag = 0; |
91447636 A |
557 | |
558 | if (nsd->nsd_cr.cr_ngroups > NGROUPS) | |
559 | nsd->nsd_cr.cr_ngroups = NGROUPS; | |
560 | ||
561 | nfsrv_setcred(&nsd->nsd_cr, &temp_cred); | |
562 | nuidp->nu_cr = kauth_cred_create(&temp_cred); | |
563 | ||
564 | if (!nuidp->nu_cr) { | |
565 | FREE_ZONE(nuidp, sizeof(struct nfsuid), M_NFSUID); | |
566 | slp->ns_numuids--; | |
567 | return (ENOMEM); | |
568 | } | |
1c79356b | 569 | nuidp->nu_timestamp = nsd->nsd_timestamp; |
55e303ae A |
570 | microtime(&now); |
571 | nuidp->nu_expire = now.tv_sec + nsd->nsd_ttl; | |
1c79356b A |
572 | /* |
573 | * and save the session key in nu_key. | |
574 | */ | |
575 | bcopy(nsd->nsd_key, nuidp->nu_key, | |
576 | sizeof (nsd->nsd_key)); | |
577 | if (nfsd->nfsd_nd->nd_nam2) { | |
578 | struct sockaddr_in *saddr; | |
579 | ||
91447636 | 580 | saddr = mbuf_data(nfsd->nfsd_nd->nd_nam2); |
1c79356b A |
581 | switch (saddr->sin_family) { |
582 | case AF_INET: | |
583 | nuidp->nu_flag |= NU_INETADDR; | |
584 | nuidp->nu_inetaddr = | |
585 | saddr->sin_addr.s_addr; | |
586 | break; | |
587 | case AF_ISO: | |
588 | default: | |
589 | nuidp->nu_flag |= NU_NAM; | |
91447636 A |
590 | error = mbuf_copym(nfsd->nfsd_nd->nd_nam2, 0, |
591 | MBUF_COPYALL, MBUF_WAITOK, | |
592 | &nuidp->nu_nam); | |
593 | if (error) { | |
21362eb3 | 594 | kauth_cred_rele(nuidp->nu_cr); |
91447636 A |
595 | FREE_ZONE(nuidp, sizeof(struct nfsuid), M_NFSUID); |
596 | slp->ns_numuids--; | |
597 | return (error); | |
598 | } | |
1c79356b A |
599 | break; |
600 | }; | |
601 | } | |
602 | TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp, | |
603 | nu_lru); | |
604 | LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid), | |
605 | nuidp, nu_hash); | |
21362eb3 A |
606 | nfsrv_setcred(nuidp->nu_cr, |
607 | nfsd->nfsd_nd->nd_cr); | |
1c79356b A |
608 | nfsd->nfsd_nd->nd_flag |= ND_KERBFULL; |
609 | } | |
610 | } | |
611 | } | |
612 | if ((uap->flag & NFSSVC_AUTHINFAIL) && (nfsd = nsd->nsd_nfsd)) | |
613 | nfsd->nfsd_flag |= NFSD_AUTHFAIL; | |
614 | error = nfssvc_nfsd(nsd, uap->argp, p); | |
91447636 A |
615 | } else if (uap->flag & NFSSVC_EXPORT) { |
616 | error = nfssvc_export(uap->argp, p); | |
617 | } else { | |
618 | error = EINVAL; | |
1c79356b A |
619 | } |
620 | #endif /* NFS_NOSERVER */ | |
621 | if (error == EINTR || error == ERESTART) | |
622 | error = 0; | |
623 | return (error); | |
624 | } | |
625 | ||
91447636 A |
626 | /* |
627 | * NFSKERB client helper daemon. | |
628 | * Gets authorization strings for "kerb" mounts. | |
629 | */ | |
630 | static int | |
631 | nfskerb_clientd( | |
632 | struct nfsmount *nmp, | |
633 | struct nfsd_cargs *ncd, | |
634 | int flag, | |
635 | user_addr_t argp, | |
636 | proc_t p) | |
637 | { | |
638 | struct nfsuid *nuidp, *nnuidp; | |
639 | int error = 0; | |
640 | struct nfsreq *rp; | |
641 | struct timeval now; | |
642 | ||
643 | /* | |
644 | * First initialize some variables | |
645 | */ | |
646 | microtime(&now); | |
647 | ||
648 | /* | |
649 | * If an authorization string is being passed in, get it. | |
650 | */ | |
651 | if ((flag & NFSSVC_GOTAUTH) && (nmp->nm_state & NFSSTA_MOUNTED) && | |
652 | ((nmp->nm_state & NFSSTA_WAITAUTH) == 0)) { | |
653 | if (nmp->nm_state & NFSSTA_HASAUTH) | |
654 | panic("cld kerb"); | |
655 | if ((flag & NFSSVC_AUTHINFAIL) == 0) { | |
656 | if (ncd->ncd_authlen <= nmp->nm_authlen && | |
657 | ncd->ncd_verflen <= nmp->nm_verflen && | |
658 | !copyin(CAST_USER_ADDR_T(ncd->ncd_authstr),nmp->nm_authstr,ncd->ncd_authlen)&& | |
659 | !copyin(CAST_USER_ADDR_T(ncd->ncd_verfstr),nmp->nm_verfstr,ncd->ncd_verflen)){ | |
660 | nmp->nm_authtype = ncd->ncd_authtype; | |
661 | nmp->nm_authlen = ncd->ncd_authlen; | |
662 | nmp->nm_verflen = ncd->ncd_verflen; | |
663 | #if NFSKERB | |
664 | nmp->nm_key = ncd->ncd_key; | |
665 | #endif | |
666 | } else | |
667 | nmp->nm_state |= NFSSTA_AUTHERR; | |
668 | } else | |
669 | nmp->nm_state |= NFSSTA_AUTHERR; | |
670 | nmp->nm_state |= NFSSTA_HASAUTH; | |
671 | wakeup((caddr_t)&nmp->nm_authlen); | |
672 | } else { | |
673 | nmp->nm_state |= NFSSTA_WAITAUTH; | |
674 | } | |
675 | ||
676 | /* | |
677 | * Loop every second updating queue until there is a termination sig. | |
678 | */ | |
679 | while (nmp->nm_state & NFSSTA_MOUNTED) { | |
680 | /* Get an authorization string, if required. */ | |
681 | if ((nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_HASAUTH)) == 0) { | |
682 | ncd->ncd_authuid = nmp->nm_authuid; | |
683 | if (copyout((caddr_t)ncd, argp, sizeof (struct nfsd_cargs))) | |
684 | nmp->nm_state |= NFSSTA_WAITAUTH; | |
685 | else | |
686 | return (ENEEDAUTH); | |
687 | } | |
688 | /* Wait a bit (no pun) and do it again. */ | |
689 | if ((nmp->nm_state & NFSSTA_MOUNTED) && | |
690 | (nmp->nm_state & (NFSSTA_WAITAUTH | NFSSTA_HASAUTH))) { | |
691 | error = tsleep((caddr_t)&nmp->nm_authstr, PSOCK | PCATCH, | |
692 | "nfskrbtimr", hz / 3); | |
693 | if (error == EINTR || error == ERESTART) | |
21362eb3 | 694 | dounmount(nmp->nm_mountp, 0, p); |
91447636 A |
695 | } |
696 | } | |
697 | ||
698 | /* | |
699 | * Finally, we can free up the mount structure. | |
700 | */ | |
701 | for (nuidp = nmp->nm_uidlruhead.tqh_first; nuidp != 0; nuidp = nnuidp) { | |
702 | nnuidp = nuidp->nu_lru.tqe_next; | |
703 | LIST_REMOVE(nuidp, nu_hash); | |
704 | TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); | |
21362eb3 | 705 | kauth_cred_rele(nuidp->nu_cr); |
91447636 A |
706 | FREE_ZONE((caddr_t)nuidp, sizeof (struct nfsuid), M_NFSUID); |
707 | } | |
708 | /* | |
709 | * Loop through outstanding request list and remove dangling | |
710 | * references to defunct nfsmount struct | |
711 | */ | |
712 | for (rp = nfs_reqq.tqh_first; rp; rp = rp->r_chain.tqe_next) | |
713 | if (rp->r_nmp == nmp) | |
714 | rp->r_nmp = (struct nfsmount *)0; | |
715 | /* Need to wake up any rcvlock waiters so they notice the unmount. */ | |
716 | if (nmp->nm_state & NFSSTA_WANTRCV) { | |
717 | nmp->nm_state &= ~NFSSTA_WANTRCV; | |
718 | wakeup(&nmp->nm_state); | |
719 | } | |
720 | FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT); | |
721 | if (error == EWOULDBLOCK) | |
722 | error = 0; | |
723 | return (error); | |
724 | } | |
725 | ||
1c79356b A |
726 | #ifndef NFS_NOSERVER |
727 | /* | |
728 | * Adds a socket to the list for servicing by nfsds. | |
729 | */ | |
730 | static int | |
91447636 A |
731 | nfssvc_addsock( |
732 | socket_t so, | |
733 | mbuf_t mynam, | |
734 | __unused proc_t p) | |
1c79356b | 735 | { |
91447636 A |
736 | int siz; |
737 | struct nfssvc_sock *slp; | |
738 | struct nfssvc_sock *tslp = NULL; | |
739 | int error, sodomain, sotype, soprotocol, on = 1; | |
740 | struct timeval timeo; | |
741 | ||
742 | /* make sure mbuf constants are set up */ | |
743 | if (!nfs_mbuf_mlen) | |
744 | nfs_mbuf_init(); | |
745 | ||
746 | sock_gettype(so, &sodomain, &sotype, &soprotocol); | |
747 | ||
1c79356b A |
748 | /* |
749 | * Add it to the list, as required. | |
750 | */ | |
91447636 | 751 | if (soprotocol == IPPROTO_UDP) { |
1c79356b | 752 | tslp = nfs_udpsock; |
91447636 A |
753 | if (!tslp || (tslp->ns_flag & SLP_VALID)) { |
754 | mbuf_freem(mynam); | |
1c79356b A |
755 | return (EPERM); |
756 | } | |
757 | #if ISO | |
91447636 | 758 | } else if (soprotocol == ISOPROTO_CLTP) { |
1c79356b | 759 | tslp = nfs_cltpsock; |
91447636 A |
760 | if (!tslp || (tslp->ns_flag & SLP_VALID)) { |
761 | mbuf_freem(mynam); | |
1c79356b A |
762 | return (EPERM); |
763 | } | |
764 | #endif /* ISO */ | |
765 | } | |
55e303ae A |
766 | /* reserve buffer space for 2 maximally-sized packets */ |
767 | siz = NFS_MAXPACKET; | |
91447636 | 768 | if (sotype == SOCK_STREAM) |
55e303ae A |
769 | siz += sizeof (u_long); |
770 | siz *= 2; | |
771 | if (siz > NFS_MAXSOCKBUF) | |
772 | siz = NFS_MAXSOCKBUF; | |
91447636 A |
773 | if ((error = sock_setsockopt(so, SOL_SOCKET, SO_SNDBUF, &siz, sizeof(siz))) || |
774 | (error = sock_setsockopt(so, SOL_SOCKET, SO_RCVBUF, &siz, sizeof(siz)))) { | |
775 | mbuf_freem(mynam); | |
1c79356b A |
776 | return (error); |
777 | } | |
778 | ||
779 | /* | |
780 | * Set protocol specific options { for now TCP only } and | |
781 | * reserve some space. For datagram sockets, this can get called | |
782 | * repeatedly for the same socket, but that isn't harmful. | |
783 | */ | |
91447636 A |
784 | if (sotype == SOCK_STREAM) { |
785 | sock_setsockopt(so, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); | |
1c79356b | 786 | } |
91447636 A |
787 | if (sodomain == AF_INET && soprotocol == IPPROTO_TCP) { |
788 | sock_setsockopt(so, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); | |
1c79356b A |
789 | } |
790 | ||
91447636 A |
791 | sock_nointerrupt(so, 0); |
792 | ||
793 | timeo.tv_usec = 0; | |
794 | timeo.tv_sec = 0; | |
795 | error = sock_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)); | |
796 | error = sock_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo)); | |
797 | ||
798 | if (tslp) { | |
1c79356b | 799 | slp = tslp; |
91447636 A |
800 | lck_mtx_lock(nfsd_mutex); |
801 | } else { | |
1c79356b A |
802 | MALLOC(slp, struct nfssvc_sock *, sizeof(struct nfssvc_sock), |
803 | M_NFSSVC, M_WAITOK); | |
91447636 A |
804 | if (!slp) { |
805 | mbuf_freem(mynam); | |
806 | return (ENOMEM); | |
807 | } | |
1c79356b | 808 | bzero((caddr_t)slp, sizeof (struct nfssvc_sock)); |
91447636 A |
809 | lck_rw_init(&slp->ns_rwlock, nfs_slp_rwlock_group, nfs_slp_lock_attr); |
810 | lck_mtx_init(&slp->ns_wgmutex, nfs_slp_mutex_group, nfs_slp_lock_attr); | |
1c79356b | 811 | TAILQ_INIT(&slp->ns_uidlruhead); |
91447636 | 812 | lck_mtx_lock(nfsd_mutex); |
1c79356b A |
813 | TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain); |
814 | } | |
91447636 A |
815 | |
816 | sock_retain(so); /* grab a retain count on the socket */ | |
1c79356b | 817 | slp->ns_so = so; |
91447636 | 818 | slp->ns_sotype = sotype; |
1c79356b | 819 | slp->ns_nam = mynam; |
91447636 A |
820 | |
821 | socket_lock(so, 1); | |
1c79356b A |
822 | so->so_upcallarg = (caddr_t)slp; |
823 | so->so_upcall = nfsrv_rcv; | |
824 | so->so_rcv.sb_flags |= SB_UPCALL; /* required for freebsd merge */ | |
91447636 A |
825 | socket_unlock(so, 1); |
826 | ||
827 | slp->ns_flag = SLP_VALID | SLP_NEEDQ; | |
828 | ||
1c79356b | 829 | nfsrv_wakenfsd(slp); |
91447636 A |
830 | lck_mtx_unlock(nfsd_mutex); |
831 | ||
1c79356b A |
832 | return (0); |
833 | } | |
834 | ||
835 | /* | |
836 | * Called by nfssvc() for nfsds. Just loops around servicing rpc requests | |
837 | * until it is killed by a signal. | |
838 | */ | |
839 | static int | |
840 | nfssvc_nfsd(nsd, argp, p) | |
841 | struct nfsd_srvargs *nsd; | |
91447636 A |
842 | user_addr_t argp; |
843 | proc_t p; | |
1c79356b | 844 | { |
91447636 A |
845 | mbuf_t m, mreq; |
846 | struct nfssvc_sock *slp; | |
1c79356b A |
847 | struct nfsd *nfsd = nsd->nsd_nfsd; |
848 | struct nfsrv_descript *nd = NULL; | |
91447636 A |
849 | int error = 0, cacherep, writes_todo; |
850 | int siz, procrastinate; | |
1c79356b | 851 | u_quad_t cur_usec; |
55e303ae | 852 | struct timeval now; |
91447636 | 853 | boolean_t funnel_state; |
1c79356b A |
854 | |
855 | #ifndef nolint | |
856 | cacherep = RC_DOIT; | |
857 | writes_todo = 0; | |
858 | #endif | |
1c79356b A |
859 | if (nfsd == (struct nfsd *)0) { |
860 | MALLOC(nfsd, struct nfsd *, sizeof(struct nfsd), M_NFSD, M_WAITOK); | |
91447636 A |
861 | if (!nfsd) |
862 | return (ENOMEM); | |
1c79356b A |
863 | nsd->nsd_nfsd = nfsd; |
864 | bzero((caddr_t)nfsd, sizeof (struct nfsd)); | |
865 | nfsd->nfsd_procp = p; | |
91447636 | 866 | lck_mtx_lock(nfsd_mutex); |
1c79356b A |
867 | TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain); |
868 | nfs_numnfsd++; | |
91447636 | 869 | lck_mtx_unlock(nfsd_mutex); |
1c79356b | 870 | } |
91447636 A |
871 | |
872 | funnel_state = thread_funnel_set(kernel_flock, FALSE); | |
873 | ||
1c79356b A |
874 | /* |
875 | * Loop getting rpc requests until SIGKILL. | |
876 | */ | |
877 | for (;;) { | |
878 | if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) { | |
91447636 A |
879 | lck_mtx_lock(nfsd_mutex); |
880 | while ((nfsd->nfsd_slp == NULL) && !(nfsd_head_flag & NFSD_CHECKSLP)) { | |
1c79356b A |
881 | nfsd->nfsd_flag |= NFSD_WAITING; |
882 | nfsd_waiting++; | |
91447636 | 883 | error = msleep(nfsd, nfsd_mutex, PSOCK | PCATCH, "nfsd", 0); |
1c79356b | 884 | nfsd_waiting--; |
91447636 A |
885 | if (error) { |
886 | lck_mtx_unlock(nfsd_mutex); | |
1c79356b | 887 | goto done; |
91447636 | 888 | } |
1c79356b | 889 | } |
91447636 A |
890 | if ((nfsd->nfsd_slp == NULL) && (nfsd_head_flag & NFSD_CHECKSLP)) { |
891 | TAILQ_FOREACH(slp, &nfssvc_sockhead, ns_chain) { | |
892 | lck_rw_lock_shared(&slp->ns_rwlock); | |
1c79356b A |
893 | if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) |
894 | == (SLP_VALID | SLP_DOREC)) { | |
91447636 A |
895 | if (lck_rw_lock_shared_to_exclusive(&slp->ns_rwlock)) { |
896 | /* upgrade failed and we lost the lock; take exclusive and recheck */ | |
897 | lck_rw_lock_exclusive(&slp->ns_rwlock); | |
898 | if ((slp->ns_flag & (SLP_VALID | SLP_DOREC)) | |
899 | != (SLP_VALID | SLP_DOREC)) { | |
900 | /* flags no longer set, so skip this socket */ | |
901 | lck_rw_done(&slp->ns_rwlock); | |
902 | continue; | |
903 | } | |
904 | } | |
1c79356b A |
905 | slp->ns_flag &= ~SLP_DOREC; |
906 | slp->ns_sref++; | |
907 | nfsd->nfsd_slp = slp; | |
91447636 | 908 | lck_rw_done(&slp->ns_rwlock); |
1c79356b A |
909 | break; |
910 | } | |
91447636 | 911 | lck_rw_done(&slp->ns_rwlock); |
1c79356b A |
912 | } |
913 | if (slp == 0) | |
914 | nfsd_head_flag &= ~NFSD_CHECKSLP; | |
915 | } | |
91447636 A |
916 | lck_mtx_unlock(nfsd_mutex); |
917 | if ((slp = nfsd->nfsd_slp) == NULL) | |
1c79356b | 918 | continue; |
91447636 | 919 | lck_rw_lock_exclusive(&slp->ns_rwlock); |
1c79356b | 920 | if (slp->ns_flag & SLP_VALID) { |
743b1565 | 921 | if ((slp->ns_flag & (SLP_NEEDQ|SLP_DISCONN)) == SLP_NEEDQ) { |
91447636 A |
922 | slp->ns_flag &= ~SLP_NEEDQ; |
923 | nfsrv_rcv_locked(slp->ns_so, slp, MBUF_WAITOK); | |
924 | } | |
743b1565 A |
925 | if (slp->ns_flag & SLP_DISCONN) |
926 | nfsrv_zapsock(slp); | |
1c79356b | 927 | error = nfsrv_dorec(slp, nfsd, &nd); |
55e303ae A |
928 | microuptime(&now); |
929 | cur_usec = (u_quad_t)now.tv_sec * 1000000 + | |
930 | (u_quad_t)now.tv_usec; | |
91447636 | 931 | if (error && slp->ns_wgtime && (slp->ns_wgtime <= cur_usec)) { |
1c79356b A |
932 | error = 0; |
933 | cacherep = RC_DOIT; | |
934 | writes_todo = 1; | |
935 | } else | |
936 | writes_todo = 0; | |
937 | nfsd->nfsd_flag |= NFSD_REQINPROG; | |
938 | } | |
91447636 | 939 | lck_rw_done(&slp->ns_rwlock); |
1c79356b A |
940 | } else { |
941 | error = 0; | |
942 | slp = nfsd->nfsd_slp; | |
943 | } | |
944 | if (error || (slp->ns_flag & SLP_VALID) == 0) { | |
945 | if (nd) { | |
55e303ae | 946 | if (nd->nd_nam2) |
91447636 | 947 | mbuf_freem(nd->nd_nam2); |
21362eb3 A |
948 | if (nd->nd_cr) |
949 | kauth_cred_rele(nd->nd_cr); | |
55e303ae | 950 | FREE_ZONE((caddr_t)nd, |
1c79356b A |
951 | sizeof *nd, M_NFSRVDESC); |
952 | nd = NULL; | |
953 | } | |
91447636 | 954 | nfsd->nfsd_slp = NULL; |
1c79356b A |
955 | nfsd->nfsd_flag &= ~NFSD_REQINPROG; |
956 | nfsrv_slpderef(slp); | |
957 | continue; | |
958 | } | |
1c79356b | 959 | if (nd) { |
55e303ae | 960 | microuptime(&nd->nd_starttime); |
1c79356b A |
961 | if (nd->nd_nam2) |
962 | nd->nd_nam = nd->nd_nam2; | |
963 | else | |
964 | nd->nd_nam = slp->ns_nam; | |
965 | ||
966 | /* | |
967 | * Check to see if authorization is needed. | |
968 | */ | |
969 | if (nfsd->nfsd_flag & NFSD_NEEDAUTH) { | |
970 | nfsd->nfsd_flag &= ~NFSD_NEEDAUTH; | |
91447636 | 971 | nsd->nsd_haddr = ((struct sockaddr_in *)mbuf_data(nd->nd_nam))->sin_addr.s_addr; |
1c79356b A |
972 | nsd->nsd_authlen = nfsd->nfsd_authlen; |
973 | nsd->nsd_verflen = nfsd->nfsd_verflen; | |
91447636 | 974 | if (!copyout(nfsd->nfsd_authstr,CAST_USER_ADDR_T(nsd->nsd_authstr), |
1c79356b | 975 | nfsd->nfsd_authlen) && |
91447636 | 976 | !copyout(nfsd->nfsd_verfstr, CAST_USER_ADDR_T(nsd->nsd_verfstr), |
1c79356b | 977 | nfsd->nfsd_verflen) && |
91447636 A |
978 | !copyout((caddr_t)nsd, argp, sizeof (*nsd))) { |
979 | thread_funnel_set(kernel_flock, funnel_state); | |
1c79356b | 980 | return (ENEEDAUTH); |
91447636 | 981 | } |
1c79356b A |
982 | cacherep = RC_DROPIT; |
983 | } else | |
984 | cacherep = nfsrv_getcache(nd, slp, &mreq); | |
985 | ||
91447636 | 986 | if (nfsd->nfsd_flag & NFSD_AUTHFAIL) { |
1c79356b A |
987 | nfsd->nfsd_flag &= ~NFSD_AUTHFAIL; |
988 | nd->nd_procnum = NFSPROC_NOOP; | |
989 | nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); | |
990 | cacherep = RC_DOIT; | |
991 | } else if (nfs_privport) { | |
992 | /* Check if source port is privileged */ | |
993 | u_short port; | |
91447636 | 994 | struct sockaddr *nam = mbuf_data(nd->nd_nam); |
1c79356b A |
995 | struct sockaddr_in *sin; |
996 | ||
997 | sin = (struct sockaddr_in *)nam; | |
998 | port = ntohs(sin->sin_port); | |
999 | if (port >= IPPORT_RESERVED && | |
1000 | nd->nd_procnum != NFSPROC_NULL) { | |
91447636 | 1001 | char strbuf[MAX_IPv4_STR_LEN]; |
1c79356b A |
1002 | nd->nd_procnum = NFSPROC_NOOP; |
1003 | nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); | |
1004 | cacherep = RC_DOIT; | |
1005 | printf("NFS request from unprivileged port (%s:%d)\n", | |
91447636 A |
1006 | inet_ntop(AF_INET, &sin->sin_addr, strbuf, sizeof(strbuf)), |
1007 | port); | |
1c79356b A |
1008 | } |
1009 | } | |
1010 | ||
1011 | } | |
1012 | ||
1013 | /* | |
1014 | * Loop to get all the write rpc relies that have been | |
1015 | * gathered together. | |
1016 | */ | |
1017 | do { | |
1018 | switch (cacherep) { | |
1019 | case RC_DOIT: | |
1020 | if (nd && (nd->nd_flag & ND_NFSV3)) | |
1021 | procrastinate = nfsrvw_procrastinate_v3; | |
1022 | else | |
1023 | procrastinate = nfsrvw_procrastinate; | |
91447636 A |
1024 | lck_rw_lock_shared(&nfs_export_rwlock); |
1025 | if (writes_todo || ((nd->nd_procnum == NFSPROC_WRITE) && (procrastinate > 0))) | |
1026 | error = nfsrv_writegather(&nd, slp, nfsd->nfsd_procp, &mreq); | |
1c79356b | 1027 | else |
91447636 A |
1028 | error = (*(nfsrv3_procs[nd->nd_procnum]))(nd, slp, nfsd->nfsd_procp, &mreq); |
1029 | lck_rw_done(&nfs_export_rwlock); | |
1c79356b A |
1030 | if (mreq == NULL) |
1031 | break; | |
1032 | if (error) { | |
91447636 | 1033 | OSAddAtomic(1, (SInt32*)&nfsstats.srv_errs); |
1c79356b | 1034 | nfsrv_updatecache(nd, FALSE, mreq); |
55e303ae | 1035 | if (nd->nd_nam2) { |
91447636 | 1036 | mbuf_freem(nd->nd_nam2); |
55e303ae A |
1037 | nd->nd_nam2 = NULL; |
1038 | } | |
1c79356b A |
1039 | break; |
1040 | } | |
91447636 | 1041 | OSAddAtomic(1, (SInt32*)&nfsstats.srvrpccnt[nd->nd_procnum]); |
1c79356b | 1042 | nfsrv_updatecache(nd, TRUE, mreq); |
91447636 | 1043 | nd->nd_mrep = NULL; |
1c79356b A |
1044 | case RC_REPLY: |
1045 | m = mreq; | |
1046 | siz = 0; | |
1047 | while (m) { | |
91447636 A |
1048 | siz += mbuf_len(m); |
1049 | m = mbuf_next(m); | |
1c79356b A |
1050 | } |
1051 | if (siz <= 0 || siz > NFS_MAXPACKET) { | |
1052 | printf("mbuf siz=%d\n",siz); | |
1053 | panic("Bad nfs svc reply"); | |
1054 | } | |
1055 | m = mreq; | |
91447636 A |
1056 | mbuf_pkthdr_setlen(m, siz); |
1057 | error = mbuf_pkthdr_setrcvif(m, NULL); | |
1058 | if (error) | |
1059 | panic("nfsd setrcvif failed: %d", error); | |
1c79356b A |
1060 | /* |
1061 | * For stream protocols, prepend a Sun RPC | |
1062 | * Record Mark. | |
1063 | */ | |
91447636 A |
1064 | if (slp->ns_sotype == SOCK_STREAM) { |
1065 | error = mbuf_prepend(&m, NFSX_UNSIGNED, MBUF_WAITOK); | |
1066 | if (!error) | |
1067 | *(u_long*)mbuf_data(m) = htonl(0x80000000 | siz); | |
1c79356b | 1068 | } |
91447636 A |
1069 | if (!error) { |
1070 | if (slp->ns_flag & SLP_VALID) { | |
1071 | error = nfs_send(slp->ns_so, nd->nd_nam2, m, NULL); | |
1072 | } else { | |
1073 | error = EPIPE; | |
1074 | mbuf_freem(m); | |
1075 | } | |
1076 | } else { | |
1077 | mbuf_freem(m); | |
1c79356b | 1078 | } |
55e303ae | 1079 | mreq = NULL; |
1c79356b | 1080 | if (nfsrtton) |
91447636 | 1081 | nfsd_rt(slp->ns_sotype, nd, cacherep); |
55e303ae | 1082 | if (nd->nd_nam2) { |
91447636 | 1083 | mbuf_freem(nd->nd_nam2); |
55e303ae A |
1084 | nd->nd_nam2 = NULL; |
1085 | } | |
1086 | if (nd->nd_mrep) { | |
91447636 | 1087 | mbuf_freem(nd->nd_mrep); |
55e303ae A |
1088 | nd->nd_mrep = NULL; |
1089 | } | |
91447636 A |
1090 | if (error == EPIPE) { |
1091 | lck_rw_lock_exclusive(&slp->ns_rwlock); | |
1c79356b | 1092 | nfsrv_zapsock(slp); |
91447636 A |
1093 | lck_rw_done(&slp->ns_rwlock); |
1094 | } | |
1c79356b | 1095 | if (error == EINTR || error == ERESTART) { |
21362eb3 A |
1096 | if (nd->nd_cr) |
1097 | kauth_cred_rele(nd->nd_cr); | |
91447636 | 1098 | FREE_ZONE((caddr_t)nd, sizeof *nd, M_NFSRVDESC); |
1c79356b | 1099 | nfsrv_slpderef(slp); |
1c79356b A |
1100 | goto done; |
1101 | } | |
1102 | break; | |
1103 | case RC_DROPIT: | |
1104 | if (nfsrtton) | |
91447636 A |
1105 | nfsd_rt(slp->ns_sotype, nd, cacherep); |
1106 | mbuf_freem(nd->nd_mrep); | |
1107 | mbuf_freem(nd->nd_nam2); | |
55e303ae | 1108 | nd->nd_mrep = nd->nd_nam2 = NULL; |
1c79356b A |
1109 | break; |
1110 | }; | |
1111 | if (nd) { | |
55e303ae | 1112 | if (nd->nd_mrep) |
91447636 | 1113 | mbuf_freem(nd->nd_mrep); |
55e303ae | 1114 | if (nd->nd_nam2) |
91447636 | 1115 | mbuf_freem(nd->nd_nam2); |
21362eb3 A |
1116 | if (nd->nd_cr) |
1117 | kauth_cred_rele(nd->nd_cr); | |
1c79356b A |
1118 | FREE_ZONE((caddr_t)nd, sizeof *nd, M_NFSRVDESC); |
1119 | nd = NULL; | |
1120 | } | |
1121 | ||
1122 | /* | |
1123 | * Check to see if there are outstanding writes that | |
1124 | * need to be serviced. | |
1125 | */ | |
55e303ae A |
1126 | microuptime(&now); |
1127 | cur_usec = (u_quad_t)now.tv_sec * 1000000 + | |
1128 | (u_quad_t)now.tv_usec; | |
91447636 | 1129 | if (slp->ns_wgtime && (slp->ns_wgtime <= cur_usec)) { |
1c79356b A |
1130 | cacherep = RC_DOIT; |
1131 | writes_todo = 1; | |
91447636 | 1132 | } else { |
1c79356b | 1133 | writes_todo = 0; |
91447636 | 1134 | } |
1c79356b | 1135 | } while (writes_todo); |
91447636 | 1136 | lck_rw_lock_exclusive(&slp->ns_rwlock); |
1c79356b | 1137 | if (nfsrv_dorec(slp, nfsd, &nd)) { |
91447636 | 1138 | lck_rw_done(&slp->ns_rwlock); |
1c79356b A |
1139 | nfsd->nfsd_flag &= ~NFSD_REQINPROG; |
1140 | nfsd->nfsd_slp = NULL; | |
1141 | nfsrv_slpderef(slp); | |
91447636 A |
1142 | } else { |
1143 | lck_rw_done(&slp->ns_rwlock); | |
1144 | } | |
1c79356b A |
1145 | } |
1146 | done: | |
91447636 A |
1147 | thread_funnel_set(kernel_flock, funnel_state); |
1148 | lck_mtx_lock(nfsd_mutex); | |
1c79356b | 1149 | TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain); |
91447636 | 1150 | FREE(nfsd, M_NFSD); |
1c79356b A |
1151 | nsd->nsd_nfsd = (struct nfsd *)0; |
1152 | if (--nfs_numnfsd == 0) | |
1153 | nfsrv_init(TRUE); /* Reinitialize everything */ | |
91447636 | 1154 | lck_mtx_unlock(nfsd_mutex); |
1c79356b A |
1155 | return (error); |
1156 | } | |
91447636 A |
1157 | |
1158 | static int | |
1159 | nfssvc_export(user_addr_t argp, proc_t p) | |
1160 | { | |
1161 | int error = 0, is_64bit; | |
1162 | struct user_nfs_export_args unxa; | |
1163 | struct vfs_context context; | |
1164 | ||
1165 | context.vc_proc = p; | |
1166 | context.vc_ucred = kauth_cred_get(); | |
1167 | is_64bit = IS_64BIT_PROCESS(p); | |
1168 | ||
1169 | /* copy in pointers to path and export args */ | |
1170 | if (is_64bit) { | |
1171 | error = copyin(argp, (caddr_t)&unxa, sizeof(unxa)); | |
1172 | } else { | |
1173 | struct nfs_export_args tnxa; | |
1174 | error = copyin(argp, (caddr_t)&tnxa, sizeof(tnxa)); | |
1175 | if (error == 0) { | |
1176 | /* munge into LP64 version of nfs_export_args structure */ | |
1177 | unxa.nxa_fsid = tnxa.nxa_fsid; | |
1178 | unxa.nxa_expid = tnxa.nxa_expid; | |
1179 | unxa.nxa_fspath = CAST_USER_ADDR_T(tnxa.nxa_fspath); | |
1180 | unxa.nxa_exppath = CAST_USER_ADDR_T(tnxa.nxa_exppath); | |
1181 | unxa.nxa_flags = tnxa.nxa_flags; | |
1182 | unxa.nxa_netcount = tnxa.nxa_netcount; | |
1183 | unxa.nxa_nets = CAST_USER_ADDR_T(tnxa.nxa_nets); | |
1184 | } | |
1185 | } | |
1186 | if (error) | |
1187 | return (error); | |
1188 | ||
1189 | error = nfsrv_export(&unxa, &context); | |
1190 | ||
1191 | return (error); | |
1192 | } | |
1193 | ||
1c79356b A |
1194 | #endif /* NFS_NOSERVER */ |
1195 | ||
1196 | int nfs_defect = 0; | |
1197 | /* XXX CSM 11/25/97 Upgrade sysctl.h someday */ | |
1198 | #ifdef notyet | |
1199 | SYSCTL_INT(_vfs_nfs, OID_AUTO, defect, CTLFLAG_RW, &nfs_defect, 0, ""); | |
1200 | #endif | |
1201 | ||
55e303ae | 1202 | int |
91447636 | 1203 | nfsclnt(proc_t p, struct nfsclnt_args *uap, __unused int *retval) |
55e303ae A |
1204 | { |
1205 | struct lockd_ans la; | |
1206 | int error; | |
1207 | ||
1208 | if (uap->flag == NFSCLNT_LOCKDWAIT) { | |
1209 | return (nfslockdwait(p)); | |
1210 | } | |
1211 | if (uap->flag == NFSCLNT_LOCKDANS) { | |
1212 | error = copyin(uap->argp, &la, sizeof(la)); | |
1213 | return (error != 0 ? error : nfslockdans(p, &la)); | |
1214 | } | |
1215 | if (uap->flag == NFSCLNT_LOCKDFD) | |
91447636 | 1216 | return (nfslockdfd(p, CAST_DOWN(int, uap->argp))); |
55e303ae A |
1217 | return EINVAL; |
1218 | } | |
1219 | ||
1220 | ||
1c79356b A |
1221 | static int nfssvc_iod_continue(int); |
1222 | ||
1223 | /* | |
1224 | * Asynchronous I/O daemons for client nfs. | |
1225 | * They do read-ahead and write-behind operations on the block I/O cache. | |
1226 | * Never returns unless it fails or gets killed. | |
1227 | */ | |
1228 | static int | |
91447636 | 1229 | nfssvc_iod(__unused proc_t p) |
1c79356b | 1230 | { |
1c79356b | 1231 | register int i, myiod; |
1c79356b A |
1232 | struct uthread *ut; |
1233 | ||
1234 | /* | |
1235 | * Assign my position or return error if too many already running | |
1236 | */ | |
1237 | myiod = -1; | |
1238 | for (i = 0; i < NFS_MAXASYNCDAEMON; i++) | |
1239 | if (nfs_asyncdaemon[i] == 0) { | |
1240 | nfs_asyncdaemon[i]++; | |
1241 | myiod = i; | |
1242 | break; | |
1243 | } | |
1244 | if (myiod == -1) | |
1245 | return (EBUSY); | |
1246 | nfs_numasync++; | |
1247 | ||
55e303ae | 1248 | /* stuff myiod into uthread to get off local stack for continuation */ |
1c79356b | 1249 | |
91447636 | 1250 | ut = (struct uthread *)get_bsdthread_info(current_thread()); |
1c79356b A |
1251 | ut->uu_state.uu_nfs_myiod = myiod; /* squirrel away for continuation */ |
1252 | ||
1253 | nfssvc_iod_continue(0); | |
1254 | /* NOTREACHED */ | |
91447636 | 1255 | return (0); |
1c79356b A |
1256 | } |
1257 | ||
1258 | /* | |
1259 | * Continuation for Asynchronous I/O daemons for client nfs. | |
1260 | */ | |
1261 | static int | |
91447636 | 1262 | nfssvc_iod_continue(int error) |
1c79356b | 1263 | { |
55e303ae | 1264 | register struct nfsbuf *bp; |
1c79356b A |
1265 | register int i, myiod; |
1266 | struct nfsmount *nmp; | |
1267 | struct uthread *ut; | |
91447636 | 1268 | proc_t p; |
8f6c56a5 | 1269 | int exiterror = 0; |
1c79356b A |
1270 | |
1271 | /* | |
1272 | * real myiod is stored in uthread, recover it | |
1273 | */ | |
91447636 | 1274 | ut = (struct uthread *)get_bsdthread_info(current_thread()); |
1c79356b | 1275 | myiod = ut->uu_state.uu_nfs_myiod; |
91447636 | 1276 | p = current_proc(); // XXX |
1c79356b A |
1277 | |
1278 | /* | |
1279 | * Just loop around doin our stuff until SIGKILL | |
55e303ae | 1280 | * - actually we don't loop with continuations... |
1c79356b | 1281 | */ |
91447636 | 1282 | lck_mtx_lock(nfs_iod_mutex); |
1c79356b A |
1283 | for (;;) { |
1284 | while (((nmp = nfs_iodmount[myiod]) == NULL | |
1285 | || nmp->nm_bufq.tqh_first == NULL) | |
55e303ae | 1286 | && error == 0 && nfs_ioddelwri == 0) { |
1c79356b A |
1287 | if (nmp) |
1288 | nmp->nm_bufqiods--; | |
91447636 | 1289 | nfs_iodwant[myiod] = p; // XXX this doesn't need to be a proc_t |
1c79356b | 1290 | nfs_iodmount[myiod] = NULL; |
91447636 A |
1291 | error = msleep0((caddr_t)&nfs_iodwant[myiod], nfs_iod_mutex, |
1292 | PWAIT | PCATCH | PDROP, "nfsidl", 0, nfssvc_iod_continue); | |
1293 | lck_mtx_lock(nfs_iod_mutex); | |
1c79356b | 1294 | } |
8f6c56a5 A |
1295 | if (error && !exiterror && nmp && (nmp->nm_bufqiods == 1) && |
1296 | !TAILQ_EMPTY(&nmp->nm_bufq)) { | |
1297 | /* | |
1298 | * Finish processing the queued buffers before exitting. | |
1299 | * Decrement the iod count now to make sure nfs_asyncio() | |
1300 | * doesn't keep queueing up more work. | |
1301 | */ | |
1302 | nmp->nm_bufqiods--; | |
1303 | exiterror = error; | |
1304 | error = 0; | |
1305 | } | |
1c79356b A |
1306 | if (error) { |
1307 | nfs_asyncdaemon[myiod] = 0; | |
8f6c56a5 A |
1308 | if (nmp && !exiterror) |
1309 | nmp->nm_bufqiods--; | |
1c79356b A |
1310 | nfs_iodwant[myiod] = NULL; |
1311 | nfs_iodmount[myiod] = NULL; | |
91447636 | 1312 | lck_mtx_unlock(nfs_iod_mutex); |
1c79356b A |
1313 | nfs_numasync--; |
1314 | if (error == EINTR || error == ERESTART) | |
1315 | error = 0; | |
1c79356b | 1316 | unix_syscall_return(error); |
1c79356b | 1317 | } |
55e303ae | 1318 | if (nmp != NULL) { |
91447636 | 1319 | while ((bp = TAILQ_FIRST(&nmp->nm_bufq)) != NULL) { |
55e303ae A |
1320 | /* Take one off the front of the list */ |
1321 | TAILQ_REMOVE(&nmp->nm_bufq, bp, nb_free); | |
1322 | bp->nb_free.tqe_next = NFSNOLIST; | |
1323 | nmp->nm_bufqlen--; | |
1324 | if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) { | |
1325 | nmp->nm_bufqwant = FALSE; | |
91447636 | 1326 | lck_mtx_unlock(nfs_iod_mutex); |
55e303ae | 1327 | wakeup(&nmp->nm_bufq); |
91447636 A |
1328 | } else { |
1329 | lck_mtx_unlock(nfs_iod_mutex); | |
55e303ae | 1330 | } |
91447636 A |
1331 | |
1332 | SET(bp->nb_flags, NB_IOD); | |
55e303ae | 1333 | if (ISSET(bp->nb_flags, NB_READ)) |
91447636 | 1334 | nfs_doio(bp, bp->nb_rcred, NULL); |
55e303ae | 1335 | else |
91447636 | 1336 | nfs_doio(bp, bp->nb_wcred, NULL); |
1c79356b | 1337 | |
91447636 | 1338 | lck_mtx_lock(nfs_iod_mutex); |
55e303ae A |
1339 | /* |
1340 | * If there are more than one iod on this mount, then defect | |
1341 | * so that the iods can be shared out fairly between the mounts | |
1342 | */ | |
8f6c56a5 | 1343 | if (!exiterror && nfs_defect && nmp->nm_bufqiods > 1) { |
55e303ae A |
1344 | nfs_iodmount[myiod] = NULL; |
1345 | nmp->nm_bufqiods--; | |
1346 | break; | |
1347 | } | |
1348 | } | |
1349 | } | |
91447636 A |
1350 | lck_mtx_unlock(nfs_iod_mutex); |
1351 | ||
55e303ae A |
1352 | if (nfs_ioddelwri) { |
1353 | i = 0; | |
1354 | nfs_ioddelwri = 0; | |
91447636 | 1355 | lck_mtx_lock(nfs_buf_mutex); |
55e303ae A |
1356 | while (i < 8 && (bp = TAILQ_FIRST(&nfsbufdelwri)) != NULL) { |
1357 | struct nfsnode *np = VTONFS(bp->nb_vp); | |
1358 | nfs_buf_remfree(bp); | |
91447636 A |
1359 | nfs_buf_refget(bp); |
1360 | while ((error = nfs_buf_acquire(bp, 0, 0, 0)) == EAGAIN); | |
1361 | nfs_buf_refrele(bp); | |
1362 | if (error) | |
1363 | break; | |
1364 | if (!bp->nb_vp) { | |
1365 | /* buffer is no longer valid */ | |
1366 | nfs_buf_drop(bp); | |
1367 | continue; | |
1368 | } | |
8f6c56a5 A |
1369 | if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) |
1370 | nfs_buf_check_write_verifier(np, bp); | |
55e303ae A |
1371 | if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) { |
1372 | /* put buffer at end of delwri list */ | |
1373 | TAILQ_INSERT_TAIL(&nfsbufdelwri, bp, nb_free); | |
1374 | nfsbufdelwricnt++; | |
91447636 A |
1375 | nfs_buf_drop(bp); |
1376 | lck_mtx_unlock(nfs_buf_mutex); | |
1377 | nfs_flushcommits(np->n_vnode, NULL, 1); | |
55e303ae | 1378 | } else { |
91447636 A |
1379 | SET(bp->nb_flags, (NB_ASYNC | NB_IOD)); |
1380 | lck_mtx_unlock(nfs_buf_mutex); | |
55e303ae A |
1381 | nfs_buf_write(bp); |
1382 | } | |
1383 | i++; | |
91447636 | 1384 | lck_mtx_lock(nfs_buf_mutex); |
1c79356b | 1385 | } |
91447636 | 1386 | lck_mtx_unlock(nfs_buf_mutex); |
1c79356b | 1387 | } |
91447636 A |
1388 | |
1389 | lck_mtx_lock(nfs_iod_mutex); | |
8f6c56a5 A |
1390 | if (exiterror) |
1391 | error = exiterror; | |
1c79356b A |
1392 | } |
1393 | } | |
1394 | ||
1395 | /* | |
1396 | * Shut down a socket associated with an nfssvc_sock structure. | |
1397 | * Should be called with the send lock set, if required. | |
1398 | * The trick here is to increment the sref at the start, so that the nfsds | |
1399 | * will stop using it and clear ns_flag at the end so that it will not be | |
1400 | * reassigned during cleanup. | |
1401 | */ | |
1402 | static void | |
91447636 | 1403 | nfsrv_zapsock(struct nfssvc_sock *slp) |
1c79356b | 1404 | { |
91447636 | 1405 | socket_t so; |
1c79356b | 1406 | |
91447636 A |
1407 | if ((slp->ns_flag & SLP_VALID) == 0) |
1408 | return; | |
1c79356b | 1409 | slp->ns_flag &= ~SLP_ALLFLAGS; |
91447636 A |
1410 | |
1411 | so = slp->ns_so; | |
1412 | if (so == NULL) | |
1413 | return; | |
1414 | ||
743b1565 A |
1415 | /* |
1416 | * Attempt to deter future upcalls, but leave the | |
1417 | * upcall info in place to avoid a race with the | |
1418 | * networking code. | |
1419 | */ | |
91447636 | 1420 | socket_lock(so, 1); |
91447636 A |
1421 | so->so_rcv.sb_flags &= ~SB_UPCALL; |
1422 | socket_unlock(so, 1); | |
743b1565 | 1423 | |
91447636 | 1424 | sock_shutdown(so, SHUT_RDWR); |
1c79356b A |
1425 | } |
1426 | ||
1427 | /* | |
1428 | * Get an authorization string for the uid by having the mount_nfs sitting | |
1429 | * on this mount point porpous out of the kernel and do it. | |
1430 | */ | |
1431 | int | |
1432 | nfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key) | |
1433 | register struct nfsmount *nmp; | |
1434 | struct nfsreq *rep; | |
91447636 | 1435 | kauth_cred_t cred; |
1c79356b A |
1436 | char **auth_str; |
1437 | int *auth_len; | |
1438 | char *verf_str; | |
1439 | int *verf_len; | |
1440 | NFSKERBKEY_T key; /* return session key */ | |
1441 | { | |
1442 | int error = 0; | |
1443 | ||
55e303ae A |
1444 | while ((nmp->nm_state & NFSSTA_WAITAUTH) == 0) { |
1445 | nmp->nm_state |= NFSSTA_WANTAUTH; | |
1c79356b A |
1446 | (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK, |
1447 | "nfsauth1", 2 * hz); | |
1448 | error = nfs_sigintr(nmp, rep, rep->r_procp); | |
1449 | if (error) { | |
55e303ae | 1450 | nmp->nm_state &= ~NFSSTA_WANTAUTH; |
1c79356b A |
1451 | return (error); |
1452 | } | |
1453 | } | |
91447636 | 1454 | nmp->nm_state &= ~NFSSTA_WANTAUTH; |
1c79356b | 1455 | MALLOC(*auth_str, char *, RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK); |
91447636 A |
1456 | if (!*auth_str) |
1457 | return (ENOMEM); | |
1c79356b A |
1458 | nmp->nm_authstr = *auth_str; |
1459 | nmp->nm_authlen = RPCAUTH_MAXSIZ; | |
1460 | nmp->nm_verfstr = verf_str; | |
1461 | nmp->nm_verflen = *verf_len; | |
91447636 A |
1462 | nmp->nm_authuid = kauth_cred_getuid(cred); |
1463 | nmp->nm_state &= ~NFSSTA_WAITAUTH; | |
1c79356b A |
1464 | wakeup((caddr_t)&nmp->nm_authstr); |
1465 | ||
1466 | /* | |
1467 | * And wait for mount_nfs to do its stuff. | |
1468 | */ | |
55e303ae | 1469 | while ((nmp->nm_state & NFSSTA_HASAUTH) == 0 && error == 0) { |
1c79356b A |
1470 | (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK, |
1471 | "nfsauth2", 2 * hz); | |
1472 | error = nfs_sigintr(nmp, rep, rep->r_procp); | |
1473 | } | |
55e303ae A |
1474 | if (nmp->nm_state & NFSSTA_AUTHERR) { |
1475 | nmp->nm_state &= ~NFSSTA_AUTHERR; | |
1c79356b A |
1476 | error = EAUTH; |
1477 | } | |
1478 | if (error) | |
91447636 | 1479 | FREE(*auth_str, M_TEMP); |
1c79356b A |
1480 | else { |
1481 | *auth_len = nmp->nm_authlen; | |
1482 | *verf_len = nmp->nm_verflen; | |
1483 | bcopy((caddr_t)nmp->nm_key, (caddr_t)key, sizeof (key)); | |
1484 | } | |
55e303ae A |
1485 | nmp->nm_state &= ~NFSSTA_HASAUTH; |
1486 | nmp->nm_state |= NFSSTA_WAITAUTH; | |
1487 | if (nmp->nm_state & NFSSTA_WANTAUTH) { | |
1488 | nmp->nm_state &= ~NFSSTA_WANTAUTH; | |
1c79356b A |
1489 | wakeup((caddr_t)&nmp->nm_authtype); |
1490 | } | |
1491 | return (error); | |
1492 | } | |
1493 | ||
1494 | /* | |
1495 | * Get a nickname authenticator and verifier. | |
1496 | */ | |
1497 | int | |
91447636 A |
1498 | nfs_getnickauth( |
1499 | struct nfsmount *nmp, | |
1500 | kauth_cred_t cred, | |
1501 | char **auth_str, | |
1502 | int *auth_len, | |
1503 | char *verf_str, | |
1504 | __unused int verf_len) | |
1c79356b A |
1505 | { |
1506 | register struct nfsuid *nuidp; | |
1507 | register u_long *nickp, *verfp; | |
55e303ae | 1508 | struct timeval ktvin, ktvout, now; |
1c79356b A |
1509 | |
1510 | #if DIAGNOSTIC | |
1511 | if (verf_len < (4 * NFSX_UNSIGNED)) | |
1512 | panic("nfs_getnickauth verf too small"); | |
1513 | #endif | |
91447636 | 1514 | for (nuidp = NMUIDHASH(nmp, kauth_cred_getuid(cred))->lh_first; |
1c79356b | 1515 | nuidp != 0; nuidp = nuidp->nu_hash.le_next) { |
91447636 | 1516 | if (kauth_cred_getuid(nuidp->nu_cr) == kauth_cred_getuid(cred)) |
1c79356b A |
1517 | break; |
1518 | } | |
55e303ae A |
1519 | microtime(&now); |
1520 | if (!nuidp || nuidp->nu_expire < now.tv_sec) | |
1c79356b A |
1521 | return (EACCES); |
1522 | ||
91447636 A |
1523 | MALLOC(nickp, u_long *, 2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK); |
1524 | if (!nickp) | |
1525 | return (ENOMEM); | |
1526 | ||
1c79356b A |
1527 | /* |
1528 | * Move to the end of the lru list (end of lru == most recently used). | |
1529 | */ | |
1530 | TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); | |
1531 | TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); | |
1532 | ||
1c79356b A |
1533 | *nickp++ = txdr_unsigned(RPCAKN_NICKNAME); |
1534 | *nickp = txdr_unsigned(nuidp->nu_nickname); | |
1535 | *auth_str = (char *)nickp; | |
1536 | *auth_len = 2 * NFSX_UNSIGNED; | |
1537 | ||
1538 | /* | |
1539 | * Now we must encrypt the verifier and package it up. | |
1540 | */ | |
1541 | verfp = (u_long *)verf_str; | |
1542 | *verfp++ = txdr_unsigned(RPCAKN_NICKNAME); | |
55e303ae A |
1543 | microtime(&now); |
1544 | if (now.tv_sec > nuidp->nu_timestamp.tv_sec || | |
1545 | (now.tv_sec == nuidp->nu_timestamp.tv_sec && | |
1546 | now.tv_usec > nuidp->nu_timestamp.tv_usec)) | |
1547 | nuidp->nu_timestamp = now; | |
1c79356b A |
1548 | else |
1549 | nuidp->nu_timestamp.tv_usec++; | |
1550 | ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec); | |
1551 | ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec); | |
1552 | ||
1553 | /* | |
1554 | * Now encrypt the timestamp verifier in ecb mode using the session | |
1555 | * key. | |
1556 | */ | |
1557 | #if NFSKERB | |
1558 | XXX | |
1559 | #endif | |
1560 | ||
1561 | *verfp++ = ktvout.tv_sec; | |
1562 | *verfp++ = ktvout.tv_usec; | |
1563 | *verfp = 0; | |
1564 | return (0); | |
1565 | } | |
1566 | ||
1567 | /* | |
1568 | * Save the current nickname in a hash list entry on the mount point. | |
1569 | */ | |
1570 | int | |
1571 | nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep) | |
1572 | register struct nfsmount *nmp; | |
91447636 | 1573 | kauth_cred_t cred; |
1c79356b A |
1574 | int len; |
1575 | NFSKERBKEY_T key; | |
91447636 | 1576 | mbuf_t *mdp; |
1c79356b | 1577 | char **dposp; |
91447636 | 1578 | mbuf_t mrep; |
1c79356b A |
1579 | { |
1580 | register struct nfsuid *nuidp; | |
1581 | register u_long *tl; | |
1582 | register long t1; | |
91447636 | 1583 | mbuf_t md = *mdp; |
55e303ae | 1584 | struct timeval ktvin, ktvout, now; |
1c79356b A |
1585 | u_long nick; |
1586 | char *dpos = *dposp, *cp2; | |
1587 | int deltasec, error = 0; | |
1588 | ||
1589 | if (len == (3 * NFSX_UNSIGNED)) { | |
1590 | nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED); | |
1591 | ktvin.tv_sec = *tl++; | |
1592 | ktvin.tv_usec = *tl++; | |
1593 | nick = fxdr_unsigned(u_long, *tl); | |
1594 | ||
1595 | /* | |
1596 | * Decrypt the timestamp in ecb mode. | |
1597 | */ | |
1598 | #if NFSKERB | |
1599 | XXX | |
1600 | #endif | |
1601 | ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec); | |
1602 | ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec); | |
55e303ae A |
1603 | microtime(&now); |
1604 | deltasec = now.tv_sec - ktvout.tv_sec; | |
1c79356b A |
1605 | if (deltasec < 0) |
1606 | deltasec = -deltasec; | |
1607 | /* | |
1608 | * If ok, add it to the hash list for the mount point. | |
1609 | */ | |
1610 | if (deltasec <= NFS_KERBCLOCKSKEW) { | |
1611 | if (nmp->nm_numuids < nuidhash_max) { | |
1612 | nmp->nm_numuids++; | |
1613 | MALLOC_ZONE(nuidp, struct nfsuid *, | |
1614 | sizeof (struct nfsuid), | |
1615 | M_NFSUID, M_WAITOK); | |
1616 | } else { | |
91447636 A |
1617 | nuidp = NULL; |
1618 | } | |
1619 | if (!nuidp) { | |
1c79356b | 1620 | nuidp = nmp->nm_uidlruhead.tqh_first; |
91447636 A |
1621 | if (!nuidp) { |
1622 | error = ENOMEM; | |
1623 | goto nfsmout; | |
1624 | } | |
1c79356b | 1625 | LIST_REMOVE(nuidp, nu_hash); |
91447636 | 1626 | TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru); |
21362eb3 | 1627 | kauth_cred_rele(nuidp->nu_cr); |
1c79356b A |
1628 | } |
1629 | nuidp->nu_flag = 0; | |
91447636 A |
1630 | kauth_cred_ref(cred); |
1631 | nuidp->nu_cr = cred; | |
55e303ae | 1632 | nuidp->nu_expire = now.tv_sec + NFS_KERBTTL; |
1c79356b A |
1633 | nuidp->nu_timestamp = ktvout; |
1634 | nuidp->nu_nickname = nick; | |
1635 | bcopy(key, nuidp->nu_key, sizeof (key)); | |
91447636 A |
1636 | TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru); |
1637 | LIST_INSERT_HEAD(NMUIDHASH(nmp, kauth_cred_getuid(cred)), | |
1c79356b A |
1638 | nuidp, nu_hash); |
1639 | } | |
1640 | } else | |
1641 | nfsm_adv(nfsm_rndup(len)); | |
1642 | nfsmout: | |
1643 | *mdp = md; | |
1644 | *dposp = dpos; | |
1645 | return (error); | |
1646 | } | |
1647 | ||
1648 | #ifndef NFS_NOSERVER | |
1649 | ||
1650 | /* | |
91447636 | 1651 | * cleanup and release a server socket structure. |
1c79356b | 1652 | */ |
743b1565 | 1653 | void |
91447636 | 1654 | nfsrv_slpfree(struct nfssvc_sock *slp) |
1c79356b | 1655 | { |
91447636 A |
1656 | struct nfsuid *nuidp, *nnuidp; |
1657 | struct nfsrv_descript *nwp, *nnwp; | |
1c79356b | 1658 | |
91447636 A |
1659 | if (slp->ns_so) { |
1660 | sock_release(slp->ns_so); | |
1661 | slp->ns_so = NULL; | |
1662 | } | |
1663 | if (slp->ns_nam) | |
1664 | mbuf_free(slp->ns_nam); | |
1665 | if (slp->ns_raw) | |
1666 | mbuf_freem(slp->ns_raw); | |
1667 | if (slp->ns_rec) | |
1668 | mbuf_freem(slp->ns_rec); | |
1669 | slp->ns_nam = slp->ns_raw = slp->ns_rec = NULL; | |
1670 | ||
1671 | for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0; | |
1672 | nuidp = nnuidp) { | |
1673 | nnuidp = nuidp->nu_lru.tqe_next; | |
1674 | LIST_REMOVE(nuidp, nu_hash); | |
1675 | TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru); | |
1676 | if (nuidp->nu_flag & NU_NAM) | |
1677 | mbuf_freem(nuidp->nu_nam); | |
21362eb3 | 1678 | kauth_cred_rele(nuidp->nu_cr); |
91447636 A |
1679 | FREE_ZONE((caddr_t)nuidp, |
1680 | sizeof (struct nfsuid), M_NFSUID); | |
1681 | } | |
55e303ae | 1682 | |
91447636 A |
1683 | for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) { |
1684 | nnwp = nwp->nd_tq.le_next; | |
1685 | LIST_REMOVE(nwp, nd_tq); | |
21362eb3 A |
1686 | if (nwp->nd_cr) |
1687 | kauth_cred_rele(nwp->nd_cr); | |
91447636 | 1688 | FREE_ZONE((caddr_t)nwp, sizeof *nwp, M_NFSRVDESC); |
55e303ae | 1689 | } |
91447636 A |
1690 | LIST_INIT(&slp->ns_tq); |
1691 | ||
1692 | lck_rw_destroy(&slp->ns_rwlock, nfs_slp_rwlock_group); | |
1693 | lck_mtx_destroy(&slp->ns_wgmutex, nfs_slp_mutex_group); | |
1694 | FREE(slp, M_NFSSVC); | |
55e303ae A |
1695 | } |
1696 | ||
1697 | /* | |
91447636 A |
1698 | * Derefence a server socket structure. If it has no more references and |
1699 | * is no longer valid, you can throw it away. | |
55e303ae A |
1700 | */ |
1701 | void | |
91447636 | 1702 | nfsrv_slpderef(struct nfssvc_sock *slp) |
55e303ae | 1703 | { |
743b1565 A |
1704 | struct timeval now; |
1705 | ||
91447636 A |
1706 | lck_mtx_lock(nfsd_mutex); |
1707 | lck_rw_lock_exclusive(&slp->ns_rwlock); | |
1708 | slp->ns_sref--; | |
1709 | if (slp->ns_sref || (slp->ns_flag & SLP_VALID)) { | |
1710 | lck_rw_done(&slp->ns_rwlock); | |
1711 | lck_mtx_unlock(nfsd_mutex); | |
1712 | return; | |
55e303ae | 1713 | } |
91447636 | 1714 | |
743b1565 A |
1715 | /* queue the socket up for deletion */ |
1716 | microuptime(&now); | |
1717 | slp->ns_timestamp = now.tv_sec; | |
91447636 | 1718 | TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); |
743b1565 A |
1719 | TAILQ_INSERT_TAIL(&nfssvc_deadsockhead, slp, ns_chain); |
1720 | lck_rw_done(&slp->ns_rwlock); | |
8ad349bb A |
1721 | if (slp == nfs_udpsock) |
1722 | nfs_udpsock = NULL; | |
1723 | #if ISO | |
1724 | else if (slp == nfs_cltpsock) | |
1725 | nfs_cltpsock = NULL; | |
1726 | #endif | |
91447636 | 1727 | lck_mtx_unlock(nfsd_mutex); |
55e303ae A |
1728 | } |
1729 | ||
91447636 | 1730 | |
1c79356b A |
1731 | /* |
1732 | * Initialize the data structures for the server. | |
1733 | * Handshake with any new nfsds starting up to avoid any chance of | |
1734 | * corruption. | |
1735 | */ | |
1736 | void | |
1737 | nfsrv_init(terminating) | |
1738 | int terminating; | |
1739 | { | |
91447636 | 1740 | struct nfssvc_sock *slp, *nslp; |
743b1565 | 1741 | struct timeval now; |
1c79356b | 1742 | |
1c79356b | 1743 | if (terminating) { |
743b1565 | 1744 | microuptime(&now); |
91447636 A |
1745 | for (slp = TAILQ_FIRST(&nfssvc_sockhead); slp != 0; slp = nslp) { |
1746 | nslp = TAILQ_NEXT(slp, ns_chain); | |
1747 | if (slp->ns_flag & SLP_VALID) { | |
1748 | lck_rw_lock_exclusive(&slp->ns_rwlock); | |
1c79356b | 1749 | nfsrv_zapsock(slp); |
91447636 A |
1750 | lck_rw_done(&slp->ns_rwlock); |
1751 | } | |
743b1565 A |
1752 | /* queue the socket up for deletion */ |
1753 | slp->ns_timestamp = now.tv_sec; | |
1c79356b | 1754 | TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain); |
743b1565 | 1755 | TAILQ_INSERT_TAIL(&nfssvc_deadsockhead, slp, ns_chain); |
8ad349bb A |
1756 | if (slp == nfs_udpsock) |
1757 | nfs_udpsock = NULL; | |
1758 | #if ISO | |
1759 | else if (slp == nfs_cltpsock) | |
1760 | nfs_cltpsock = NULL; | |
1761 | #endif | |
1c79356b A |
1762 | } |
1763 | nfsrv_cleancache(); /* And clear out server cache */ | |
91447636 A |
1764 | /* XXX Revisit when enabling WebNFS */ |
1765 | #ifdef WEBNFS_ENABLED | |
1c79356b A |
1766 | } else |
1767 | nfs_pub.np_valid = 0; | |
1768 | #else | |
1769 | } | |
1770 | #endif | |
1771 | ||
8ad349bb A |
1772 | if (!terminating) { |
1773 | TAILQ_INIT(&nfssvc_sockhead); | |
1774 | TAILQ_INIT(&nfssvc_deadsockhead); | |
1775 | TAILQ_INIT(&nfsd_head); | |
1776 | nfsd_head_flag &= ~NFSD_CHECKSLP; | |
1777 | } | |
1c79356b A |
1778 | |
1779 | MALLOC(nfs_udpsock, struct nfssvc_sock *, sizeof(struct nfssvc_sock), | |
1780 | M_NFSSVC, M_WAITOK); | |
91447636 A |
1781 | if (nfs_udpsock) { |
1782 | bzero((caddr_t)nfs_udpsock, sizeof (struct nfssvc_sock)); | |
1783 | lck_rw_init(&nfs_udpsock->ns_rwlock, nfs_slp_rwlock_group, nfs_slp_lock_attr); | |
8ad349bb | 1784 | lck_mtx_init(&nfs_udpsock->ns_wgmutex, nfs_slp_mutex_group, nfs_slp_lock_attr); |
91447636 A |
1785 | TAILQ_INIT(&nfs_udpsock->ns_uidlruhead); |
1786 | TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain); | |
1787 | } else { | |
1788 | printf("nfsrv_init() failed to allocate UDP socket\n"); | |
1789 | } | |
1c79356b | 1790 | |
91447636 | 1791 | #if ISO |
1c79356b A |
1792 | MALLOC(nfs_cltpsock, struct nfssvc_sock *, sizeof(struct nfssvc_sock), |
1793 | M_NFSSVC, M_WAITOK); | |
91447636 A |
1794 | if (nfs_cltpsock) { |
1795 | bzero((caddr_t)nfs_cltpsock, sizeof (struct nfssvc_sock)); | |
1796 | lck_rw_init(&nfs_cltpsock->ns_rwlock, nfs_slp_rwlock_group, nfs_slp_lock_attr); | |
8ad349bb | 1797 | lck_mtx_init(&nfs_cltpsock->ns_wgmutex, nfs_slp_mutex_group, nfs_slp_lock_attr); |
91447636 A |
1798 | TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead); |
1799 | TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain); | |
1800 | } else { | |
1801 | printf("nfsrv_init() failed to allocate CLTP socket\n"); | |
1802 | } | |
1803 | #endif | |
1c79356b A |
1804 | } |
1805 | ||
1806 | /* | |
1807 | * Add entries to the server monitor log. | |
1808 | */ | |
1809 | static void | |
1810 | nfsd_rt(sotype, nd, cacherep) | |
1811 | int sotype; | |
1812 | register struct nfsrv_descript *nd; | |
1813 | int cacherep; | |
1814 | { | |
1815 | register struct drt *rt; | |
55e303ae | 1816 | struct timeval now; |
1c79356b A |
1817 | |
1818 | rt = &nfsdrt.drt[nfsdrt.pos]; | |
1819 | if (cacherep == RC_DOIT) | |
1820 | rt->flag = 0; | |
1821 | else if (cacherep == RC_REPLY) | |
1822 | rt->flag = DRT_CACHEREPLY; | |
1823 | else | |
1824 | rt->flag = DRT_CACHEDROP; | |
1825 | if (sotype == SOCK_STREAM) | |
1826 | rt->flag |= DRT_TCP; | |
1c79356b A |
1827 | else if (nd->nd_flag & ND_NFSV3) |
1828 | rt->flag |= DRT_NFSV3; | |
1829 | rt->proc = nd->nd_procnum; | |
91447636 A |
1830 | if (((struct sockaddr *)mbuf_data(nd->nd_nam))->sa_family == AF_INET) |
1831 | rt->ipadr = ((struct sockaddr_in *)mbuf_data(nd->nd_nam))->sin_addr.s_addr; | |
1c79356b A |
1832 | else |
1833 | rt->ipadr = INADDR_ANY; | |
55e303ae A |
1834 | microuptime(&now); |
1835 | rt->resptime = ((now.tv_sec - nd->nd_starttime.tv_sec) * 1000000) + | |
1836 | (now.tv_usec - nd->nd_starttime.tv_usec); | |
1837 | microtime(&rt->tstamp); // XXX unused | |
1c79356b A |
1838 | nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ; |
1839 | } | |
1840 | #endif /* NFS_NOSERVER */ |