nfs_syscalls.c revision 1.48.2.8 1 /* $NetBSD: nfs_syscalls.c,v 1.48.2.8 2002/07/12 01:40:36 nathanw Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95
39 */
40
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: nfs_syscalls.c,v 1.48.2.8 2002/07/12 01:40:36 nathanw Exp $");
43
44 #include "fs_nfs.h"
45 #include "opt_nfs.h"
46 #include "opt_nfsserver.h"
47 #include "opt_iso.h"
48 #include "opt_inet.h"
49 #include "opt_compat_netbsd.h"
50
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/kernel.h>
54 #include <sys/file.h>
55 #include <sys/stat.h>
56 #include <sys/vnode.h>
57 #include <sys/mount.h>
58 #include <sys/proc.h>
59 #include <sys/uio.h>
60 #include <sys/malloc.h>
61 #include <sys/buf.h>
62 #include <sys/mbuf.h>
63 #include <sys/socket.h>
64 #include <sys/socketvar.h>
65 #include <sys/signalvar.h>
66 #include <sys/domain.h>
67 #include <sys/protosw.h>
68 #include <sys/namei.h>
69 #include <sys/syslog.h>
70 #include <sys/filedesc.h>
71 #include <sys/kthread.h>
72
73 #include <sys/sa.h>
74 #include <sys/syscallargs.h>
75
76 #include <netinet/in.h>
77 #include <netinet/tcp.h>
78 #ifdef ISO
79 #include <netiso/iso.h>
80 #endif
81 #include <nfs/xdr_subs.h>
82 #include <nfs/rpcv2.h>
83 #include <nfs/nfsproto.h>
84 #include <nfs/nfs.h>
85 #include <nfs/nfsm_subs.h>
86 #include <nfs/nfsrvcache.h>
87 #include <nfs/nfsmount.h>
88 #include <nfs/nfsnode.h>
89 #include <nfs/nqnfs.h>
90 #include <nfs/nfsrtt.h>
91 #include <nfs/nfs_var.h>
92
93 /* Global defs. */
94 extern int32_t (*nfsrv3_procs[NFS_NPROCS]) __P((struct nfsrv_descript *,
95 struct nfssvc_sock *,
96 struct proc *, struct mbuf **));
97 extern time_t nqnfsstarttime;
98 extern int nfsrvw_procrastinate;
99
100 struct nfssvc_sock *nfs_udpsock;
101 #ifdef ISO
102 struct nfssvc_sock *nfs_cltpsock;
103 #endif
104 #ifdef INET6
105 struct nfssvc_sock *nfs_udp6sock;
106 #endif
107 int nuidhash_max = NFS_MAXUIDHASH;
108 int nfsd_waiting = 0;
109 #ifdef NFSSERVER
110 static int nfs_numnfsd = 0;
111 static int notstarted = 1;
112 static int modify_flag = 0;
113 static struct nfsdrt nfsdrt;
114 #endif
115
116 struct nfssvc_sockhead nfssvc_sockhead;
117 struct nfsdhead nfsd_head;
118
119 int nfssvc_sockhead_flag;
120 int nfsd_head_flag;
121
122 #define TRUE 1
123 #define FALSE 0
124
125 #ifdef NFS
126 static struct proc *nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
127 int nfs_niothreads = -1; /* == "0, and has never been set" */
128 #endif
129
130 #ifdef NFSSERVER
131 static void nfsd_rt __P((int, struct nfsrv_descript *, int));
132 #endif
133
134 /*
135 * NFS server system calls
136 */
137
138
139 /*
140 * Nfs server pseudo system call for the nfsd's
141 * Based on the flag value it either:
142 * - adds a socket to the selection list
143 * - remains in the kernel as an nfsd
144 * - remains in the kernel as an nfsiod
145 */
146 int
147 sys_nfssvc(l, v, retval)
148 struct lwp *l;
149 void *v;
150 register_t *retval;
151 {
152 struct sys_nfssvc_args /* {
153 syscallarg(int) flag;
154 syscallarg(caddr_t) argp;
155 } */ *uap = v;
156 struct proc *p = l->l_proc;
157 int error;
158 #ifdef NFS
159 struct nameidata nd;
160 struct nfsmount *nmp;
161 struct nfsd_cargs ncd;
162 #endif
163 #ifdef NFSSERVER
164 struct file *fp;
165 struct mbuf *nam;
166 struct nfsd_args nfsdarg;
167 struct nfsd_srvargs nfsd_srvargs, *nsd = &nfsd_srvargs;
168 struct nfsd *nfsd;
169 struct nfssvc_sock *slp;
170 struct nfsuid *nuidp;
171 #endif
172
173 /*
174 * Must be super user
175 */
176 error = suser(p->p_ucred, &p->p_acflag);
177 if(error)
178 return (error);
179 while (nfssvc_sockhead_flag & SLP_INIT) {
180 nfssvc_sockhead_flag |= SLP_WANTINIT;
181 (void) tsleep((caddr_t)&nfssvc_sockhead, PSOCK, "nfsd init", 0);
182 }
183 if (SCARG(uap, flag) & NFSSVC_BIOD) {
184 #if defined(NFS) && defined(COMPAT_14)
185 error = nfssvc_iod(l);
186 #else
187 error = ENOSYS;
188 #endif
189 } else if (SCARG(uap, flag) & NFSSVC_MNTD) {
190 #ifndef NFS
191 error = ENOSYS;
192 #else
193 error = copyin(SCARG(uap, argp), (caddr_t)&ncd, sizeof (ncd));
194 if (error)
195 return (error);
196 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
197 ncd.ncd_dirp, p);
198 error = namei(&nd);
199 if (error)
200 return (error);
201 if ((nd.ni_vp->v_flag & VROOT) == 0)
202 error = EINVAL;
203 nmp = VFSTONFS(nd.ni_vp->v_mount);
204 vput(nd.ni_vp);
205 if (error)
206 return (error);
207 if ((nmp->nm_iflag & NFSMNT_MNTD) &&
208 (SCARG(uap, flag) & NFSSVC_GOTAUTH) == 0)
209 return (0);
210 nmp->nm_iflag |= NFSMNT_MNTD;
211 error = nqnfs_clientd(nmp, p->p_ucred, &ncd, SCARG(uap, flag),
212 SCARG(uap, argp), l);
213 #endif /* NFS */
214 } else if (SCARG(uap, flag) & NFSSVC_ADDSOCK) {
215 #ifndef NFSSERVER
216 error = ENOSYS;
217 #else
218 error = copyin(SCARG(uap, argp), (caddr_t)&nfsdarg,
219 sizeof(nfsdarg));
220 if (error)
221 return (error);
222 /* getsock() will use the descriptor for us */
223 error = getsock(p->p_fd, nfsdarg.sock, &fp);
224 if (error)
225 return (error);
226 /*
227 * Get the client address for connected sockets.
228 */
229 if (nfsdarg.name == NULL || nfsdarg.namelen == 0)
230 nam = (struct mbuf *)0;
231 else {
232 error = sockargs(&nam, nfsdarg.name, nfsdarg.namelen,
233 MT_SONAME);
234 if (error) {
235 FILE_UNUSE(fp, NULL);
236 return (error);
237 }
238 }
239 error = nfssvc_addsock(fp, nam);
240 FILE_UNUSE(fp, NULL);
241 #endif /* !NFSSERVER */
242 } else {
243 #ifndef NFSSERVER
244 error = ENOSYS;
245 #else
246 error = copyin(SCARG(uap, argp), (caddr_t)nsd, sizeof (*nsd));
247 if (error)
248 return (error);
249 if ((SCARG(uap, flag) & NFSSVC_AUTHIN) &&
250 ((nfsd = nsd->nsd_nfsd)) != NULL &&
251 (nfsd->nfsd_slp->ns_flag & SLP_VALID)) {
252 slp = nfsd->nfsd_slp;
253
254 /*
255 * First check to see if another nfsd has already
256 * added this credential.
257 */
258 for (nuidp = NUIDHASH(slp,nsd->nsd_cr.cr_uid)->lh_first;
259 nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
260 if (nuidp->nu_cr.cr_uid == nsd->nsd_cr.cr_uid &&
261 (!nfsd->nfsd_nd->nd_nam2 ||
262 netaddr_match(NU_NETFAM(nuidp),
263 &nuidp->nu_haddr, nfsd->nfsd_nd->nd_nam2)))
264 break;
265 }
266 if (nuidp) {
267 nfsrv_setcred(&nuidp->nu_cr,&nfsd->nfsd_nd->nd_cr);
268 nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
269 } else {
270 /*
271 * Nope, so we will.
272 */
273 if (slp->ns_numuids < nuidhash_max) {
274 slp->ns_numuids++;
275 nuidp = (struct nfsuid *)
276 malloc(sizeof (struct nfsuid), M_NFSUID,
277 M_WAITOK);
278 } else
279 nuidp = (struct nfsuid *)0;
280 if ((slp->ns_flag & SLP_VALID) == 0) {
281 if (nuidp)
282 free((caddr_t)nuidp, M_NFSUID);
283 } else {
284 if (nuidp == (struct nfsuid *)0) {
285 nuidp = slp->ns_uidlruhead.tqh_first;
286 LIST_REMOVE(nuidp, nu_hash);
287 TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp,
288 nu_lru);
289 if (nuidp->nu_flag & NU_NAM)
290 m_freem(nuidp->nu_nam);
291 }
292 nuidp->nu_flag = 0;
293 crcvt(&nuidp->nu_cr, &nsd->nsd_cr);
294 if (nuidp->nu_cr.cr_ngroups > NGROUPS)
295 nuidp->nu_cr.cr_ngroups = NGROUPS;
296 nuidp->nu_cr.cr_ref = 1;
297 nuidp->nu_timestamp = nsd->nsd_timestamp;
298 nuidp->nu_expire = time.tv_sec + nsd->nsd_ttl;
299 /*
300 * and save the session key in nu_key.
301 */
302 memcpy(nuidp->nu_key, nsd->nsd_key,
303 sizeof(nsd->nsd_key));
304 if (nfsd->nfsd_nd->nd_nam2) {
305 struct sockaddr_in *saddr;
306
307 saddr = mtod(nfsd->nfsd_nd->nd_nam2,
308 struct sockaddr_in *);
309 switch (saddr->sin_family) {
310 case AF_INET:
311 nuidp->nu_flag |= NU_INETADDR;
312 nuidp->nu_inetaddr =
313 saddr->sin_addr.s_addr;
314 break;
315 case AF_ISO:
316 default:
317 nuidp->nu_flag |= NU_NAM;
318 nuidp->nu_nam = m_copym(
319 nfsd->nfsd_nd->nd_nam2, 0,
320 M_COPYALL, M_WAIT);
321 break;
322 };
323 }
324 TAILQ_INSERT_TAIL(&slp->ns_uidlruhead, nuidp,
325 nu_lru);
326 LIST_INSERT_HEAD(NUIDHASH(slp, nsd->nsd_uid),
327 nuidp, nu_hash);
328 nfsrv_setcred(&nuidp->nu_cr,
329 &nfsd->nfsd_nd->nd_cr);
330 nfsd->nfsd_nd->nd_flag |= ND_KERBFULL;
331 }
332 }
333 }
334 if ((SCARG(uap, flag) & NFSSVC_AUTHINFAIL) &&
335 (nfsd = nsd->nsd_nfsd))
336 nfsd->nfsd_flag |= NFSD_AUTHFAIL;
337 error = nfssvc_nfsd(nsd, SCARG(uap, argp), l);
338 #endif /* !NFSSERVER */
339 }
340 if (error == EINTR || error == ERESTART)
341 error = 0;
342 return (error);
343 }
344
345 #ifdef NFSSERVER
346 /*
347 * Adds a socket to the list for servicing by nfsds.
348 */
349 int
350 nfssvc_addsock(fp, mynam)
351 struct file *fp;
352 struct mbuf *mynam;
353 {
354 struct mbuf *m;
355 int siz;
356 struct nfssvc_sock *slp;
357 struct socket *so;
358 struct nfssvc_sock *tslp;
359 int error, s;
360
361 so = (struct socket *)fp->f_data;
362 tslp = (struct nfssvc_sock *)0;
363 /*
364 * Add it to the list, as required.
365 */
366 if (so->so_proto->pr_protocol == IPPROTO_UDP) {
367 #ifdef INET6
368 if (so->so_proto->pr_domain->dom_family == AF_INET6)
369 tslp = nfs_udp6sock;
370 else
371 #endif
372 tslp = nfs_udpsock;
373 if (tslp->ns_flag & SLP_VALID) {
374 m_freem(mynam);
375 return (EPERM);
376 }
377 #ifdef ISO
378 } else if (so->so_proto->pr_protocol == ISOPROTO_CLTP) {
379 tslp = nfs_cltpsock;
380 if (tslp->ns_flag & SLP_VALID) {
381 m_freem(mynam);
382 return (EPERM);
383 }
384 #endif /* ISO */
385 }
386 if (so->so_type == SOCK_STREAM)
387 siz = NFS_MAXPACKET + sizeof (u_long);
388 else
389 siz = NFS_MAXPACKET;
390 error = soreserve(so, siz, siz);
391 if (error) {
392 m_freem(mynam);
393 return (error);
394 }
395
396 /*
397 * Set protocol specific options { for now TCP only } and
398 * reserve some space. For datagram sockets, this can get called
399 * repeatedly for the same socket, but that isn't harmful.
400 */
401 if (so->so_type == SOCK_STREAM) {
402 MGET(m, M_WAIT, MT_SOOPTS);
403 *mtod(m, int32_t *) = 1;
404 m->m_len = sizeof(int32_t);
405 sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
406 }
407 if ((so->so_proto->pr_domain->dom_family == AF_INET
408 #ifdef INET6
409 || so->so_proto->pr_domain->dom_family == AF_INET6
410 #endif
411 ) &&
412 so->so_proto->pr_protocol == IPPROTO_TCP) {
413 MGET(m, M_WAIT, MT_SOOPTS);
414 *mtod(m, int32_t *) = 1;
415 m->m_len = sizeof(int32_t);
416 sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
417 }
418 so->so_rcv.sb_flags &= ~SB_NOINTR;
419 so->so_rcv.sb_timeo = 0;
420 so->so_snd.sb_flags &= ~SB_NOINTR;
421 so->so_snd.sb_timeo = 0;
422 if (tslp)
423 slp = tslp;
424 else {
425 slp = (struct nfssvc_sock *)
426 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
427 memset((caddr_t)slp, 0, sizeof (struct nfssvc_sock));
428 TAILQ_INIT(&slp->ns_uidlruhead);
429 TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
430 }
431 slp->ns_so = so;
432 slp->ns_nam = mynam;
433 fp->f_count++;
434 slp->ns_fp = fp;
435 s = splsoftnet();
436 so->so_upcallarg = (caddr_t)slp;
437 so->so_upcall = nfsrv_rcv;
438 so->so_rcv.sb_flags |= SB_UPCALL;
439 slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
440 nfsrv_wakenfsd(slp);
441 splx(s);
442 return (0);
443 }
444
445 /*
446 * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
447 * until it is killed by a signal.
448 */
449 int
450 nfssvc_nfsd(nsd, argp, l)
451 struct nfsd_srvargs *nsd;
452 caddr_t argp;
453 struct lwp *l;
454 {
455 struct mbuf *m;
456 int siz;
457 struct nfssvc_sock *slp;
458 struct socket *so;
459 int *solockp;
460 struct nfsd *nfsd = nsd->nsd_nfsd;
461 struct nfsrv_descript *nd = NULL;
462 struct mbuf *mreq;
463 int error = 0, cacherep, s, sotype, writes_todo;
464 u_quad_t cur_usec;
465 struct proc *p = l->l_proc;
466
467 #ifndef nolint
468 cacherep = RC_DOIT;
469 writes_todo = 0;
470 #endif
471 s = splsoftnet();
472 if (nfsd == (struct nfsd *)0) {
473 nsd->nsd_nfsd = nfsd = (struct nfsd *)
474 malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK);
475 memset((caddr_t)nfsd, 0, sizeof (struct nfsd));
476 nfsd->nfsd_procp = p;
477 TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
478 nfs_numnfsd++;
479 }
480 PHOLD(l);
481 /*
482 * Loop getting rpc requests until SIGKILL.
483 */
484 for (;;) {
485 if ((nfsd->nfsd_flag & NFSD_REQINPROG) == 0) {
486 while (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
487 (nfsd_head_flag & NFSD_CHECKSLP) == 0) {
488 nfsd->nfsd_flag |= NFSD_WAITING;
489 nfsd_waiting++;
490 error = tsleep((caddr_t)nfsd, PSOCK | PCATCH,
491 "nfsd", 0);
492 nfsd_waiting--;
493 if (error)
494 goto done;
495 }
496 if (nfsd->nfsd_slp == (struct nfssvc_sock *)0 &&
497 (nfsd_head_flag & NFSD_CHECKSLP) != 0) {
498 for (slp = nfssvc_sockhead.tqh_first; slp != 0;
499 slp = slp->ns_chain.tqe_next) {
500 if ((slp->ns_flag & (SLP_VALID | SLP_DOREC))
501 == (SLP_VALID | SLP_DOREC)) {
502 slp->ns_flag &= ~SLP_DOREC;
503 slp->ns_sref++;
504 nfsd->nfsd_slp = slp;
505 break;
506 }
507 }
508 if (slp == 0)
509 nfsd_head_flag &= ~NFSD_CHECKSLP;
510 }
511 if ((slp = nfsd->nfsd_slp) == (struct nfssvc_sock *)0)
512 continue;
513 if (slp->ns_flag & SLP_VALID) {
514 if (slp->ns_flag & SLP_DISCONN)
515 nfsrv_zapsock(slp);
516 else if (slp->ns_flag & SLP_NEEDQ) {
517 slp->ns_flag &= ~SLP_NEEDQ;
518 (void) nfs_sndlock(&slp->ns_solock,
519 (struct nfsreq *)0);
520 nfsrv_rcv(slp->ns_so, (caddr_t)slp,
521 M_WAIT);
522 nfs_sndunlock(&slp->ns_solock);
523 }
524 error = nfsrv_dorec(slp, nfsd, &nd);
525 cur_usec = (u_quad_t)time.tv_sec * 1000000 +
526 (u_quad_t)time.tv_usec;
527 if (error && slp->ns_tq.lh_first &&
528 slp->ns_tq.lh_first->nd_time <= cur_usec) {
529 error = 0;
530 cacherep = RC_DOIT;
531 writes_todo = 1;
532 } else
533 writes_todo = 0;
534 nfsd->nfsd_flag |= NFSD_REQINPROG;
535 }
536 } else {
537 error = 0;
538 slp = nfsd->nfsd_slp;
539 }
540 if (error || (slp->ns_flag & SLP_VALID) == 0) {
541 if (nd) {
542 free((caddr_t)nd, M_NFSRVDESC);
543 nd = NULL;
544 }
545 nfsd->nfsd_slp = (struct nfssvc_sock *)0;
546 nfsd->nfsd_flag &= ~NFSD_REQINPROG;
547 nfsrv_slpderef(slp);
548 continue;
549 }
550 splx(s);
551 so = slp->ns_so;
552 sotype = so->so_type;
553 if (so->so_proto->pr_flags & PR_CONNREQUIRED)
554 solockp = &slp->ns_solock;
555 else
556 solockp = (int *)0;
557 if (nd) {
558 nd->nd_starttime = time;
559 if (nd->nd_nam2)
560 nd->nd_nam = nd->nd_nam2;
561 else
562 nd->nd_nam = slp->ns_nam;
563
564 /*
565 * Check to see if authorization is needed.
566 */
567 if (nfsd->nfsd_flag & NFSD_NEEDAUTH) {
568 nfsd->nfsd_flag &= ~NFSD_NEEDAUTH;
569 nsd->nsd_haddr = mtod(nd->nd_nam,
570 struct sockaddr_in *)->sin_addr.s_addr;
571 nsd->nsd_authlen = nfsd->nfsd_authlen;
572 nsd->nsd_verflen = nfsd->nfsd_verflen;
573 if (!copyout(nfsd->nfsd_authstr,nsd->nsd_authstr,
574 nfsd->nfsd_authlen) &&
575 !copyout(nfsd->nfsd_verfstr, nsd->nsd_verfstr,
576 nfsd->nfsd_verflen) &&
577 !copyout((caddr_t)nsd, argp, sizeof (*nsd))) {
578 PRELE(l);
579 return (ENEEDAUTH);
580 }
581 cacherep = RC_DROPIT;
582 } else
583 cacherep = nfsrv_getcache(nd, slp, &mreq);
584
585 /*
586 * Check for just starting up for NQNFS and send
587 * fake "try again later" replies to the NQNFS clients.
588 */
589 if (notstarted && nqnfsstarttime <= time.tv_sec) {
590 if (modify_flag) {
591 nqnfsstarttime = time.tv_sec + nqsrv_writeslack;
592 modify_flag = 0;
593 } else
594 notstarted = 0;
595 }
596 if (notstarted) {
597 if ((nd->nd_flag & ND_NQNFS) == 0)
598 cacherep = RC_DROPIT;
599 else if (nd->nd_procnum != NFSPROC_WRITE) {
600 nd->nd_procnum = NFSPROC_NOOP;
601 nd->nd_repstat = NQNFS_TRYLATER;
602 cacherep = RC_DOIT;
603 } else
604 modify_flag = 1;
605 } else if (nfsd->nfsd_flag & NFSD_AUTHFAIL) {
606 nfsd->nfsd_flag &= ~NFSD_AUTHFAIL;
607 nd->nd_procnum = NFSPROC_NOOP;
608 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
609 cacherep = RC_DOIT;
610 }
611 }
612
613 /*
614 * Loop to get all the write rpc relies that have been
615 * gathered together.
616 */
617 do {
618 #ifdef DIAGNOSTIC
619 int lockcount;
620 #endif
621 switch (cacherep) {
622 case RC_DOIT:
623 #ifdef DIAGNOSTIC
624 /*
625 * NFS server procs should neither release
626 * locks already held, nor leave things
627 * locked. Catch this sooner, rather than
628 * later (when we try to relock something we
629 * already have locked). Careful inspection
630 * of the failing routine usually turns up the
631 * lock leak.. once we know what it is..
632 */
633 lockcount = l->l_locks;
634 #endif
635 if (writes_todo || (!(nd->nd_flag & ND_NFSV3) &&
636 nd->nd_procnum == NFSPROC_WRITE &&
637 nfsrvw_procrastinate > 0 && !notstarted))
638 error = nfsrv_writegather(&nd, slp,
639 nfsd->nfsd_procp, &mreq);
640 else
641 error = (*(nfsrv3_procs[nd->nd_procnum]))(nd,
642 slp, nfsd->nfsd_procp, &mreq);
643 #ifdef DIAGNOSTIC
644 if (l->l_locks != lockcount) {
645 /*
646 * If you see this panic, audit
647 * nfsrv3_procs[nd->nd_procnum] for vnode
648 * locking errors (usually, it's due to
649 * forgetting to vput() something).
650 */
651 #ifdef DEBUG
652 extern void printlockedvnodes(void);
653 printlockedvnodes();
654 #endif
655 printf("nfsd: locking botch in op %d"
656 " (before %d, after %d)\n",
657 nd ? nd->nd_procnum : -1,
658 lockcount, l->l_locks);
659 }
660 #endif
661 if (mreq == NULL)
662 break;
663 if (error) {
664 if (nd->nd_procnum != NQNFSPROC_VACATED)
665 nfsstats.srv_errs++;
666 nfsrv_updatecache(nd, FALSE, mreq);
667 if (nd->nd_nam2)
668 m_freem(nd->nd_nam2);
669 break;
670 }
671 nfsstats.srvrpccnt[nd->nd_procnum]++;
672 nfsrv_updatecache(nd, TRUE, mreq);
673 nd->nd_mrep = (struct mbuf *)0;
674 case RC_REPLY:
675 m = mreq;
676 siz = 0;
677 while (m) {
678 siz += m->m_len;
679 m = m->m_next;
680 }
681 if (siz <= 0 || siz > NFS_MAXPACKET) {
682 printf("mbuf siz=%d\n",siz);
683 panic("Bad nfs svc reply");
684 }
685 m = mreq;
686 m->m_pkthdr.len = siz;
687 m->m_pkthdr.rcvif = (struct ifnet *)0;
688 /*
689 * For stream protocols, prepend a Sun RPC
690 * Record Mark.
691 */
692 if (sotype == SOCK_STREAM) {
693 M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
694 *mtod(m, u_int32_t *) = htonl(0x80000000 | siz);
695 }
696 if (solockp)
697 (void) nfs_sndlock(solockp, (struct nfsreq *)0);
698 if (slp->ns_flag & SLP_VALID)
699 error = nfs_send(so, nd->nd_nam2, m, NULL);
700 else {
701 error = EPIPE;
702 m_freem(m);
703 }
704 if (nfsrtton)
705 nfsd_rt(sotype, nd, cacherep);
706 if (nd->nd_nam2)
707 MFREE(nd->nd_nam2, m);
708 if (nd->nd_mrep)
709 m_freem(nd->nd_mrep);
710 if (error == EPIPE)
711 nfsrv_zapsock(slp);
712 if (solockp)
713 nfs_sndunlock(solockp);
714 if (error == EINTR || error == ERESTART) {
715 free((caddr_t)nd, M_NFSRVDESC);
716 nfsrv_slpderef(slp);
717 s = splsoftnet();
718 goto done;
719 }
720 break;
721 case RC_DROPIT:
722 if (nfsrtton)
723 nfsd_rt(sotype, nd, cacherep);
724 m_freem(nd->nd_mrep);
725 m_freem(nd->nd_nam2);
726 break;
727 };
728 if (nd) {
729 FREE((caddr_t)nd, M_NFSRVDESC);
730 nd = NULL;
731 }
732
733 /*
734 * Check to see if there are outstanding writes that
735 * need to be serviced.
736 */
737 cur_usec = (u_quad_t)time.tv_sec * 1000000 +
738 (u_quad_t)time.tv_usec;
739 s = splsoftclock();
740 if (slp->ns_tq.lh_first &&
741 slp->ns_tq.lh_first->nd_time <= cur_usec) {
742 cacherep = RC_DOIT;
743 writes_todo = 1;
744 } else
745 writes_todo = 0;
746 splx(s);
747 } while (writes_todo);
748 s = splsoftnet();
749 if (nfsrv_dorec(slp, nfsd, &nd)) {
750 nfsd->nfsd_flag &= ~NFSD_REQINPROG;
751 nfsd->nfsd_slp = NULL;
752 nfsrv_slpderef(slp);
753 }
754 }
755 done:
756 PRELE(l);
757 TAILQ_REMOVE(&nfsd_head, nfsd, nfsd_chain);
758 splx(s);
759 free((caddr_t)nfsd, M_NFSD);
760 nsd->nsd_nfsd = (struct nfsd *)0;
761 if (--nfs_numnfsd == 0)
762 nfsrv_init(TRUE); /* Reinitialize everything */
763 return (error);
764 }
765
766 /*
767 * Shut down a socket associated with an nfssvc_sock structure.
768 * Should be called with the send lock set, if required.
769 * The trick here is to increment the sref at the start, so that the nfsds
770 * will stop using it and clear ns_flag at the end so that it will not be
771 * reassigned during cleanup.
772 */
773 void
774 nfsrv_zapsock(slp)
775 struct nfssvc_sock *slp;
776 {
777 struct nfsuid *nuidp, *nnuidp;
778 struct nfsrv_descript *nwp, *nnwp;
779 struct socket *so;
780 struct file *fp;
781 struct mbuf *m;
782 int s;
783
784 slp->ns_flag &= ~SLP_ALLFLAGS;
785 fp = slp->ns_fp;
786 if (fp) {
787 FILE_USE(fp);
788 slp->ns_fp = (struct file *)0;
789 so = slp->ns_so;
790 so->so_upcall = NULL;
791 so->so_upcallarg = NULL;
792 so->so_rcv.sb_flags &= ~SB_UPCALL;
793 soshutdown(so, 2);
794 closef(fp, (struct proc *)0);
795 if (slp->ns_nam)
796 MFREE(slp->ns_nam, m);
797 m_freem(slp->ns_raw);
798 m_freem(slp->ns_rec);
799 for (nuidp = slp->ns_uidlruhead.tqh_first; nuidp != 0;
800 nuidp = nnuidp) {
801 nnuidp = nuidp->nu_lru.tqe_next;
802 LIST_REMOVE(nuidp, nu_hash);
803 TAILQ_REMOVE(&slp->ns_uidlruhead, nuidp, nu_lru);
804 if (nuidp->nu_flag & NU_NAM)
805 m_freem(nuidp->nu_nam);
806 free((caddr_t)nuidp, M_NFSUID);
807 }
808 s = splsoftclock();
809 for (nwp = slp->ns_tq.lh_first; nwp; nwp = nnwp) {
810 nnwp = nwp->nd_tq.le_next;
811 LIST_REMOVE(nwp, nd_tq);
812 free((caddr_t)nwp, M_NFSRVDESC);
813 }
814 LIST_INIT(&slp->ns_tq);
815 splx(s);
816 }
817 }
818
819 /*
820 * Derefence a server socket structure. If it has no more references and
821 * is no longer valid, you can throw it away.
822 */
823 void
824 nfsrv_slpderef(slp)
825 struct nfssvc_sock *slp;
826 {
827 if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
828 TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
829 free((caddr_t)slp, M_NFSSVC);
830 }
831 }
832
833 /*
834 * Initialize the data structures for the server.
835 * Handshake with any new nfsds starting up to avoid any chance of
836 * corruption.
837 */
838 void
839 nfsrv_init(terminating)
840 int terminating;
841 {
842 struct nfssvc_sock *slp, *nslp;
843
844 if (nfssvc_sockhead_flag & SLP_INIT)
845 panic("nfsd init");
846 nfssvc_sockhead_flag |= SLP_INIT;
847 if (terminating) {
848 for (slp = nfssvc_sockhead.tqh_first; slp != 0; slp = nslp) {
849 nslp = slp->ns_chain.tqe_next;
850 if (slp->ns_flag & SLP_VALID)
851 nfsrv_zapsock(slp);
852 TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
853 free((caddr_t)slp, M_NFSSVC);
854 }
855 nfsrv_cleancache(); /* And clear out server cache */
856 } else
857 nfs_pub.np_valid = 0;
858
859 TAILQ_INIT(&nfssvc_sockhead);
860 nfssvc_sockhead_flag &= ~SLP_INIT;
861 if (nfssvc_sockhead_flag & SLP_WANTINIT) {
862 nfssvc_sockhead_flag &= ~SLP_WANTINIT;
863 wakeup((caddr_t)&nfssvc_sockhead);
864 }
865
866 TAILQ_INIT(&nfsd_head);
867 nfsd_head_flag &= ~NFSD_CHECKSLP;
868
869 nfs_udpsock = (struct nfssvc_sock *)
870 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
871 memset((caddr_t)nfs_udpsock, 0, sizeof (struct nfssvc_sock));
872 TAILQ_INIT(&nfs_udpsock->ns_uidlruhead);
873 TAILQ_INSERT_HEAD(&nfssvc_sockhead, nfs_udpsock, ns_chain);
874
875 #ifdef INET6
876 nfs_udp6sock = (struct nfssvc_sock *)
877 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
878 memset((caddr_t)nfs_udp6sock, 0, sizeof (struct nfssvc_sock));
879 TAILQ_INIT(&nfs_udp6sock->ns_uidlruhead);
880 TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_udp6sock, ns_chain);
881 #endif
882
883 #ifdef ISO
884 nfs_cltpsock = (struct nfssvc_sock *)
885 malloc(sizeof (struct nfssvc_sock), M_NFSSVC, M_WAITOK);
886 memset((caddr_t)nfs_cltpsock, 0, sizeof (struct nfssvc_sock));
887 TAILQ_INIT(&nfs_cltpsock->ns_uidlruhead);
888 TAILQ_INSERT_TAIL(&nfssvc_sockhead, nfs_cltpsock, ns_chain);
889 #endif
890 }
891
892 /*
893 * Add entries to the server monitor log.
894 */
895 static void
896 nfsd_rt(sotype, nd, cacherep)
897 int sotype;
898 struct nfsrv_descript *nd;
899 int cacherep;
900 {
901 struct drt *rt;
902
903 rt = &nfsdrt.drt[nfsdrt.pos];
904 if (cacherep == RC_DOIT)
905 rt->flag = 0;
906 else if (cacherep == RC_REPLY)
907 rt->flag = DRT_CACHEREPLY;
908 else
909 rt->flag = DRT_CACHEDROP;
910 if (sotype == SOCK_STREAM)
911 rt->flag |= DRT_TCP;
912 if (nd->nd_flag & ND_NQNFS)
913 rt->flag |= DRT_NQNFS;
914 else if (nd->nd_flag & ND_NFSV3)
915 rt->flag |= DRT_NFSV3;
916 rt->proc = nd->nd_procnum;
917 if (mtod(nd->nd_nam, struct sockaddr *)->sa_family == AF_INET)
918 rt->ipadr = mtod(nd->nd_nam, struct sockaddr_in *)->sin_addr.s_addr;
919 else
920 rt->ipadr = INADDR_ANY;
921 rt->resptime = ((time.tv_sec - nd->nd_starttime.tv_sec) * 1000000) +
922 (time.tv_usec - nd->nd_starttime.tv_usec);
923 rt->tstamp = time;
924 nfsdrt.pos = (nfsdrt.pos + 1) % NFSRTTLOGSIZ;
925 }
926 #endif /* NFSSERVER */
927
928 #ifdef NFS
929
930 int nfs_defect = 0;
931 /*
932 * Asynchronous I/O threads for client nfs.
933 * They do read-ahead and write-behind operations on the block I/O cache.
934 * Never returns unless it fails or gets killed.
935 */
936
937 int
938 nfssvc_iod(l)
939 struct lwp *l;
940 {
941 struct buf *bp;
942 int i, myiod;
943 struct nfsmount *nmp;
944 int error = 0;
945 struct proc *p = l->l_proc;
946
947 /*
948 * Assign my position or return error if too many already running
949 */
950 myiod = -1;
951 for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
952 if (nfs_asyncdaemon[i] == NULL) {
953 myiod = i;
954 break;
955 }
956 if (myiod == -1)
957 return (EBUSY);
958 nfs_asyncdaemon[myiod] = p;
959 nfs_numasync++;
960 PHOLD(l);
961 /*
962 * Just loop around doing our stuff until SIGKILL
963 */
964 for (;;) {
965 while (((nmp = nfs_iodmount[myiod]) == NULL
966 || nmp->nm_bufq.tqh_first == NULL)
967 && error == 0) {
968 if (nmp)
969 nmp->nm_bufqiods--;
970 nfs_iodwant[myiod] = p;
971 nfs_iodmount[myiod] = NULL;
972 error = tsleep((caddr_t)&nfs_iodwant[myiod],
973 PWAIT | PCATCH, "nfsidl", 0);
974 }
975 while (nmp != NULL && (bp = nmp->nm_bufq.tqh_first) != NULL) {
976 /* Take one off the front of the list */
977 TAILQ_REMOVE(&nmp->nm_bufq, bp, b_freelist);
978 nmp->nm_bufqlen--;
979 if (nmp->nm_bufqwant && nmp->nm_bufqlen < 2 * nfs_numasync) {
980 nmp->nm_bufqwant = FALSE;
981 wakeup(&nmp->nm_bufq);
982 }
983 (void) nfs_doio(bp, NULL);
984 /*
985 * If there are more than one iod on this mount, then defect
986 * so that the iods can be shared out fairly between the mounts
987 */
988 if (nfs_defect && nmp->nm_bufqiods > 1) {
989 nfs_iodmount[myiod] = NULL;
990 nmp->nm_bufqiods--;
991 break;
992 }
993 }
994 if (error) {
995 break;
996 }
997 }
998 PRELE(l);
999 if (nmp)
1000 nmp->nm_bufqiods--;
1001 nfs_iodwant[myiod] = NULL;
1002 nfs_iodmount[myiod] = NULL;
1003 nfs_asyncdaemon[myiod] = NULL;
1004 nfs_numasync--;
1005
1006 return (error);
1007 }
1008
1009 void
1010 start_nfsio(arg)
1011 void *arg;
1012 {
1013 nfssvc_iod(curlwp);
1014
1015 kthread_exit(0);
1016 }
1017
1018 void
1019 nfs_getset_niothreads(set)
1020 int set;
1021 {
1022 int i, have, start;
1023
1024 for (have = 0, i = 0; i < NFS_MAXASYNCDAEMON; i++)
1025 if (nfs_asyncdaemon[i] != NULL)
1026 have++;
1027
1028 if (set) {
1029 /* clamp to sane range */
1030 nfs_niothreads = max(0, min(nfs_niothreads, NFS_MAXASYNCDAEMON));
1031
1032 start = nfs_niothreads - have;
1033
1034 while (start > 0) {
1035 kthread_create1(start_nfsio, NULL, NULL, "nfsio");
1036 start--;
1037 }
1038
1039 for (i = 0; (start < 0) && (i < NFS_MAXASYNCDAEMON); i++)
1040 if (nfs_asyncdaemon[i] != NULL) {
1041 psignal(nfs_asyncdaemon[i], SIGKILL);
1042 start++;
1043 }
1044 } else {
1045 if (nfs_niothreads >= 0)
1046 nfs_niothreads = have;
1047 }
1048 }
1049
1050 /*
1051 * Get an authorization string for the uid by having the mount_nfs sitting
1052 * on this mount point porpous out of the kernel and do it.
1053 */
1054 int
1055 nfs_getauth(nmp, rep, cred, auth_str, auth_len, verf_str, verf_len, key)
1056 struct nfsmount *nmp;
1057 struct nfsreq *rep;
1058 struct ucred *cred;
1059 char **auth_str;
1060 int *auth_len;
1061 char *verf_str;
1062 int *verf_len;
1063 NFSKERBKEY_T key; /* return session key */
1064 {
1065 int error = 0;
1066
1067 while ((nmp->nm_iflag & NFSMNT_WAITAUTH) == 0) {
1068 nmp->nm_iflag |= NFSMNT_WANTAUTH;
1069 (void) tsleep((caddr_t)&nmp->nm_authtype, PSOCK,
1070 "nfsauth1", 2 * hz);
1071 error = nfs_sigintr(nmp, rep, rep->r_procp);
1072 if (error) {
1073 nmp->nm_iflag &= ~NFSMNT_WANTAUTH;
1074 return (error);
1075 }
1076 }
1077 nmp->nm_iflag &= ~(NFSMNT_WAITAUTH | NFSMNT_WANTAUTH);
1078 nmp->nm_authstr = *auth_str = (char *)malloc(RPCAUTH_MAXSIZ, M_TEMP, M_WAITOK);
1079 nmp->nm_authlen = RPCAUTH_MAXSIZ;
1080 nmp->nm_verfstr = verf_str;
1081 nmp->nm_verflen = *verf_len;
1082 nmp->nm_authuid = cred->cr_uid;
1083 wakeup((caddr_t)&nmp->nm_authstr);
1084
1085 /*
1086 * And wait for mount_nfs to do its stuff.
1087 */
1088 while ((nmp->nm_iflag & NFSMNT_HASAUTH) == 0 && error == 0) {
1089 (void) tsleep((caddr_t)&nmp->nm_authlen, PSOCK,
1090 "nfsauth2", 2 * hz);
1091 error = nfs_sigintr(nmp, rep, rep->r_procp);
1092 }
1093 if (nmp->nm_iflag & NFSMNT_AUTHERR) {
1094 nmp->nm_iflag &= ~NFSMNT_AUTHERR;
1095 error = EAUTH;
1096 }
1097 if (error)
1098 free((caddr_t)*auth_str, M_TEMP);
1099 else {
1100 *auth_len = nmp->nm_authlen;
1101 *verf_len = nmp->nm_verflen;
1102 memcpy((caddr_t)key, (caddr_t)nmp->nm_key, sizeof (key));
1103 }
1104 nmp->nm_iflag &= ~NFSMNT_HASAUTH;
1105 nmp->nm_iflag |= NFSMNT_WAITAUTH;
1106 if (nmp->nm_iflag & NFSMNT_WANTAUTH) {
1107 nmp->nm_iflag &= ~NFSMNT_WANTAUTH;
1108 wakeup((caddr_t)&nmp->nm_authtype);
1109 }
1110 return (error);
1111 }
1112
1113 /*
1114 * Get a nickname authenticator and verifier.
1115 */
1116 int
1117 nfs_getnickauth(nmp, cred, auth_str, auth_len, verf_str, verf_len)
1118 struct nfsmount *nmp;
1119 struct ucred *cred;
1120 char **auth_str;
1121 int *auth_len;
1122 char *verf_str;
1123 int verf_len;
1124 {
1125 struct nfsuid *nuidp;
1126 u_int32_t *nickp, *verfp;
1127 struct timeval ktvin, ktvout;
1128
1129 #ifdef DIAGNOSTIC
1130 if (verf_len < (4 * NFSX_UNSIGNED))
1131 panic("nfs_getnickauth verf too small");
1132 #endif
1133 for (nuidp = NMUIDHASH(nmp, cred->cr_uid)->lh_first;
1134 nuidp != 0; nuidp = nuidp->nu_hash.le_next) {
1135 if (nuidp->nu_cr.cr_uid == cred->cr_uid)
1136 break;
1137 }
1138 if (!nuidp || nuidp->nu_expire < time.tv_sec)
1139 return (EACCES);
1140
1141 /*
1142 * Move to the end of the lru list (end of lru == most recently used).
1143 */
1144 TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
1145 TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp, nu_lru);
1146
1147 nickp = (u_int32_t *)malloc(2 * NFSX_UNSIGNED, M_TEMP, M_WAITOK);
1148 *nickp++ = txdr_unsigned(RPCAKN_NICKNAME);
1149 *nickp = txdr_unsigned(nuidp->nu_nickname);
1150 *auth_str = (char *)nickp;
1151 *auth_len = 2 * NFSX_UNSIGNED;
1152
1153 /*
1154 * Now we must encrypt the verifier and package it up.
1155 */
1156 verfp = (u_int32_t *)verf_str;
1157 *verfp++ = txdr_unsigned(RPCAKN_NICKNAME);
1158 if (time.tv_sec > nuidp->nu_timestamp.tv_sec ||
1159 (time.tv_sec == nuidp->nu_timestamp.tv_sec &&
1160 time.tv_usec > nuidp->nu_timestamp.tv_usec))
1161 nuidp->nu_timestamp = time;
1162 else
1163 nuidp->nu_timestamp.tv_usec++;
1164 ktvin.tv_sec = txdr_unsigned(nuidp->nu_timestamp.tv_sec);
1165 ktvin.tv_usec = txdr_unsigned(nuidp->nu_timestamp.tv_usec);
1166
1167 /*
1168 * Now encrypt the timestamp verifier in ecb mode using the session
1169 * key.
1170 */
1171 #ifdef NFSKERB
1172 XXX
1173 #endif
1174
1175 *verfp++ = ktvout.tv_sec;
1176 *verfp++ = ktvout.tv_usec;
1177 *verfp = 0;
1178 return (0);
1179 }
1180
1181 /*
1182 * Save the current nickname in a hash list entry on the mount point.
1183 */
1184 int
1185 nfs_savenickauth(nmp, cred, len, key, mdp, dposp, mrep)
1186 struct nfsmount *nmp;
1187 struct ucred *cred;
1188 int len;
1189 NFSKERBKEY_T key;
1190 struct mbuf **mdp;
1191 char **dposp;
1192 struct mbuf *mrep;
1193 {
1194 struct nfsuid *nuidp;
1195 u_int32_t *tl;
1196 int32_t t1;
1197 struct mbuf *md = *mdp;
1198 struct timeval ktvin, ktvout;
1199 u_int32_t nick;
1200 char *dpos = *dposp, *cp2;
1201 int deltasec, error = 0;
1202
1203 if (len == (3 * NFSX_UNSIGNED)) {
1204 nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1205 ktvin.tv_sec = *tl++;
1206 ktvin.tv_usec = *tl++;
1207 nick = fxdr_unsigned(u_int32_t, *tl);
1208
1209 /*
1210 * Decrypt the timestamp in ecb mode.
1211 */
1212 #ifdef NFSKERB
1213 XXX
1214 #endif
1215 ktvout.tv_sec = fxdr_unsigned(long, ktvout.tv_sec);
1216 ktvout.tv_usec = fxdr_unsigned(long, ktvout.tv_usec);
1217 deltasec = time.tv_sec - ktvout.tv_sec;
1218 if (deltasec < 0)
1219 deltasec = -deltasec;
1220 /*
1221 * If ok, add it to the hash list for the mount point.
1222 */
1223 if (deltasec <= NFS_KERBCLOCKSKEW) {
1224 if (nmp->nm_numuids < nuidhash_max) {
1225 nmp->nm_numuids++;
1226 nuidp = (struct nfsuid *)
1227 malloc(sizeof (struct nfsuid), M_NFSUID,
1228 M_WAITOK);
1229 } else {
1230 nuidp = nmp->nm_uidlruhead.tqh_first;
1231 LIST_REMOVE(nuidp, nu_hash);
1232 TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp,
1233 nu_lru);
1234 }
1235 nuidp->nu_flag = 0;
1236 nuidp->nu_cr.cr_uid = cred->cr_uid;
1237 nuidp->nu_expire = time.tv_sec + NFS_KERBTTL;
1238 nuidp->nu_timestamp = ktvout;
1239 nuidp->nu_nickname = nick;
1240 memcpy(nuidp->nu_key, key, sizeof (key));
1241 TAILQ_INSERT_TAIL(&nmp->nm_uidlruhead, nuidp,
1242 nu_lru);
1243 LIST_INSERT_HEAD(NMUIDHASH(nmp, cred->cr_uid),
1244 nuidp, nu_hash);
1245 }
1246 } else
1247 nfsm_adv(nfsm_rndup(len));
1248 nfsmout:
1249 *mdp = md;
1250 *dposp = dpos;
1251 return (error);
1252 }
1253 #endif /* NFS */
1254