]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/nfsclient/nfs_subs.c
- For kernel compiled only with KDTRACE_HOOKS and not any lock debugging
[FreeBSD/FreeBSD.git] / sys / nfsclient / nfs_subs.c
1 /*-
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *      @(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 /*
39  * These functions support the macros and help fiddle mbuf chains for
40  * the nfs op functions. They do things like create the rpc header and
41  * copy data between mbuf chains and uio lists.
42  */
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/bio.h>
48 #include <sys/buf.h>
49 #include <sys/proc.h>
50 #include <sys/mount.h>
51 #include <sys/vnode.h>
52 #include <sys/namei.h>
53 #include <sys/mbuf.h>
54 #include <sys/socket.h>
55 #include <sys/stat.h>
56 #include <sys/malloc.h>
57 #include <sys/rwlock.h>
58 #include <sys/sysent.h>
59 #include <sys/syscall.h>
60 #include <sys/sysproto.h>
61 #include <sys/taskqueue.h>
62
63 #include <vm/vm.h>
64 #include <vm/vm_object.h>
65 #include <vm/vm_extern.h>
66 #include <vm/uma.h>
67
68 #include <nfs/nfsproto.h>
69 #include <nfsclient/nfs.h>
70 #include <nfsclient/nfsnode.h>
71 #include <nfs/nfs_kdtrace.h>
72 #include <nfs/xdr_subs.h>
73 #include <nfsclient/nfsm_subs.h>
74 #include <nfsclient/nfsmount.h>
75
76 #include <netinet/in.h>
77
78 /*
79  * Note that stdarg.h and the ANSI style va_start macro is used for both
80  * ANSI and traditional C compilers.
81  */
82 #include <machine/stdarg.h>
83
84 #ifdef KDTRACE_HOOKS
85 dtrace_nfsclient_attrcache_flush_probe_func_t
86     dtrace_nfsclient_attrcache_flush_done_probe;
87 uint32_t nfsclient_attrcache_flush_done_id;
88
89 dtrace_nfsclient_attrcache_get_hit_probe_func_t
90     dtrace_nfsclient_attrcache_get_hit_probe;
91 uint32_t nfsclient_attrcache_get_hit_id;
92
93 dtrace_nfsclient_attrcache_get_miss_probe_func_t
94     dtrace_nfsclient_attrcache_get_miss_probe;
95 uint32_t nfsclient_attrcache_get_miss_id;
96
97 dtrace_nfsclient_attrcache_load_probe_func_t
98     dtrace_nfsclient_attrcache_load_done_probe;
99 uint32_t nfsclient_attrcache_load_done_id;
100 #endif /* !KDTRACE_HOOKS */
101
102 /*
103  * Data items converted to xdr at startup, since they are constant
104  * This is kinda hokey, but may save a little time doing byte swaps
105  */
106 u_int32_t       nfs_xdrneg1;
107 u_int32_t       nfs_true, nfs_false;
108
109 /* And other global data */
110 static u_int32_t nfs_xid = 0;
111 static enum vtype nv2tov_type[8]= {
112         VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON,  VNON
113 };
114
115 int             nfs_ticks;
116 int             nfs_pbuf_freecnt = -1;  /* start out unlimited */
117
118 struct nfs_bufq nfs_bufq;
119 static struct mtx nfs_xid_mtx;
120 struct task     nfs_nfsiodnew_task;
121
122 /*
123  * and the reverse mapping from generic to Version 2 procedure numbers
124  */
125 int nfsv2_procid[NFS_NPROCS] = {
126         NFSV2PROC_NULL,
127         NFSV2PROC_GETATTR,
128         NFSV2PROC_SETATTR,
129         NFSV2PROC_LOOKUP,
130         NFSV2PROC_NOOP,
131         NFSV2PROC_READLINK,
132         NFSV2PROC_READ,
133         NFSV2PROC_WRITE,
134         NFSV2PROC_CREATE,
135         NFSV2PROC_MKDIR,
136         NFSV2PROC_SYMLINK,
137         NFSV2PROC_CREATE,
138         NFSV2PROC_REMOVE,
139         NFSV2PROC_RMDIR,
140         NFSV2PROC_RENAME,
141         NFSV2PROC_LINK,
142         NFSV2PROC_READDIR,
143         NFSV2PROC_NOOP,
144         NFSV2PROC_STATFS,
145         NFSV2PROC_NOOP,
146         NFSV2PROC_NOOP,
147         NFSV2PROC_NOOP,
148         NFSV2PROC_NOOP,
149 };
150
151 LIST_HEAD(nfsnodehashhead, nfsnode);
152
153 u_int32_t
154 nfs_xid_gen(void)
155 {
156         uint32_t xid;
157
158         mtx_lock(&nfs_xid_mtx);
159
160         /* Get a pretty random xid to start with */
161         if (!nfs_xid)
162                 nfs_xid = random();
163         /*
164          * Skip zero xid if it should ever happen.
165          */
166         if (++nfs_xid == 0)
167                 nfs_xid++;
168         xid = nfs_xid;
169         mtx_unlock(&nfs_xid_mtx);
170         return xid;
171 }
172
173 /*
174  * copies a uio scatter/gather list to an mbuf chain.
175  * NOTE: can ony handle iovcnt == 1
176  */
177 int
178 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
179 {
180         char *uiocp;
181         struct mbuf *mp, *mp2;
182         int xfer, left, mlen;
183         int uiosiz, clflg, rem;
184         char *cp;
185
186         KASSERT(uiop->uio_iovcnt == 1, ("nfsm_uiotombuf: iovcnt != 1"));
187
188         if (siz > MLEN)         /* or should it >= MCLBYTES ?? */
189                 clflg = 1;
190         else
191                 clflg = 0;
192         rem = nfsm_rndup(siz)-siz;
193         mp = mp2 = *mq;
194         while (siz > 0) {
195                 left = uiop->uio_iov->iov_len;
196                 uiocp = uiop->uio_iov->iov_base;
197                 if (left > siz)
198                         left = siz;
199                 uiosiz = left;
200                 while (left > 0) {
201                         mlen = M_TRAILINGSPACE(mp);
202                         if (mlen == 0) {
203                                 if (clflg)
204                                         mp = m_getcl(M_WAITOK, MT_DATA, 0);
205                                 else
206                                         mp = m_get(M_WAITOK, MT_DATA);
207                                 mp2->m_next = mp;
208                                 mp2 = mp;
209                                 mlen = M_TRAILINGSPACE(mp);
210                         }
211                         xfer = (left > mlen) ? mlen : left;
212 #ifdef notdef
213                         /* Not Yet.. */
214                         if (uiop->uio_iov->iov_op != NULL)
215                                 (*(uiop->uio_iov->iov_op))
216                                 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
217                         else
218 #endif
219                         if (uiop->uio_segflg == UIO_SYSSPACE)
220                                 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
221                         else
222                                 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
223                         mp->m_len += xfer;
224                         left -= xfer;
225                         uiocp += xfer;
226                         uiop->uio_offset += xfer;
227                         uiop->uio_resid -= xfer;
228                 }
229                 uiop->uio_iov->iov_base =
230                     (char *)uiop->uio_iov->iov_base + uiosiz;
231                 uiop->uio_iov->iov_len -= uiosiz;
232                 siz -= uiosiz;
233         }
234         if (rem > 0) {
235                 if (rem > M_TRAILINGSPACE(mp)) {
236                         mp = m_get(M_WAITOK, MT_DATA);
237                         mp2->m_next = mp;
238                 }
239                 cp = mtod(mp, caddr_t)+mp->m_len;
240                 for (left = 0; left < rem; left++)
241                         *cp++ = '\0';
242                 mp->m_len += rem;
243                 *bpos = cp;
244         } else
245                 *bpos = mtod(mp, caddr_t)+mp->m_len;
246         *mq = mp;
247         return (0);
248 }
249
250 /*
251  * Copy a string into mbufs for the hard cases...
252  */
253 int
254 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
255 {
256         struct mbuf *m1 = NULL, *m2;
257         long left, xfer, len, tlen;
258         u_int32_t *tl;
259         int putsize;
260
261         putsize = 1;
262         m2 = *mb;
263         left = M_TRAILINGSPACE(m2);
264         if (left > 0) {
265                 tl = ((u_int32_t *)(*bpos));
266                 *tl++ = txdr_unsigned(siz);
267                 putsize = 0;
268                 left -= NFSX_UNSIGNED;
269                 m2->m_len += NFSX_UNSIGNED;
270                 if (left > 0) {
271                         bcopy(cp, (caddr_t) tl, left);
272                         siz -= left;
273                         cp += left;
274                         m2->m_len += left;
275                         left = 0;
276                 }
277         }
278         /* Loop around adding mbufs */
279         while (siz > 0) {
280                 if (siz > MLEN) {
281                         m1 = m_getcl(M_WAITOK, MT_DATA, 0);
282                         m1->m_len = MCLBYTES;
283                 } else {
284                         m1 = m_get(M_WAITOK, MT_DATA);
285                         m1->m_len = MLEN;
286                 }
287                 m2->m_next = m1;
288                 m2 = m1;
289                 tl = mtod(m1, u_int32_t *);
290                 tlen = 0;
291                 if (putsize) {
292                         *tl++ = txdr_unsigned(siz);
293                         m1->m_len -= NFSX_UNSIGNED;
294                         tlen = NFSX_UNSIGNED;
295                         putsize = 0;
296                 }
297                 if (siz < m1->m_len) {
298                         len = nfsm_rndup(siz);
299                         xfer = siz;
300                         if (xfer < len)
301                                 *(tl+(xfer>>2)) = 0;
302                 } else {
303                         xfer = len = m1->m_len;
304                 }
305                 bcopy(cp, (caddr_t) tl, xfer);
306                 m1->m_len = len+tlen;
307                 siz -= xfer;
308                 cp += xfer;
309         }
310         *mb = m1;
311         *bpos = mtod(m1, caddr_t)+m1->m_len;
312         return (0);
313 }
314
315 /*
316  * Called once to initialize data structures...
317  */
318 int
319 nfs_init(struct vfsconf *vfsp)
320 {
321         int i;
322
323         nfsmount_zone = uma_zcreate("NFSMOUNT", sizeof(struct nfsmount),
324             NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
325         nfs_true = txdr_unsigned(TRUE);
326         nfs_false = txdr_unsigned(FALSE);
327         nfs_xdrneg1 = txdr_unsigned(-1);
328         nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
329         if (nfs_ticks < 1)
330                 nfs_ticks = 1;
331         /* Ensure async daemons disabled */
332         for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
333                 nfs_iodwant[i] = NFSIOD_NOT_AVAILABLE;
334                 nfs_iodmount[i] = NULL;
335         }
336         nfs_nhinit();                   /* Init the nfsnode table */
337
338         /*
339          * Initialize reply list and start timer
340          */
341         mtx_init(&nfs_iod_mtx, "NFS iod lock", NULL, MTX_DEF);
342         mtx_init(&nfs_xid_mtx, "NFS xid lock", NULL, MTX_DEF);
343         TASK_INIT(&nfs_nfsiodnew_task, 0, nfs_nfsiodnew_tq, NULL);
344
345         nfs_pbuf_freecnt = nswbuf / 2 + 1;
346
347         return (0);
348 }
349
350 int
351 nfs_uninit(struct vfsconf *vfsp)
352 {
353         int i;
354
355         /*
356          * Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup
357          * any sleeping nfsiods so they check nfs_iodmax and exit.
358          * Drain nfsiodnew task before we wait for them to finish.
359          */
360         mtx_lock(&nfs_iod_mtx);
361         nfs_iodmax = 0;
362         mtx_unlock(&nfs_iod_mtx);
363         taskqueue_drain(taskqueue_thread, &nfs_nfsiodnew_task);
364         mtx_lock(&nfs_iod_mtx);
365         for (i = 0; i < nfs_numasync; i++)
366                 if (nfs_iodwant[i] == NFSIOD_AVAILABLE)
367                         wakeup(&nfs_iodwant[i]);
368         /* The last nfsiod to exit will wake us up when nfs_numasync hits 0 */
369         while (nfs_numasync)
370                 msleep(&nfs_numasync, &nfs_iod_mtx, PWAIT, "ioddie", 0);
371         mtx_unlock(&nfs_iod_mtx);
372         nfs_nhuninit();
373         uma_zdestroy(nfsmount_zone);
374         return (0);
375 }
376
377 void 
378 nfs_dircookie_lock(struct nfsnode *np)
379 {
380         mtx_lock(&np->n_mtx);
381         while (np->n_flag & NDIRCOOKIELK)
382                 (void) msleep(&np->n_flag, &np->n_mtx, PZERO, "nfsdirlk", 0);
383         np->n_flag |= NDIRCOOKIELK;
384         mtx_unlock(&np->n_mtx);
385 }
386
387 void 
388 nfs_dircookie_unlock(struct nfsnode *np)
389 {
390         mtx_lock(&np->n_mtx);
391         np->n_flag &= ~NDIRCOOKIELK;
392         wakeup(&np->n_flag);
393         mtx_unlock(&np->n_mtx);
394 }
395
396 int
397 nfs_upgrade_vnlock(struct vnode *vp)
398 {
399         int old_lock;
400
401         ASSERT_VOP_LOCKED(vp, "nfs_upgrade_vnlock");
402         old_lock = VOP_ISLOCKED(vp);
403         if (old_lock != LK_EXCLUSIVE) {
404                 KASSERT(old_lock == LK_SHARED,
405                     ("nfs_upgrade_vnlock: wrong old_lock %d", old_lock));
406                 /* Upgrade to exclusive lock, this might block */
407                 vn_lock(vp, LK_UPGRADE | LK_RETRY);
408         }
409         return (old_lock);
410 }
411
412 void
413 nfs_downgrade_vnlock(struct vnode *vp, int old_lock)
414 {
415         if (old_lock != LK_EXCLUSIVE) {
416                 KASSERT(old_lock == LK_SHARED, ("wrong old_lock %d", old_lock));
417                 /* Downgrade from exclusive lock. */
418                 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
419         }
420 }
421
422 void
423 nfs_printf(const char *fmt, ...)
424 {
425         va_list ap;
426
427         mtx_lock(&Giant);
428         va_start(ap, fmt);
429         vprintf(fmt, ap);
430         va_end(ap);
431         mtx_unlock(&Giant);
432 }
433
434 /*
435  * Attribute cache routines.
436  * nfs_loadattrcache() - loads or updates the cache contents from attributes
437  *      that are on the mbuf list
438  * nfs_getattrcache() - returns valid attributes if found in cache, returns
439  *      error otherwise
440  */
441
442 /*
443  * Load the attribute cache (that lives in the nfsnode entry) with
444  * the values on the mbuf list and
445  * Iff vap not NULL
446  *    copy the attributes to *vaper
447  */
448 int
449 nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp,
450                   struct vattr *vaper, int dontshrink)
451 {
452         struct vnode *vp = *vpp;
453         struct vattr *vap;
454         struct nfs_fattr *fp;
455         struct nfsnode *np = NULL;
456         int32_t t1;
457         caddr_t cp2;
458         int rdev;
459         struct mbuf *md;
460         enum vtype vtyp;
461         u_short vmode;
462         struct timespec mtime, mtime_save;
463         int v3 = NFS_ISV3(vp);
464         int error = 0;
465         u_quad_t nsize;
466         int setnsize;
467
468         md = *mdp;
469         t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
470         cp2 = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, M_WAITOK);
471         if (cp2 == NULL) {
472                 error = EBADRPC;
473                 goto out;
474         }
475         fp = (struct nfs_fattr *)cp2;
476         if (v3) {
477                 vtyp = nfsv3tov_type(fp->fa_type);
478                 vmode = fxdr_unsigned(u_short, fp->fa_mode);
479                 rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
480                         fxdr_unsigned(int, fp->fa3_rdev.specdata2));
481                 fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
482         } else {
483                 vtyp = nfsv2tov_type(fp->fa_type);
484                 vmode = fxdr_unsigned(u_short, fp->fa_mode);
485                 /*
486                  * XXX
487                  *
488                  * The duplicate information returned in fa_type and fa_mode
489                  * is an ambiguity in the NFS version 2 protocol.
490                  *
491                  * VREG should be taken literally as a regular file.  If a
492                  * server intents to return some type information differently
493                  * in the upper bits of the mode field (e.g. for sockets, or
494                  * FIFOs), NFSv2 mandates fa_type to be VNON.  Anyway, we
495                  * leave the examination of the mode bits even in the VREG
496                  * case to avoid breakage for bogus servers, but we make sure
497                  * that there are actually type bits set in the upper part of
498                  * fa_mode (and failing that, trust the va_type field).
499                  *
500                  * NFSv3 cleared the issue, and requires fa_mode to not
501                  * contain any type information (while also introduing sockets
502                  * and FIFOs for fa_type).
503                  */
504                 if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
505                         vtyp = IFTOVT(vmode);
506                 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
507                 fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
508
509                 /*
510                  * Really ugly NFSv2 kludge.
511                  */
512                 if (vtyp == VCHR && rdev == 0xffffffff)
513                         vtyp = VFIFO;
514         }
515
516         /*
517          * If v_type == VNON it is a new node, so fill in the v_type,
518          * n_mtime fields. Check to see if it represents a special
519          * device, and if so, check for a possible alias. Once the
520          * correct vnode has been obtained, fill in the rest of the
521          * information.
522          */
523         np = VTONFS(vp);
524         mtx_lock(&np->n_mtx);
525         if (vp->v_type != vtyp) {
526                 vp->v_type = vtyp;
527                 if (vp->v_type == VFIFO)
528                         vp->v_op = &nfs_fifoops;
529                 np->n_mtime = mtime;
530         }
531         vap = &np->n_vattr;
532         vap->va_type = vtyp;
533         vap->va_mode = (vmode & 07777);
534         vap->va_rdev = rdev;
535         mtime_save = vap->va_mtime;
536         vap->va_mtime = mtime;
537         vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
538         if (v3) {
539                 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
540                 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
541                 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
542                 vap->va_size = fxdr_hyper(&fp->fa3_size);
543                 vap->va_blocksize = NFS_FABLKSIZE;
544                 vap->va_bytes = fxdr_hyper(&fp->fa3_used);
545                 vap->va_fileid = fxdr_unsigned(int32_t,
546                     fp->fa3_fileid.nfsuquad[1]);
547                 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
548                 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
549                 vap->va_flags = 0;
550                 vap->va_filerev = 0;
551         } else {
552                 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
553                 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
554                 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
555                 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
556                 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
557                 vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks)
558                     * NFS_FABLKSIZE;
559                 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
560                 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
561                 vap->va_flags = 0;
562                 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
563                     fp->fa2_ctime.nfsv2_sec);
564                 vap->va_ctime.tv_nsec = 0;
565                 vap->va_gen = fxdr_unsigned(u_int32_t, fp->fa2_ctime.nfsv2_usec);
566                 vap->va_filerev = 0;
567         }
568         np->n_attrstamp = time_second;
569         setnsize = 0;
570         nsize = 0;
571         if (vap->va_size != np->n_size) {
572                 if (vap->va_type == VREG) {
573                         if (dontshrink && vap->va_size < np->n_size) {
574                                 /*
575                                  * We've been told not to shrink the file;
576                                  * zero np->n_attrstamp to indicate that
577                                  * the attributes are stale.
578                                  */
579                                 vap->va_size = np->n_size;
580                                 np->n_attrstamp = 0;
581                                 KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
582                                 vnode_pager_setsize(vp, np->n_size);
583                         } else if (np->n_flag & NMODIFIED) {
584                                 /*
585                                  * We've modified the file: Use the larger
586                                  * of our size, and the server's size.
587                                  */
588                                 if (vap->va_size < np->n_size) {
589                                         vap->va_size = np->n_size;
590                                 } else {
591                                         np->n_size = vap->va_size;
592                                         np->n_flag |= NSIZECHANGED;
593                                 }
594                                 vnode_pager_setsize(vp, np->n_size);
595                         } else if (vap->va_size < np->n_size) {
596                                 /*
597                                  * When shrinking the size, the call to
598                                  * vnode_pager_setsize() cannot be done
599                                  * with the mutex held, so delay it until
600                                  * after the mtx_unlock call.
601                                  */
602                                 nsize = np->n_size = vap->va_size;
603                                 np->n_flag |= NSIZECHANGED;
604                                 setnsize = 1;
605                         } else {
606                                 np->n_size = vap->va_size;
607                                 np->n_flag |= NSIZECHANGED;
608                                 vnode_pager_setsize(vp, np->n_size);
609                         }
610                 } else {
611                         np->n_size = vap->va_size;
612                 }
613         }
614         /*
615          * The following checks are added to prevent a race between (say)
616          * a READDIR+ and a WRITE. 
617          * READDIR+, WRITE requests sent out.
618          * READDIR+ resp, WRITE resp received on client.
619          * However, the WRITE resp was handled before the READDIR+ resp
620          * causing the post op attrs from the write to be loaded first
621          * and the attrs from the READDIR+ to be loaded later. If this 
622          * happens, we have stale attrs loaded into the attrcache.
623          * We detect this by for the mtime moving back. We invalidate the 
624          * attrcache when this happens.
625          */
626         if (timespeccmp(&mtime_save, &vap->va_mtime, >)) {
627                 /* Size changed or mtime went backwards */
628                 np->n_attrstamp = 0;
629                 KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
630         }
631         if (vaper != NULL) {
632                 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
633                 if (np->n_flag & NCHG) {
634                         if (np->n_flag & NACC)
635                                 vaper->va_atime = np->n_atim;
636                         if (np->n_flag & NUPD)
637                                 vaper->va_mtime = np->n_mtim;
638                 }
639         }
640
641 #ifdef KDTRACE_HOOKS
642         if (np->n_attrstamp != 0)
643                 KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, &np->n_vattr, 0);
644 #endif
645         mtx_unlock(&np->n_mtx);
646         if (setnsize)
647                 vnode_pager_setsize(vp, nsize);
648 out:
649 #ifdef KDTRACE_HOOKS
650         if (error)
651                 KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, NULL, error);
652 #endif
653         return (error);
654 }
655
656 #ifdef NFS_ACDEBUG
657 #include <sys/sysctl.h>
658 SYSCTL_DECL(_vfs_oldnfs);
659 static int nfs_acdebug;
660 SYSCTL_INT(_vfs_oldnfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0,
661     "Toggle acdebug (attribute cache debug) flag");
662 #endif
663
664 /*
665  * Check the time stamp
666  * If the cache is valid, copy contents to *vap and return 0
667  * otherwise return an error
668  */
669 int
670 nfs_getattrcache(struct vnode *vp, struct vattr *vaper)
671 {
672         struct nfsnode *np;
673         struct vattr *vap;
674         struct nfsmount *nmp;
675         int timeo;
676         
677         np = VTONFS(vp);
678         vap = &np->n_vattr;
679         nmp = VFSTONFS(vp->v_mount);
680 #ifdef NFS_ACDEBUG
681         mtx_lock(&Giant);       /* nfs_printf() */
682 #endif
683         mtx_lock(&np->n_mtx);
684         /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
685         timeo = (time_second - np->n_mtime.tv_sec) / 10;
686
687 #ifdef NFS_ACDEBUG
688         if (nfs_acdebug>1)
689                 nfs_printf("nfs_getattrcache: initial timeo = %d\n", timeo);
690 #endif
691
692         if (vap->va_type == VDIR) {
693                 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin)
694                         timeo = nmp->nm_acdirmin;
695                 else if (timeo > nmp->nm_acdirmax)
696                         timeo = nmp->nm_acdirmax;
697         } else {
698                 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin)
699                         timeo = nmp->nm_acregmin;
700                 else if (timeo > nmp->nm_acregmax)
701                         timeo = nmp->nm_acregmax;
702         }
703
704 #ifdef NFS_ACDEBUG
705         if (nfs_acdebug > 2)
706                 nfs_printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
707                            nmp->nm_acregmin, nmp->nm_acregmax,
708                            nmp->nm_acdirmin, nmp->nm_acdirmax);
709
710         if (nfs_acdebug)
711                 nfs_printf("nfs_getattrcache: age = %d; final timeo = %d\n",
712                            (time_second - np->n_attrstamp), timeo);
713 #endif
714
715         if ((time_second - np->n_attrstamp) >= timeo) {
716                 nfsstats.attrcache_misses++;
717                 mtx_unlock(&np->n_mtx);
718 #ifdef NFS_ACDEBUG
719                 mtx_unlock(&Giant);     /* nfs_printf() */
720 #endif
721                 KDTRACE_NFS_ATTRCACHE_GET_MISS(vp);
722                 return (ENOENT);
723         }
724         nfsstats.attrcache_hits++;
725         if (vap->va_size != np->n_size) {
726                 if (vap->va_type == VREG) {
727                         if (np->n_flag & NMODIFIED) {
728                                 if (vap->va_size < np->n_size)
729                                         vap->va_size = np->n_size;
730                                 else
731                                         np->n_size = vap->va_size;
732                         } else {
733                                 np->n_size = vap->va_size;
734                         }
735                         vnode_pager_setsize(vp, np->n_size);
736                 } else {
737                         np->n_size = vap->va_size;
738                 }
739         }
740         bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
741         if (np->n_flag & NCHG) {
742                 if (np->n_flag & NACC)
743                         vaper->va_atime = np->n_atim;
744                 if (np->n_flag & NUPD)
745                         vaper->va_mtime = np->n_mtim;
746         }
747         mtx_unlock(&np->n_mtx);
748 #ifdef NFS_ACDEBUG
749         mtx_unlock(&Giant);     /* nfs_printf() */
750 #endif
751         KDTRACE_NFS_ATTRCACHE_GET_HIT(vp, vap);
752         return (0);
753 }
754
755 /*
756  * Purge all cached information about an NFS vnode including name
757  * cache entries, the attribute cache, and the access cache.  This is
758  * called when an NFS request for a node fails with a stale
759  * filehandle.
760  */
761 void
762 nfs_purgecache(struct vnode *vp)
763 {
764         struct nfsnode *np;
765         int i;
766
767         np = VTONFS(vp);
768         cache_purge(vp);
769         mtx_lock(&np->n_mtx);
770         np->n_attrstamp = 0;
771         KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
772         for (i = 0; i < NFS_ACCESSCACHESIZE; i++)
773                 np->n_accesscache[i].stamp = 0;
774         KDTRACE_NFS_ACCESSCACHE_FLUSH_DONE(vp);
775         mtx_unlock(&np->n_mtx);
776 }
777
778 static nfsuint64 nfs_nullcookie = { { 0, 0 } };
779 /*
780  * This function finds the directory cookie that corresponds to the
781  * logical byte offset given.
782  */
783 nfsuint64 *
784 nfs_getcookie(struct nfsnode *np, off_t off, int add)
785 {
786         struct nfsdmap *dp, *dp2;
787         int pos;
788         nfsuint64 *retval = NULL;
789         
790         pos = (uoff_t)off / NFS_DIRBLKSIZ;
791         if (pos == 0 || off < 0) {
792                 KASSERT(!add, ("nfs getcookie add at <= 0"));
793                 return (&nfs_nullcookie);
794         }
795         pos--;
796         dp = LIST_FIRST(&np->n_cookies);
797         if (!dp) {
798                 if (add) {
799                         dp = malloc(sizeof (struct nfsdmap),
800                                 M_NFSDIROFF, M_WAITOK);
801                         dp->ndm_eocookie = 0;
802                         LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
803                 } else
804                         goto out;
805         }
806         while (pos >= NFSNUMCOOKIES) {
807                 pos -= NFSNUMCOOKIES;
808                 if (LIST_NEXT(dp, ndm_list)) {
809                         if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
810                             pos >= dp->ndm_eocookie)
811                                 goto out;
812                         dp = LIST_NEXT(dp, ndm_list);
813                 } else if (add) {
814                         dp2 = malloc(sizeof (struct nfsdmap),
815                                 M_NFSDIROFF, M_WAITOK);
816                         dp2->ndm_eocookie = 0;
817                         LIST_INSERT_AFTER(dp, dp2, ndm_list);
818                         dp = dp2;
819                 } else
820                         goto out;
821         }
822         if (pos >= dp->ndm_eocookie) {
823                 if (add)
824                         dp->ndm_eocookie = pos + 1;
825                 else
826                         goto out;
827         }
828         retval = &dp->ndm_cookies[pos];
829 out:
830         return (retval);
831 }
832
833 /*
834  * Invalidate cached directory information, except for the actual directory
835  * blocks (which are invalidated separately).
836  * Done mainly to avoid the use of stale offset cookies.
837  */
838 void
839 nfs_invaldir(struct vnode *vp)
840 {
841         struct nfsnode *np = VTONFS(vp);
842
843         KASSERT(vp->v_type == VDIR, ("nfs: invaldir not dir"));
844         nfs_dircookie_lock(np);
845         np->n_direofoffset = 0;
846         np->n_cookieverf.nfsuquad[0] = 0;
847         np->n_cookieverf.nfsuquad[1] = 0;
848         if (LIST_FIRST(&np->n_cookies))
849                 LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0;
850         nfs_dircookie_unlock(np);
851 }
852
853 /*
854  * The write verifier has changed (probably due to a server reboot), so all
855  * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
856  * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
857  * and B_CLUSTEROK flags.  Once done the new write verifier can be set for the
858  * mount point.
859  *
860  * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data
861  * writes are not clusterable.
862  */
863 void
864 nfs_clearcommit(struct mount *mp)
865 {
866         struct vnode *vp, *nvp;
867         struct buf *bp, *nbp;
868         struct bufobj *bo;
869
870         MNT_VNODE_FOREACH_ALL(vp, mp, nvp) {
871                 bo = &vp->v_bufobj;
872                 vholdl(vp);
873                 VI_UNLOCK(vp);
874                 BO_LOCK(bo);
875                 TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) {
876                         if (!BUF_ISLOCKED(bp) &&
877                             (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
878                                 == (B_DELWRI | B_NEEDCOMMIT))
879                                 bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK);
880                 }
881                 BO_UNLOCK(bo);
882                 vdrop(vp);
883         }
884 }
885
886 /*
887  * Helper functions for former macros.  Some of these should be
888  * moved to their callers.
889  */
890
891 int
892 nfsm_mtofh_xx(struct vnode *d, struct vnode **v, int v3, int *f,
893     struct mbuf **md, caddr_t *dpos)
894 {
895         struct nfsnode *ttnp;
896         struct vnode *ttvp;
897         nfsfh_t *ttfhp;
898         u_int32_t *tl;
899         int ttfhsize;
900         int t1;
901
902         if (v3) {
903                 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
904                 if (tl == NULL)
905                         return EBADRPC;
906                 *f = fxdr_unsigned(int, *tl);
907         } else
908                 *f = 1;
909         if (*f) {
910                 t1 = nfsm_getfh_xx(&ttfhp, &ttfhsize, (v3), md, dpos);
911                 if (t1 != 0)
912                         return t1;
913                 t1 = nfs_nget(d->v_mount, ttfhp, ttfhsize, &ttnp, LK_EXCLUSIVE);
914                 if (t1 != 0)
915                         return t1;
916                 *v = NFSTOV(ttnp);
917         }
918         if (v3) {
919                 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
920                 if (tl == NULL)
921                         return EBADRPC;
922                 if (*f)
923                         *f = fxdr_unsigned(int, *tl);
924                 else if (fxdr_unsigned(int, *tl))
925                         nfsm_adv_xx(NFSX_V3FATTR, md, dpos);
926         }
927         if (*f) {
928                 ttvp = *v;
929                 t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 0);
930                 if (t1)
931                         return t1;
932                 *v = ttvp;
933         }
934         return 0;
935 }
936
937 int
938 nfsm_getfh_xx(nfsfh_t **f, int *s, int v3, struct mbuf **md, caddr_t *dpos)
939 {
940         u_int32_t *tl;
941
942         if (v3) {
943                 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
944                 if (tl == NULL)
945                         return EBADRPC;
946                 *s = fxdr_unsigned(int, *tl);
947                 if (*s <= 0 || *s > NFSX_V3FHMAX)
948                         return EBADRPC;
949         } else
950                 *s = NFSX_V2FH;
951         *f = nfsm_dissect_xx(nfsm_rndup(*s), md, dpos);
952         if (*f == NULL)
953                 return EBADRPC;
954         else
955                 return 0;
956 }
957
958
959 int
960 nfsm_loadattr_xx(struct vnode **v, struct vattr *va, struct mbuf **md,
961                  caddr_t *dpos)
962 {
963         int t1;
964
965         struct vnode *ttvp = *v;
966         t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 0);
967         if (t1 != 0)
968                 return t1;
969         *v = ttvp;
970         return 0;
971 }
972
973 int
974 nfsm_postop_attr_xx(struct vnode **v, int *f, struct vattr *va,
975                     struct mbuf **md, caddr_t *dpos)
976 {
977         u_int32_t *tl;
978         int t1;
979
980         struct vnode *ttvp = *v;
981         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
982         if (tl == NULL)
983                 return EBADRPC;
984         *f = fxdr_unsigned(int, *tl);
985         if (*f != 0) {
986                 t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 1);
987                 if (t1 != 0) {
988                         *f = 0;
989                         return t1;
990                 }
991                 *v = ttvp;
992         }
993         return 0;
994 }
995
996 int
997 nfsm_wcc_data_xx(struct vnode **v, int *f, struct mbuf **md, caddr_t *dpos)
998 {
999         u_int32_t *tl;
1000         int ttattrf, ttretf = 0;
1001         int t1;
1002
1003         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1004         if (tl == NULL)
1005                 return EBADRPC;
1006         if (*tl == nfs_true) {
1007                 tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos);
1008                 if (tl == NULL)
1009                         return EBADRPC;
1010                 mtx_lock(&(VTONFS(*v))->n_mtx);
1011                 if (*f)
1012                         ttretf = (VTONFS(*v)->n_mtime.tv_sec == fxdr_unsigned(u_int32_t, *(tl + 2)) && 
1013                                   VTONFS(*v)->n_mtime.tv_nsec == fxdr_unsigned(u_int32_t, *(tl + 3))); 
1014                 mtx_unlock(&(VTONFS(*v))->n_mtx);
1015         }
1016         t1 = nfsm_postop_attr_xx(v, &ttattrf, NULL, md, dpos);
1017         if (t1)
1018                 return t1;
1019         if (*f)
1020                 *f = ttretf;
1021         else
1022                 *f = ttattrf;
1023         return 0;
1024 }
1025
1026 int
1027 nfsm_strtom_xx(const char *a, int s, int m, struct mbuf **mb, caddr_t *bpos)
1028 {
1029         u_int32_t *tl;
1030         int t1;
1031
1032         if (s > m)
1033                 return ENAMETOOLONG;
1034         t1 = nfsm_rndup(s) + NFSX_UNSIGNED;
1035         if (t1 <= M_TRAILINGSPACE(*mb)) {
1036                 tl = nfsm_build_xx(t1, mb, bpos);
1037                 *tl++ = txdr_unsigned(s);
1038                 *(tl + ((t1 >> 2) - 2)) = 0;
1039                 bcopy(a, tl, s);
1040         } else {
1041                 t1 = nfsm_strtmbuf(mb, bpos, a, s);
1042                 if (t1 != 0)
1043                         return t1;
1044         }
1045         return 0;
1046 }
1047
1048 int
1049 nfsm_fhtom_xx(struct vnode *v, int v3, struct mbuf **mb, caddr_t *bpos)
1050 {
1051         u_int32_t *tl;
1052         int t1;
1053         caddr_t cp;
1054
1055         if (v3) {
1056                 t1 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED;
1057                 if (t1 < M_TRAILINGSPACE(*mb)) {
1058                         tl = nfsm_build_xx(t1, mb, bpos);
1059                         *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize);
1060                         *(tl + ((t1 >> 2) - 2)) = 0;
1061                         bcopy(VTONFS(v)->n_fhp, tl, VTONFS(v)->n_fhsize);
1062                 } else {
1063                         t1 = nfsm_strtmbuf(mb, bpos,
1064                             (const char *)VTONFS(v)->n_fhp,
1065                             VTONFS(v)->n_fhsize);
1066                         if (t1 != 0)
1067                                 return t1;
1068                 }
1069         } else {
1070                 cp = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1071                 bcopy(VTONFS(v)->n_fhp, cp, NFSX_V2FH);
1072         }
1073         return 0;
1074 }
1075
1076 void
1077 nfsm_v3attrbuild_xx(struct vattr *va, int full, struct mbuf **mb,
1078     caddr_t *bpos)
1079 {
1080         u_int32_t *tl;
1081
1082         if (va->va_mode != (mode_t)VNOVAL) {
1083                 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
1084                 *tl++ = nfs_true;
1085                 *tl = txdr_unsigned(va->va_mode);
1086         } else {
1087                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
1088                 *tl = nfs_false;
1089         }
1090         if (full && va->va_uid != (uid_t)VNOVAL) {
1091                 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
1092                 *tl++ = nfs_true;
1093                 *tl = txdr_unsigned(va->va_uid);
1094         } else {
1095                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
1096                 *tl = nfs_false;
1097         }
1098         if (full && va->va_gid != (gid_t)VNOVAL) {
1099                 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
1100                 *tl++ = nfs_true;
1101                 *tl = txdr_unsigned(va->va_gid);
1102         } else {
1103                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
1104                 *tl = nfs_false;
1105         }
1106         if (full && va->va_size != VNOVAL) {
1107                 tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos);
1108                 *tl++ = nfs_true;
1109                 txdr_hyper(va->va_size, tl);
1110         } else {
1111                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
1112                 *tl = nfs_false;
1113         }
1114         if (va->va_atime.tv_sec != VNOVAL) {
1115                 if ((va->va_vaflags & VA_UTIMES_NULL) == 0) {
1116                         tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos);
1117                         *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
1118                         txdr_nfsv3time(&va->va_atime, tl);
1119                 } else {
1120                         tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
1121                         *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
1122                 }
1123         } else {
1124                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
1125                 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
1126         }
1127         if (va->va_mtime.tv_sec != VNOVAL) {
1128                 if ((va->va_vaflags & VA_UTIMES_NULL) == 0) {
1129                         tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos);
1130                         *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
1131                         txdr_nfsv3time(&va->va_mtime, tl);
1132                 } else {
1133                         tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
1134                         *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
1135                 }
1136         } else {
1137                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
1138                 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
1139         }
1140 }