]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/nfs4client/nfs4_vnops.c
This commit was generated by cvs2svn to compensate for changes in r133211,
[FreeBSD/FreeBSD.git] / sys / nfs4client / nfs4_vnops.c
1 /* $FreeBSD$ */
2 /* $Id: nfs_vnops.c,v 1.45 2003/11/05 14:59:02 rees Exp $ */
3
4 /*
5  * copyright (c) 2003
6  * the regents of the university of michigan
7  * all rights reserved
8  * 
9  * permission is granted to use, copy, create derivative works and redistribute
10  * this software and such derivative works for any purpose, so long as the name
11  * of the university of michigan is not used in any advertising or publicity
12  * pertaining to the use or distribution of this software without specific,
13  * written prior authorization.  if the above copyright notice or any other
14  * identification of the university of michigan is included in any copy of any
15  * portion of this software, then the disclaimer below must also be included.
16  * 
17  * this software is provided as is, without representation from the university
18  * of michigan as to its fitness for any purpose, and without warranty by the
19  * university of michigan of any kind, either express or implied, including
20  * without limitation the implied warranties of merchantability and fitness for
21  * a particular purpose. the regents of the university of michigan shall not be
22  * liable for any damages, including special, indirect, incidental, or
23  * consequential damages, with respect to any claim arising out of or in
24  * connection with the use of the software, even if it has been or is hereafter
25  * advised of the possibility of such damages.
26  */
27
28 /*
29  * Copyright (c) 1989, 1993
30  *      The Regents of the University of California.  All rights reserved.
31  *
32  * This code is derived from software contributed to Berkeley by
33  * Rick Macklem at The University of Guelph.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  * 4. Neither the name of the University nor the names of its contributors
44  *    may be used to endorse or promote products derived from this software
45  *    without specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57  * SUCH DAMAGE.
58  *
59  *      @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
60  */
61
62 #include <sys/cdefs.h>
63 __FBSDID("$FreeBSD$");
64
65 /*
66  * vnode op calls for Sun NFS version 2 and 3
67  */
68
69 #include "opt_inet.h"
70
71 #include <sys/param.h>
72 #include <sys/kernel.h>
73 #include <sys/systm.h>
74 #include <sys/resourcevar.h>
75 #include <sys/proc.h>
76 #include <sys/mount.h>
77 #include <sys/bio.h>
78 #include <sys/buf.h>
79 #include <sys/malloc.h>
80 #include <sys/mbuf.h>
81 #include <sys/namei.h>
82 #include <sys/socket.h>
83 #include <sys/vnode.h>
84 #include <sys/dirent.h>
85 #include <sys/fcntl.h>
86 #include <sys/lockf.h>
87 #include <sys/stat.h>
88 #include <sys/sysctl.h>
89 #include <sys/lockmgr.h>
90
91 #include <vm/vm.h>
92 #include <vm/vm_extern.h>
93
94 #include <fs/fifofs/fifo.h>
95
96 #include <rpc/rpcclnt.h>
97
98 #include <nfs/rpcv2.h>
99 #include <nfs/nfsproto.h>
100 #include <nfsclient/nfs.h>
101 #include <nfs4client/nfs4.h>
102 #include <nfsclient/nfsnode.h>
103 #include <nfsclient/nfsmount.h>
104 #include <nfsclient/nfs_lock.h>
105 #include <nfs/xdr_subs.h>
106 #include <nfsclient/nfsm_subs.h>
107
108 #include <net/if.h>
109 #include <netinet/in.h>
110 #include <netinet/in_var.h>
111
112 /* NFSv4 */
113 #include <nfs4client/nfs4m_subs.h>
114 #include <nfs4client/nfs4_vn.h>
115
116 /* Defs */
117 #define TRUE    1
118 #define FALSE   0
119
120 /*
121  * Ifdef for FreeBSD-current merged buffer cache. It is unfortunate that these
122  * calls are not in getblk() and brelse() so that they would not be necessary
123  * here.
124  */
125 #ifndef B_VMIO
126 #define vfs_busy_pages(bp, f)
127 #endif
128
129 static int      nfsspec_read(struct vop_read_args *);
130 static int      nfsspec_write(struct vop_write_args *);
131 static int      nfsfifo_read(struct vop_read_args *);
132 static int      nfsfifo_write(struct vop_write_args *);
133 static int      nfsspec_close(struct vop_close_args *);
134 static int      nfsfifo_close(struct vop_close_args *);
135 static int      nfs4_flush(struct vnode *, struct ucred *, int, struct thread *,
136                     int);
137 static int      nfs4_setattrrpc(struct vnode *, struct vattr *, struct ucred *,
138                     struct thread *);
139 static int      nfs4_closerpc(struct vnode *, struct ucred *, struct thread *, int);
140
141 static  int     nfs4_lookup(struct vop_lookup_args *);
142 static  int     nfs4_create(struct vop_create_args *);
143 static  int     nfs4_mknod(struct vop_mknod_args *);
144 static  int     nfs4_open(struct vop_open_args *);
145 static  int     nfs4_close(struct vop_close_args *);
146 static  int     nfs4_access(struct vop_access_args *);
147 static  int     nfs4_getattr(struct vop_getattr_args *);
148 static  int     nfs4_setattr(struct vop_setattr_args *);
149 static  int     nfs4_read(struct vop_read_args *);
150 static  int     nfs4_fsync(struct vop_fsync_args *);
151 static  int     nfs4_remove(struct vop_remove_args *);
152 static  int     nfs4_link(struct vop_link_args *);
153 static  int     nfs4_rename(struct vop_rename_args *);
154 static  int     nfs4_mkdir(struct vop_mkdir_args *);
155 static  int     nfs4_rmdir(struct vop_rmdir_args *);
156 static  int     nfs4_symlink(struct vop_symlink_args *);
157 static  int     nfs4_readdir(struct vop_readdir_args *);
158 static  int     nfs4_strategy(struct vop_strategy_args *);
159 static  int     nfs4_lookitup(struct vnode *, const char *, int,
160                     struct ucred *, struct thread *, struct nfsnode **);
161 static  int     nfs4_sillyrename(struct vnode *, struct vnode *,
162                     struct componentname *);
163 static int      nfsspec_access(struct vop_access_args *);
164 static int      nfs4_readlink(struct vop_readlink_args *);
165 static int      nfs4_print(struct vop_print_args *);
166 static int      nfs4_advlock(struct vop_advlock_args *);
167
168 /*
169  * Global vfs data structures for nfs
170  */
171 vop_t **nfs4_vnodeop_p;
172 static struct vnodeopv_entry_desc nfs4_vnodeop_entries[] = {
173         { &vop_default_desc,            (vop_t *) vop_defaultop },
174         { &vop_access_desc,             (vop_t *) nfs4_access },
175         { &vop_advlock_desc,            (vop_t *) nfs4_advlock },
176         { &vop_close_desc,              (vop_t *) nfs4_close },
177         { &vop_create_desc,             (vop_t *) nfs4_create },
178         { &vop_fsync_desc,              (vop_t *) nfs4_fsync },
179         { &vop_getattr_desc,            (vop_t *) nfs4_getattr },
180         { &vop_getpages_desc,           (vop_t *) nfs_getpages },
181         { &vop_putpages_desc,           (vop_t *) nfs_putpages },
182         { &vop_inactive_desc,           (vop_t *) nfs_inactive },
183         { &vop_lease_desc,              (vop_t *) vop_null },
184         { &vop_link_desc,               (vop_t *) nfs4_link },
185         { &vop_lookup_desc,             (vop_t *) nfs4_lookup },
186         { &vop_mkdir_desc,              (vop_t *) nfs4_mkdir },
187         { &vop_mknod_desc,              (vop_t *) nfs4_mknod },
188         { &vop_open_desc,               (vop_t *) nfs4_open },
189         { &vop_print_desc,              (vop_t *) nfs4_print },
190         { &vop_read_desc,               (vop_t *) nfs4_read },
191         { &vop_readdir_desc,            (vop_t *) nfs4_readdir },
192         { &vop_readlink_desc,           (vop_t *) nfs4_readlink },
193         { &vop_reclaim_desc,            (vop_t *) nfs_reclaim },
194         { &vop_remove_desc,             (vop_t *) nfs4_remove },
195         { &vop_rename_desc,             (vop_t *) nfs4_rename },
196         { &vop_rmdir_desc,              (vop_t *) nfs4_rmdir },
197         { &vop_setattr_desc,            (vop_t *) nfs4_setattr },
198         { &vop_strategy_desc,           (vop_t *) nfs4_strategy },
199         { &vop_symlink_desc,            (vop_t *) nfs4_symlink },
200         { &vop_write_desc,              (vop_t *) nfs_write },
201         { NULL, NULL }
202 };
203 static struct vnodeopv_desc nfs4_vnodeop_opv_desc =
204         { &nfs4_vnodeop_p, nfs4_vnodeop_entries };
205 VNODEOP_SET(nfs4_vnodeop_opv_desc);
206
207 /*
208  * Special device vnode ops
209  */
210 vop_t **spec_nfs4nodeop_p;
211 static struct vnodeopv_entry_desc nfs4_specop_entries[] = {
212         { &vop_default_desc,            (vop_t *) spec_vnoperate },
213         { &vop_access_desc,             (vop_t *) nfsspec_access },
214         { &vop_close_desc,              (vop_t *) nfsspec_close },
215         { &vop_fsync_desc,              (vop_t *) nfs4_fsync },
216         { &vop_getattr_desc,            (vop_t *) nfs4_getattr },
217         { &vop_inactive_desc,           (vop_t *) nfs_inactive },
218         { &vop_print_desc,              (vop_t *) nfs4_print },
219         { &vop_read_desc,               (vop_t *) nfsspec_read },
220         { &vop_reclaim_desc,            (vop_t *) nfs_reclaim },
221         { &vop_setattr_desc,            (vop_t *) nfs4_setattr },
222         { &vop_write_desc,              (vop_t *) nfsspec_write },
223         { NULL, NULL }
224 };
225 static struct vnodeopv_desc spec_nfs4nodeop_opv_desc =
226         { &spec_nfs4nodeop_p, nfs4_specop_entries };
227 VNODEOP_SET(spec_nfs4nodeop_opv_desc);
228
229 vop_t **fifo_nfs4nodeop_p;
230 static struct vnodeopv_entry_desc nfs4_fifoop_entries[] = {
231         { &vop_default_desc,            (vop_t *) fifo_vnoperate },
232         { &vop_access_desc,             (vop_t *) nfsspec_access },
233         { &vop_close_desc,              (vop_t *) nfsfifo_close },
234         { &vop_fsync_desc,              (vop_t *) nfs4_fsync },
235         { &vop_getattr_desc,            (vop_t *) nfs4_getattr },
236         { &vop_inactive_desc,           (vop_t *) nfs_inactive },
237         { &vop_print_desc,              (vop_t *) nfs4_print },
238         { &vop_read_desc,               (vop_t *) nfsfifo_read },
239         { &vop_reclaim_desc,            (vop_t *) nfs_reclaim },
240         { &vop_setattr_desc,            (vop_t *) nfs4_setattr },
241         { &vop_write_desc,              (vop_t *) nfsfifo_write },
242         { NULL, NULL }
243 };
244 static struct vnodeopv_desc fifo_nfs4nodeop_opv_desc =
245         { &fifo_nfs4nodeop_p, nfs4_fifoop_entries };
246 VNODEOP_SET(fifo_nfs4nodeop_opv_desc);
247
248 static int      nfs4_removerpc(struct vnode *dvp, const char *name, int namelen,
249                               struct ucred *cred, struct thread *td);
250 static int      nfs4_renamerpc(struct vnode *fdvp, const char *fnameptr,
251                               int fnamelen, struct vnode *tdvp,
252                               const char *tnameptr, int tnamelen,
253                               struct ucred *cred, struct thread *td);
254 static int      nfs4_renameit(struct vnode *sdvp, struct componentname *scnp,
255                              struct sillyrename *sp);
256 static int      nfs4_openrpc(struct vnode *, struct vnode **,
257                             struct componentname *, int, struct vattr *);
258 static int      nfs4_open_confirm(struct vnode *vp, struct nfs4_compound *cpp,
259                                  struct nfs4_oparg_open *openap,
260                                  struct nfs4_oparg_getfh *gfh,
261                                  struct ucred *cred, struct thread *td);
262 static int      nfs4_createrpc(struct vnode *, struct vnode **,
263                               struct componentname *, nfstype,
264                               struct vattr *, char *);
265
266 /*
267  * Global variables
268  */
269 struct nfs4_lowner nfs4_masterlowner;
270
271 #define DIRHDSIZ        (sizeof (struct dirent) - (MAXNAMLEN + 1))
272
273 SYSCTL_DECL(_vfs_nfs4);
274
275 static int      nfsaccess_cache_timeout = NFS_MAXATTRTIMO;
276 SYSCTL_INT(_vfs_nfs4, OID_AUTO, access_cache_timeout, CTLFLAG_RW,
277            &nfsaccess_cache_timeout, 0, "NFS ACCESS cache timeout");
278
279 static int      nfsv3_commit_on_close = 0;
280 SYSCTL_INT(_vfs_nfs4, OID_AUTO, nfsv3_commit_on_close, CTLFLAG_RW,
281            &nfsv3_commit_on_close, 0, "write+commit on close, else only write");
282 #if 0
283 SYSCTL_INT(_vfs_nfs4, OID_AUTO, access_cache_hits, CTLFLAG_RD,
284            &nfsstats.accesscache_hits, 0, "NFS ACCESS cache hit count");
285
286 SYSCTL_INT(_vfs_nfs4, OID_AUTO, access_cache_misses, CTLFLAG_RD,
287            &nfsstats.accesscache_misses, 0, "NFS ACCESS cache miss count");
288 #endif
289
290 #define NFSV3ACCESS_ALL (NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY          \
291                          | NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE     \
292                          | NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP)
293 static int
294 nfs3_access_otw(struct vnode *vp, int wmode, struct thread *td,
295     struct ucred *cred)
296 {
297         const int v3 = 1;
298         u_int32_t *tl;
299         int error = 0, attrflag;
300
301         return (0);
302
303         struct mbuf *mreq, *mrep = NULL, *md, *mb;
304         caddr_t bpos, dpos;
305         u_int32_t rmode;
306         struct nfsnode *np = VTONFS(vp);
307
308         nfsstats.rpccnt[NFSPROC_ACCESS]++;
309         mreq = nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
310         mb = mreq;
311         bpos = mtod(mb, caddr_t);
312         nfsm_fhtom(vp, v3);
313         tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
314         *tl = txdr_unsigned(wmode);
315         nfsm_request(vp, NFSPROC_ACCESS, td, cred);
316         nfsm_postop_attr(vp, attrflag);
317         if (!error) {
318                 tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
319                 rmode = fxdr_unsigned(u_int32_t, *tl);
320                 np->n_mode = rmode;
321                 np->n_modeuid = cred->cr_uid;
322                 np->n_modestamp = time_second;
323         }
324         m_freem(mrep);
325 nfsmout:
326         return error;
327 }
328
329 /*
330  * nfs access vnode op.
331  * For nfs version 2, just return ok. File accesses may fail later.
332  * For nfs version 3, use the access rpc to check accessibility. If file modes
333  * are changed on the server, accesses might still fail later.
334  */
335 static int
336 nfs4_access(struct vop_access_args *ap)
337 {
338         struct vnode *vp = ap->a_vp;
339         int error = 0;
340         u_int32_t mode, wmode;
341         int v3 = NFS_ISV3(vp);  /* v3 \in v4 */
342         struct nfsnode *np = VTONFS(vp);
343         caddr_t bpos, dpos;
344         struct mbuf *mreq, *mrep = NULL, *md, *mb;
345         struct nfs4_compound cp;
346         struct nfs4_oparg_access acc;
347         struct thread *td = ap->a_td;
348         struct ucred *cred = ap->a_cred;
349
350         /*
351          * Disallow write attempts on filesystems mounted read-only;
352          * unless the file is a socket, fifo, or a block or character
353          * device resident on the filesystem.
354          */
355         if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
356                 switch (vp->v_type) {
357                 case VREG:
358                 case VDIR:
359                 case VLNK:
360                         return (EROFS);
361                 default:
362                         break;
363                 }
364         }
365         /*
366          * For nfs v3, check to see if we have done this recently, and if
367          * so return our cached result instead of making an ACCESS call.
368          * If not, do an access rpc, otherwise you are stuck emulating
369          * ufs_access() locally using the vattr. This may not be correct,
370          * since the server may apply other access criteria such as
371          * client uid-->server uid mapping that we do not know about.
372          */
373         /* XXX Disable this for now; needs fixing of _access_otw() */
374         if (0 && v3) {
375                 if (ap->a_mode & VREAD)
376                         mode = NFSV3ACCESS_READ;
377                 else
378                         mode = 0;
379                 if (vp->v_type != VDIR) {
380                         if (ap->a_mode & VWRITE)
381                                 mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
382                         if (ap->a_mode & VEXEC)
383                                 mode |= NFSV3ACCESS_EXECUTE;
384                 } else {
385                         if (ap->a_mode & VWRITE)
386                                 mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
387                                     NFSV3ACCESS_DELETE);
388                         if (ap->a_mode & VEXEC)
389                                 mode |= NFSV3ACCESS_LOOKUP;
390                 }
391                 /* XXX safety belt, only make blanket request if caching */
392                 if (nfsaccess_cache_timeout > 0) {
393                         wmode = NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY |
394                             NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE |
395                             NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP;
396                 } else {
397                         wmode = mode;
398                 }
399
400                 /*
401                  * Does our cached result allow us to give a definite yes to
402                  * this request?
403                  */
404                 if ((time_second < (np->n_modestamp + nfsaccess_cache_timeout)) &&
405                     (ap->a_cred->cr_uid == np->n_modeuid) &&
406                     ((np->n_mode & mode) == mode)) {
407                         nfsstats.accesscache_hits++;
408                 } else {
409                         /*
410                          * Either a no, or a don't know.  Go to the wire.
411                          */
412                         nfsstats.accesscache_misses++;
413                         error = nfs3_access_otw(vp, wmode, ap->a_td,ap->a_cred);
414                         if (!error) {
415                                 if ((np->n_mode & mode) != mode) {
416                                         error = EACCES;
417                                 }
418                         }
419                 }
420                 return (error);
421         }
422
423         /* XXX use generic access code here? */
424         mode = ap->a_mode & VREAD ? NFSV4ACCESS_READ : 0;
425         if (vp->v_type == VDIR) {
426                 if (ap->a_mode & VWRITE)
427                         mode |= NFSV4ACCESS_MODIFY | NFSV4ACCESS_EXTEND | NFSV4ACCESS_DELETE;
428                 if (ap->a_mode & VEXEC)
429                         mode |= NFSV4ACCESS_LOOKUP;
430         } else {
431                 if (ap->a_mode & VWRITE)
432                         mode |= NFSV4ACCESS_MODIFY | NFSV4ACCESS_EXTEND;
433                 if (ap->a_mode & VEXEC)
434                         mode |= NFSV4ACCESS_EXECUTE;
435         }
436
437         nfs_v4initcompound(&cp);
438         acc.mode = mode;
439
440         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
441         mb = mreq;
442         bpos = mtod(mb, caddr_t);
443
444         nfsm_v4build_compound(&cp, "nfs4_access()");
445         nfsm_v4build_putfh(&cp, vp);
446         nfsm_v4build_access(&cp, &acc);
447         nfsm_v4build_finalize(&cp);
448
449         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
450         if (error != 0)
451                 goto nfsmout;
452
453         nfsm_v4dissect_compound(&cp);
454         nfsm_v4dissect_putfh(&cp);
455         nfsm_v4dissect_access(&cp, &acc);
456
457         if ((acc.rmode & mode) != mode)
458                 error = EACCES;
459
460  nfsmout:
461         error = nfs_v4postop(&cp, error);
462
463         if (mrep != NULL)
464                 m_freem(mrep);
465
466         return (error);
467 }
468
469 static int
470 nfs4_openrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
471     int flags, struct vattr *vap)
472 {
473         struct vnode *vp = *vpp;
474         struct nfs4_oparg_getattr getattr;
475         struct nfs4_oparg_getfh getfh;
476         struct nfs4_oparg_open opena;
477         struct nfs4_compound cp;
478         caddr_t bpos, dpos;
479         int error = 0;
480         struct mbuf *mreq, *mrep = NULL, *md, *mb;
481         struct ucred *cred = cnp->cn_cred;
482         struct thread *td = cnp->cn_thread;
483         struct nfs4_fctx xfc, *fcp;
484         struct nfsnode *np;
485
486         if (vp == NULL) {
487                 /* Create a new file */
488                 np = NULL;
489                 fcp = &xfc;
490                 bzero(fcp, sizeof(*fcp));
491         } else {
492                 np = VTONFS(vp);
493                 fcp = flags & FWRITE ? &np->n_wfc : &np->n_rfc;
494         }
495
496         /*
497          * Since we are currently only one lockowner; we only open the
498          * file once each for reading and writing.
499          */
500         if (fcp->refcnt++ != 0) {
501                 *vpp = vp;
502                 /*printf("not opening %s\n", np->n_name != NULL ? np->n_name : "");*/
503                 return (0);
504         }
505
506         fcp->lop = &nfs4_masterlowner;
507         fcp->np = np;
508
509         nfs_v4initcompound(&cp);
510         cp.nmp = VFSTONFS(dvp->v_mount);
511
512         opena.ctype = NCLNULL;
513         opena.flags = flags;
514         opena.vap = vap;
515         opena.fcp = fcp;                /* For lockowner */
516         opena.cnp = cnp;
517
518         getattr.bm = &nfsv4_getattrbm;
519
520         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
521         mb = mreq;
522         bpos = mtod(mb, caddr_t);
523
524         nfsm_v4build_compound(&cp, "nfs4_openrpc()");
525         nfsm_v4build_putfh(&cp, dvp);
526         nfsm_v4build_open(&cp, &opena);
527         nfsm_v4build_getattr(&cp, &getattr);
528         nfsm_v4build_getfh(&cp, &getfh);
529         nfsm_v4build_finalize(&cp);
530
531         nfsm_request(vp != NULL ? vp : dvp, NFSV4PROC_COMPOUND, td, cred);
532         if (error != 0)
533                 goto nfsmout;
534
535         nfsm_v4dissect_compound(&cp);
536         nfsm_v4dissect_putfh(&cp);
537         nfsm_v4dissect_open(&cp, &opena);
538         nfsm_v4dissect_getattr(&cp, &getattr);
539         nfsm_v4dissect_getfh(&cp, &getfh);
540
541         error = nfs_v4postop(&cp, error);
542
543         if (opena.rflags & NFSV4OPENRES_CONFIRM) {
544                 error = nfs4_open_confirm(vp ? vp : dvp, &cp, &opena, &getfh, cred, td);
545                 if (error != 0)
546                         goto nfsmout;
547         }
548
549         if (vp == NULL) {
550                 /* New file */
551                 error = nfs_nget(dvp->v_mount, &getfh.fh_val,
552                     getfh.fh_len, &np);
553                 if (error != 0)
554                         goto nfsmout;
555
556                 vp = NFSTOV(np);
557                 np->n_dvp = dvp;
558                 np->n_namelen = cnp->cn_namelen; /* XXX memory leaks on these; track! */
559                 if (np->n_name != NULL)
560                         FREE(np->n_name, M_NFSREQ);
561                 MALLOC(np->n_name, u_char *, np->n_namelen + 1, M_NFSREQ, M_WAITOK);
562                 bcopy(cnp->cn_nameptr, np->n_name, np->n_namelen);
563                 np->n_name[np->n_namelen] = '\0';
564                 if (flags & FWRITE)
565                         np->n_wfc = *fcp;
566                 else
567                         np->n_rfc = *fcp;
568
569                 /*printf("opened new file %s\n", np->n_name);*/
570
571                 nfs4_vnop_loadattrcache(vp, &getattr.fa, NULL);
572                 *vpp = vp;
573         } else {
574                 /*printf("openend \"old\" %s\n", np->n_name != NULL ? np->n_name : "");*/
575
576                 if (flags & O_TRUNC && np->n_size != 0) {
577                         struct vattr va;
578
579                         VATTR_NULL(&va);
580                         va.va_size = 0;
581                         error = nfs4_setattrrpc(vp, &va,
582                             cnp->cn_cred, cnp->cn_thread);
583                 }
584                 np->n_attrstamp = 0;
585         }
586
587  nfsmout:
588         if (mrep != NULL)
589                 m_freem(mrep);
590
591         return (error);
592 }
593
594 static int
595 nfs4_open_confirm(struct vnode *vp, struct nfs4_compound *cpp,
596     struct nfs4_oparg_open *openap, struct nfs4_oparg_getfh *gfh,
597     struct ucred *cred, struct thread *td)
598 {
599         caddr_t bpos, dpos;
600         int error = 0;
601         struct mbuf *mreq, *mrep = NULL, *md, *mb;
602
603         nfs_v4initcompound(cpp);
604         cpp->nmp = VFSTONFS(vp->v_mount);
605
606         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
607         mb = mreq;
608         bpos = mtod(mb, caddr_t);
609
610         nfsm_v4build_compound(cpp, "nfs4_open_confirm()");
611         nfsm_v4build_putfh_nv(cpp, gfh);
612         nfsm_v4build_open_confirm(cpp, openap);
613         nfsm_v4build_finalize(cpp);
614
615         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
616         if (error != 0)
617                 goto nfsmout;
618
619         nfsm_v4dissect_compound(cpp);
620         nfsm_v4dissect_putfh(cpp);
621         nfsm_v4dissect_open_confirm(cpp, openap);
622
623  nfsmout:
624         error = nfs_v4postop(cpp, error);
625
626         if (mrep != NULL)
627                 m_freem(mrep);
628
629         return (error);
630 }
631
632
633 /*
634  * nfs open vnode op
635  * Check to see if the type is ok
636  * and that deletion is not in progress.
637  * For paged in text files, you will need to flush the page cache
638  * if consistency is lost.
639  */
640 /* ARGSUSED */
641 static int
642 nfs4_open(struct vop_open_args *ap)
643 {
644         struct vnode *vp = ap->a_vp;
645         struct nfsnode *np = VTONFS(vp);
646         enum vtype vtype = vp->v_type;
647         int mode = ap->a_mode;
648         struct componentname cn;
649
650         if (vtype != VREG) {
651                 if (vtype != VDIR && vtype != VLNK) {
652 #ifdef DIAGNOSTIC
653                         printf("open eacces vtyp=%d\n", vp->v_type);
654 #endif
655                         return (EACCES);
656                 } else
657                         return (0);
658         }
659
660         if (np->n_flag & NCREATED) {
661                 np->n_flag &= ~NCREATED;
662                 return (0);
663         }
664
665         cn.cn_nameptr = np->n_name;
666         cn.cn_namelen = np->n_namelen;
667         cn.cn_cred = ap->a_cred;
668         cn.cn_thread = ap->a_td;
669
670         return (nfs4_openrpc(np->n_dvp, &vp, &cn, mode, NULL));
671 }
672
673 static int
674 nfs4_closerpc(struct vnode *vp, struct ucred *cred, struct thread *td, int flags)
675 {
676         caddr_t bpos, dpos;
677         int error = 0;
678         struct mbuf *mreq, *mrep = NULL, *md, *mb;
679         struct nfs4_fctx *fcp;
680         struct nfs4_compound cp;
681         struct nfsnode *np = VTONFS(vp);
682
683         fcp = flags & FWRITE ? &np->n_wfc : &np->n_rfc;
684
685         nfs_v4initcompound(&cp);
686
687         if (--fcp->refcnt != 0)
688                 return (0);
689
690         /*printf("closing %s\n", np->n_name != NULL ? np->n_name : "");*/
691
692         cp.fcp = fcp;
693
694         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
695         mb = mreq;
696         bpos = mtod(mb, caddr_t);
697
698         nfsm_v4build_compound(&cp, "nfs4_closerpc()");
699         nfsm_v4build_putfh(&cp, vp);
700         nfsm_v4build_close(&cp, fcp);
701         nfsm_v4build_finalize(&cp);
702
703         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
704         if (error != 0)
705                 goto nfsmout;
706
707         nfsm_v4dissect_compound(&cp);
708         nfsm_v4dissect_putfh(&cp);
709         nfsm_v4dissect_close(&cp, fcp);
710
711  nfsmout:
712         error = nfs_v4postop(&cp, error);
713
714         if (mrep != NULL)
715                 m_freem(mrep);
716
717         return (error);
718 }
719
720 /*
721  * nfs close vnode op
722  * play it safe for now (see comments in v2/v3 nfs_close regarding dirty buffers)
723  */
724 /* ARGSUSED */
725 static int
726 nfs4_close(struct vop_close_args *ap)
727 {
728         struct vnode *vp = ap->a_vp;
729         struct nfsnode *np = VTONFS(vp);
730         int error = 0;
731
732         if (vp->v_type != VREG)
733                 return (0);
734
735         if (np->n_flag & NMODIFIED) {
736                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_td);
737                 error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1);
738                 VOP_UNLOCK(vp, 0, ap->a_td);
739                 np->n_attrstamp = 0;
740         }
741
742         error = nfs4_closerpc(vp, ap->a_cred, ap->a_td, ap->a_fflag);
743
744         if (!error && np->n_flag & NWRITEERR) {
745                 np->n_flag &= ~NWRITEERR;
746                 error = np->n_error;
747         }
748         return (error);
749 }
750
751 /*
752  * nfs getattr call from vfs.
753  */
754 static int
755 nfs4_getattr(struct vop_getattr_args *ap)
756 {
757         struct vnode *vp = ap->a_vp;
758         struct nfsnode *np = VTONFS(vp);
759         caddr_t bpos, dpos;
760         int error = 0;
761         struct mbuf *mreq, *mrep = NULL, *md, *mb;
762         struct nfs4_oparg_getattr ga;
763         struct nfs4_compound cp;
764
765         /*
766          * Update local times for special files.
767          */
768         if (np->n_flag & (NACC | NUPD))
769                 np->n_flag |= NCHG;
770         /*
771          * First look in the cache.
772          */
773         if (nfs_getattrcache(vp, ap->a_vap) == 0)
774                 return (0);
775
776         nfsstats.rpccnt[NFSPROC_GETATTR]++;
777
778         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, NFSX_FH(1));
779         mb = mreq;
780         bpos = mtod(mb, caddr_t);
781
782         ga.bm = &nfsv4_getattrbm;
783         nfs_v4initcompound(&cp);
784
785         nfsm_v4build_compound(&cp, "nfs4_getattr()");
786         nfsm_v4build_putfh(&cp, vp);
787         nfsm_v4build_getattr(&cp, &ga);
788         nfsm_v4build_finalize(&cp);
789
790         nfsm_request(vp, NFSV4PROC_COMPOUND, ap->a_td, ap->a_cred);
791         if (error != 0)
792                 goto nfsmout;
793
794         nfsm_v4dissect_compound(&cp);
795         nfsm_v4dissect_putfh(&cp);
796         nfsm_v4dissect_getattr(&cp, &ga);
797
798         nfs4_vnop_loadattrcache(vp, &ga.fa, ap->a_vap);
799
800 nfsmout:
801         error = nfs_v4postop(&cp, error);
802
803         if (mrep != NULL)
804                 m_freem(mrep);
805         return (error);
806 }
807
808 /*
809  * nfs setattr call.
810  */
811 static int
812 nfs4_setattr(struct vop_setattr_args *ap)
813 {
814         struct vnode *vp = ap->a_vp;
815         struct nfsnode *np = VTONFS(vp);
816         struct vattr *vap = ap->a_vap;
817         int error = 0;
818         u_quad_t tsize;
819
820 #ifndef nolint
821         tsize = (u_quad_t)0;
822 #endif
823
824         /*
825          * Setting of flags is not supported.
826          */
827         if (vap->va_flags != VNOVAL)
828                 return (EOPNOTSUPP);
829
830         /*
831          * Disallow write attempts if the filesystem is mounted read-only.
832          */
833         if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
834             vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
835             vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
836             (vp->v_mount->mnt_flag & MNT_RDONLY))
837                 return (EROFS);
838         if (vap->va_size != VNOVAL) {
839                 switch (vp->v_type) {
840                 case VDIR:
841                         return (EISDIR);
842                 case VCHR:
843                 case VBLK:
844                 case VSOCK:
845                 case VFIFO:
846                         if (vap->va_mtime.tv_sec == VNOVAL &&
847                             vap->va_atime.tv_sec == VNOVAL &&
848                             vap->va_mode == (mode_t)VNOVAL &&
849                             vap->va_uid == (uid_t)VNOVAL &&
850                             vap->va_gid == (gid_t)VNOVAL)
851                                 return (0);
852                         vap->va_size = VNOVAL;
853                         break;
854                 default:
855                         /*
856                          * Disallow write attempts if the filesystem is
857                          * mounted read-only.
858                          */
859                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
860                                 return (EROFS);
861
862                         /*
863                          *  We run vnode_pager_setsize() early (why?),
864                          * we must set np->n_size now to avoid vinvalbuf
865                          * V_SAVE races that might setsize a lower
866                          * value.
867                          */
868
869                         tsize = np->n_size;
870                         error = nfs_meta_setsize(vp, ap->a_cred, 
871                                                 ap->a_td, vap->va_size);
872
873                         if (np->n_flag & NMODIFIED) {
874                             if (vap->va_size == 0)
875                                 error = nfs_vinvalbuf(vp, 0,
876                                         ap->a_cred, ap->a_td, 1);
877                             else
878                                 error = nfs_vinvalbuf(vp, V_SAVE,
879                                         ap->a_cred, ap->a_td, 1);
880                             if (error) {
881                                 vnode_pager_setsize(vp, np->n_size);
882                                 return (error);
883                             }
884                         }
885                         /*
886                          * np->n_size has already been set to vap->va_size
887                          * in nfs_meta_setsize(). We must set it again since
888                          * nfs_loadattrcache() could be called through
889                          * nfs_meta_setsize() and could modify np->n_size.
890                          */
891                         np->n_vattr.va_size = np->n_size = vap->va_size;
892                 };
893         } else if ((vap->va_mtime.tv_sec != VNOVAL ||
894                 vap->va_atime.tv_sec != VNOVAL) && (np->n_flag & NMODIFIED) &&
895                 vp->v_type == VREG &&
896                 (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
897                  ap->a_td, 1)) == EINTR)
898                 return (error);
899
900         if (vap->va_size != VNOVAL && np->n_wfc.refcnt == 0) {
901                 /* Have to open the file before we can truncate it */
902                 struct componentname cn;
903
904                 cn.cn_nameptr = np->n_name;
905                 cn.cn_namelen = np->n_namelen;
906                 cn.cn_cred = ap->a_cred;
907                 cn.cn_thread = ap->a_td;
908                 error = nfs4_openrpc(np->n_dvp, &vp, &cn, FWRITE, NULL);
909                 if (error)
910                         return error;
911                 np->n_flag |= NTRUNCATE;
912         }
913
914         error = nfs4_setattrrpc(vp, vap, ap->a_cred, ap->a_td);
915         if (error && vap->va_size != VNOVAL) {
916                 np->n_size = np->n_vattr.va_size = tsize;
917                 vnode_pager_setsize(vp, np->n_size);
918         }
919         return (error);
920 }
921
922 /*
923  * Do an nfs setattr rpc.
924  */
925 static int
926 nfs4_setattrrpc(struct vnode *vp, struct vattr *vap, struct ucred *cred,
927     struct thread *td)
928 {
929         caddr_t bpos, dpos;
930         int error = 0;
931         struct mbuf *mreq, *mrep = NULL, *md, *mb;
932         struct nfs4_compound cp;
933         struct nfs4_oparg_getattr ga;
934         struct nfsnode *np = VTONFS(vp);
935         struct nfs4_fctx *fcp;
936
937         nfsstats.rpccnt[NFSPROC_SETATTR]++;
938         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
939         mb = mreq;
940         bpos = mtod(mb, caddr_t);
941
942         ga.bm = &nfsv4_getattrbm;
943         fcp = (vap->va_size != VNOVAL) ? &np->n_wfc : NULL;
944         nfs_v4initcompound(&cp);
945
946         nfsm_v4build_compound(&cp, "nfs4_setattrrpc");
947         nfsm_v4build_putfh(&cp, vp);
948         nfsm_v4build_setattr(&cp, vap, fcp);
949         nfsm_v4build_getattr(&cp, &ga);
950         nfsm_v4build_finalize(&cp);
951
952         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
953         if (error != 0)
954                 goto nfsmout;
955
956         nfsm_v4dissect_compound(&cp);
957         nfsm_v4dissect_putfh(&cp);
958         nfsm_v4dissect_setattr(&cp);
959         nfsm_v4dissect_getattr(&cp, &ga);
960
961         nfs4_vnop_loadattrcache(vp, &ga.fa, NULL);
962
963         /* TODO: do the settatr and close in a single compound rpc */
964         if (np->n_flag & NTRUNCATE) {
965                 error = nfs4_closerpc(vp, cred, td, FWRITE);
966                 np->n_flag &= ~NTRUNCATE;
967         }
968
969 nfsmout:
970         error = nfs_v4postop(&cp, error);
971
972         if (mrep != NULL)
973                 m_freem(mrep);
974         
975         return (error);
976 }
977
978 /*
979  * nfs lookup call, one step at a time...
980  * First look in cache
981  * If not found, unlock the directory nfsnode and do the rpc
982  */
983 static int
984 nfs4_lookup(struct vop_lookup_args *ap)
985 {
986         struct componentname *cnp = ap->a_cnp;
987         struct vnode *dvp = ap->a_dvp;
988         struct vnode **vpp = ap->a_vpp;
989         int isdot, flags = cnp->cn_flags;
990         struct vnode *newvp;
991         struct nfsmount *nmp;
992         caddr_t bpos, dpos;
993         struct mbuf *mreq, *mrep = NULL, *md, *mb;
994         long len;
995         nfsfh_t *fhp;
996         struct nfsnode *np;
997         int lockparent, wantparent, error = 0, fhsize;
998         struct thread *td = cnp->cn_thread;
999         struct nfs4_compound cp;
1000         struct nfs4_oparg_getattr ga, dga;
1001         struct nfs4_oparg_lookup l;
1002         struct nfs4_oparg_getfh gfh;
1003
1004         *vpp = NULLVP;
1005         cnp->cn_flags &= ~PDIRUNLOCK;
1006         if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
1007             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
1008                 return (EROFS);
1009         if (dvp->v_type != VDIR)
1010                 return (ENOTDIR);
1011         lockparent = flags & LOCKPARENT;
1012         wantparent = flags & (LOCKPARENT|WANTPARENT);
1013         nmp = VFSTONFS(dvp->v_mount);
1014         np = VTONFS(dvp);
1015
1016         isdot = cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.';
1017
1018         if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
1019                 struct vattr vattr;
1020                 int vpid;
1021
1022                 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) {
1023                         *vpp = NULLVP;
1024                         return (error);
1025                 }
1026
1027                 vhold(*vpp);
1028                 newvp = *vpp;
1029                 vpid = newvp->v_id;
1030                 /*
1031                  * See the comment starting `Step through' in ufs/ufs_lookup.c
1032                  * for an explanation of the locking protocol
1033                  */
1034                 if (dvp == newvp) {
1035                         VREF(newvp);
1036                         error = 0;
1037                 } else if (flags & ISDOTDOT) {
1038                         VOP_UNLOCK(dvp, 0, td);
1039                         cnp->cn_flags |= PDIRUNLOCK;
1040                         error = vget(newvp, LK_EXCLUSIVE, td);
1041                         if (!error && lockparent && (flags & ISLASTCN)) {
1042                                 error = vn_lock(dvp, LK_EXCLUSIVE, td);
1043                                 if (error == 0)
1044                                         cnp->cn_flags &= ~PDIRUNLOCK;
1045                         }
1046                 } else {
1047                         error = vget(newvp, LK_EXCLUSIVE, td);
1048                         if (!lockparent || error || !(flags & ISLASTCN)) {
1049                                 VOP_UNLOCK(dvp, 0, td);
1050                                 cnp->cn_flags |= PDIRUNLOCK;
1051                         }
1052                 }
1053                 if (!error) {
1054                         if (vpid == newvp->v_id) {
1055                            if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, td)
1056                             && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
1057                                 nfsstats.lookupcache_hits++;
1058                                 if (cnp->cn_nameiop != LOOKUP &&
1059                                     (flags & ISLASTCN))
1060                                         cnp->cn_flags |= SAVENAME;
1061                                 vdrop(newvp);
1062                                 return (0);
1063                            }
1064                            cache_purge(newvp);
1065                         }
1066                         vput(newvp);
1067                         if (lockparent && dvp != newvp && (flags & ISLASTCN))
1068                                 VOP_UNLOCK(dvp, 0, td);
1069                 }
1070                 vdrop(newvp);
1071                 error = vn_lock(dvp, LK_EXCLUSIVE, td);
1072                 *vpp = NULLVP;
1073                 if (error) {
1074                         cnp->cn_flags |= PDIRUNLOCK;
1075                         return (error);
1076                 }
1077                 cnp->cn_flags &= ~PDIRUNLOCK;
1078         }
1079
1080         error = 0;
1081         newvp = NULLVP;
1082         nfsstats.lookupcache_misses++;
1083         nfsstats.rpccnt[NFSPROC_LOOKUP]++;
1084
1085         len = cnp->cn_namelen;
1086         mreq = nfsm_reqhead(NULL, NFSV4PROC_COMPOUND, 0);
1087         mb = mreq;
1088         bpos = mtod(mb, caddr_t);
1089
1090         ga.bm = &nfsv4_getattrbm;
1091         dga.bm = &nfsv4_getattrbm;
1092         nfs_v4initcompound(&cp);
1093
1094         nfsm_v4build_compound(&cp, "nfs4_lookup()");
1095         nfsm_v4build_putfh(&cp, dvp);
1096         nfsm_v4build_getattr(&cp, &dga);
1097         if (flags & ISDOTDOT)
1098                 nfsm_v4build_lookupp(&cp);
1099         else if (!isdot) {
1100                 l.name = cnp->cn_nameptr;
1101                 l.namelen = len;
1102                 nfsm_v4build_lookup(&cp, &l);
1103         }
1104         nfsm_v4build_getattr(&cp, &ga);
1105         nfsm_v4build_getfh(&cp, &gfh);
1106         nfsm_v4build_finalize(&cp);
1107
1108         nfsm_request(dvp, NFSV4PROC_COMPOUND, cnp->cn_thread, cnp->cn_cred);
1109         if (error != 0)
1110                 goto nfsmout;
1111
1112         nfsm_v4dissect_compound(&cp);
1113         nfsm_v4dissect_putfh(&cp);
1114         nfsm_v4dissect_getattr(&cp, &dga);
1115         if (flags & ISDOTDOT)
1116                 nfsm_v4dissect_lookupp(&cp);
1117         else if (!isdot)
1118                 nfsm_v4dissect_lookup(&cp);
1119         nfsm_v4dissect_getattr(&cp, &ga);
1120         nfsm_v4dissect_getfh(&cp, &gfh);
1121
1122         nfs4_vnop_loadattrcache(dvp, &dga.fa, NULL);
1123         fhp = &gfh.fh_val;
1124         fhsize = gfh.fh_len;
1125
1126         /*
1127          * Handle RENAME case...
1128          */
1129         if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
1130                 if (NFS_CMPFH(np, fhp, fhsize))
1131                         return (EISDIR);
1132
1133                 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
1134                 if (error)
1135                         return (error);
1136
1137                 newvp = NFSTOV(np);
1138
1139                 nfs4_vnop_loadattrcache(newvp, &ga.fa, NULL);
1140
1141                 *vpp = newvp;
1142                 cnp->cn_flags |= SAVENAME;
1143                 if (!lockparent) {
1144                         VOP_UNLOCK(dvp, 0, td);
1145                         cnp->cn_flags |= PDIRUNLOCK;
1146                 }
1147                 return (0);
1148         }
1149
1150         if (flags & ISDOTDOT) {
1151                 VOP_UNLOCK(dvp, 0, td);
1152
1153                 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
1154                 if (error) {
1155                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
1156                         return (error);
1157                 }
1158                 newvp = NFSTOV(np);
1159
1160                 nfs4_vnop_loadattrcache(newvp, &ga.fa, NULL);
1161
1162                 if (lockparent && (flags & ISLASTCN)) {
1163                         error = vn_lock(dvp, LK_EXCLUSIVE, td);
1164                         if (error) {
1165                                 cnp->cn_flags |= PDIRUNLOCK;
1166                                 vput(newvp);
1167                                 return (error);
1168                         }
1169                 } else
1170                         cnp->cn_flags |= PDIRUNLOCK;
1171         } else if (NFS_CMPFH(np, fhp, fhsize)) {
1172                 VREF(dvp);
1173                 newvp = dvp;
1174         } else {
1175                 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
1176                 if (error)
1177                         return (error);
1178
1179                 if (!lockparent || !(flags & ISLASTCN)) {
1180                         cnp->cn_flags |= PDIRUNLOCK;
1181                         VOP_UNLOCK(dvp, 0, td);
1182                 }
1183                 newvp = NFSTOV(np);
1184
1185                 /* Fill in np used by open. */
1186                 np->n_dvp = dvp;
1187                 np->n_namelen = cnp->cn_namelen;
1188                 if (np->n_name != NULL)
1189                         FREE(np->n_name, M_NFSREQ);
1190                 MALLOC(np->n_name, u_char *, np->n_namelen + 1, M_NFSREQ, M_WAITOK);
1191                 bcopy(cnp->cn_nameptr, np->n_name, np->n_namelen);
1192                 np->n_name[np->n_namelen] = '\0';
1193
1194                 nfs4_vnop_loadattrcache(newvp, &ga.fa, NULL);
1195         }
1196
1197         if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
1198                 cnp->cn_flags |= SAVENAME;
1199         if ((cnp->cn_flags & MAKEENTRY) &&
1200             (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
1201                 np->n_ctime = np->n_vattr.va_ctime.tv_sec;
1202                 cache_enter(dvp, newvp, cnp);
1203         }
1204         *vpp = newvp;
1205         m_freem(mrep);
1206 nfsmout:
1207         error = nfs_v4postop(&cp, error);
1208
1209         if (error) {
1210                 if (newvp != NULLVP) {
1211                         vrele(newvp);
1212                         *vpp = NULLVP;
1213                 }
1214                 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
1215                     (flags & ISLASTCN) && error == ENOENT) {
1216                         if (!lockparent) {
1217                                 VOP_UNLOCK(dvp, 0, td);
1218                                 cnp->cn_flags |= PDIRUNLOCK;
1219                         }
1220                         if (dvp->v_mount->mnt_flag & MNT_RDONLY)
1221                                 error = EROFS;
1222                         else
1223                                 error = EJUSTRETURN;
1224                 }
1225                 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
1226                         cnp->cn_flags |= SAVENAME;
1227         }
1228
1229         return (error);
1230 }
1231
1232 /*
1233  * nfs read call.
1234  * Just call nfs_bioread() to do the work.
1235  */
1236 static int
1237 nfs4_read(struct vop_read_args *ap)
1238 {
1239         struct vnode *vp = ap->a_vp;
1240
1241         switch (vp->v_type) {
1242         case VREG:
1243                 return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
1244         case VDIR:
1245                 return (EISDIR);
1246         default:
1247                 return (EOPNOTSUPP);
1248         }
1249 }
1250
1251 /*
1252  * nfs readlink call
1253  */
1254 static int
1255 nfs4_readlink(struct vop_readlink_args *ap)
1256 {
1257         struct vnode *vp = ap->a_vp;
1258
1259         if (vp->v_type != VLNK)
1260                 return (EINVAL);
1261         return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
1262 }
1263
1264 /*
1265  * Do a readlink rpc.
1266  * Called by nfs_doio() from below the buffer cache.
1267  */
1268 int
1269 nfs4_readlinkrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred)
1270 {
1271         caddr_t bpos, dpos;
1272         int error = 0;
1273         struct mbuf *mreq, *mrep = NULL, *md, *mb;
1274         struct nfs4_compound cp;
1275
1276         nfsstats.rpccnt[NFSPROC_READLINK]++;
1277
1278         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
1279         mb = mreq;
1280         bpos = mtod(mb, caddr_t);
1281
1282         nfs_v4initcompound(&cp);
1283
1284         nfsm_v4build_compound(&cp, "nfs4_readlinkrpc()");
1285         nfsm_v4build_putfh(&cp, vp);
1286         nfsm_v4build_readlink(&cp);
1287         nfsm_v4build_finalize(&cp);
1288
1289         nfsm_request(vp, NFSV4PROC_COMPOUND, uiop->uio_td, cred);
1290         if (error != 0)
1291                 goto nfsmout;
1292
1293         nfsm_v4dissect_compound(&cp);
1294         nfsm_v4dissect_putfh(&cp);
1295         nfsm_v4dissect_readlink(&cp, uiop);
1296
1297 nfsmout:
1298         error = nfs_v4postop(&cp, error);
1299
1300         if (m_freem != NULL)
1301                 m_freem(mrep);
1302         return (error);
1303 }
1304
1305 /*
1306  * nfs read rpc call
1307  * Ditto above
1308  */
1309 int
1310 nfs4_readrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred)
1311 {
1312         caddr_t bpos, dpos;
1313         struct mbuf *mreq, *mrep = NULL, *md, *mb;
1314         struct nfsmount *nmp;
1315         int error = 0, len, tsiz;
1316         struct nfs4_compound cp;
1317         struct nfs4_oparg_read read;
1318         struct nfsnode *np = VTONFS(vp);
1319
1320         nmp = VFSTONFS(vp->v_mount);
1321         tsiz = uiop->uio_resid;
1322         if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize)
1323                 return (EFBIG);
1324
1325         if (tsiz == 0)
1326                 return (0);
1327
1328         read.uiop = uiop;
1329         read.fcp = np->n_rfc.refcnt > 0 ? &np->n_rfc : &np->n_wfc;
1330
1331         while (tsiz > 0) {
1332                 nfsstats.rpccnt[NFSPROC_READ]++;
1333                 len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
1334
1335                 read.off = uiop->uio_offset;
1336                 read.maxcnt = len;
1337                 nfs_v4initcompound(&cp);
1338
1339                 mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
1340                 mb = mreq;
1341                 bpos = mtod(mb, caddr_t);
1342
1343                 nfsm_v4build_compound(&cp, "nfs4_readrpc()");
1344                 nfsm_v4build_putfh(&cp, vp);
1345                 nfsm_v4build_read(&cp, &read);
1346                 nfsm_v4build_finalize(&cp);
1347
1348                 nfsm_request(vp, NFSV4PROC_COMPOUND, uiop->uio_td, cred);
1349                 if (error != 0) {
1350                         error = nfs_v4postop(&cp, error);
1351                         goto nfsmout;
1352                 }
1353
1354                 nfsm_v4dissect_compound(&cp);
1355                 nfsm_v4dissect_putfh(&cp);
1356                 nfsm_v4dissect_read(&cp, &read);
1357
1358                 if (read.eof || read.retlen == 0)
1359                         tsiz = 0;
1360                 else
1361                         tsiz -= read.retlen;
1362
1363                 error = nfs_v4postop(&cp, error);
1364
1365                 m_freem(mrep);
1366                 mrep = NULL;
1367         }
1368 nfsmout:
1369         if (mrep != NULL)
1370                 m_freem(mrep);
1371         
1372         return (error);
1373 }
1374
1375 /*
1376  * nfs write call
1377  */
1378 int
1379 nfs4_writerpc(struct vnode *vp, struct uio *uiop, struct ucred *cred,
1380     int *iomode, int *must_commit)
1381 {
1382         int32_t backup;
1383         caddr_t bpos, dpos;
1384         struct mbuf *mreq, *mrep = NULL, *md, *mb;
1385         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1386         int error = 0, len, tsiz, wccflag = 1, rlen;
1387         struct nfs4_compound cp;
1388         struct nfs4_oparg_write write;
1389         nfsv4stablehow commit, committed = NSHFILESYNC;
1390         caddr_t verf;
1391         struct nfsnode *np = VTONFS(vp);
1392
1393 #ifndef DIAGNOSTIC
1394         if (uiop->uio_iovcnt != 1)
1395                 panic("nfs: writerpc iovcnt > 1");
1396 #endif
1397         *must_commit = 0;
1398         tsiz = uiop->uio_resid;
1399         if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize)
1400                 return (EFBIG);
1401
1402         if (tsiz == 0)
1403                 return (0);
1404
1405         write.stable = (nfsv4stablehow)*iomode;
1406         write.uiop = uiop;
1407         write.fcp = &np->n_wfc;
1408
1409         while (tsiz > 0) {
1410                 nfsstats.rpccnt[NFSPROC_WRITE]++;
1411                 len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
1412
1413                 write.off = uiop->uio_offset;
1414                 write.cnt = len;
1415                 nfs_v4initcompound(&cp);
1416
1417                 mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
1418                 mb = mreq;
1419                 bpos = mtod(mb, caddr_t);
1420
1421                 nfsm_v4build_compound(&cp, "nfs4_writerpc()");
1422                 nfsm_v4build_putfh(&cp, vp);
1423                 nfsm_v4build_write(&cp, &write);
1424                 nfsm_v4build_finalize(&cp);
1425
1426                 nfsm_request(vp, NFSV4PROC_COMPOUND, uiop->uio_td, cred);
1427                 if (error != 0) {
1428                         error = nfs_v4postop(&cp, error);
1429                         goto nfsmout;
1430                 }
1431
1432                 nfsm_v4dissect_compound(&cp);
1433                 nfsm_v4dissect_putfh(&cp);
1434                 nfsm_v4dissect_write(&cp, &write);
1435
1436                 rlen = write.retlen;
1437                 if (rlen == 0) {
1438                         error = NFSERR_IO;
1439                         break;
1440                 } else if (rlen < len) {
1441                         backup = len - rlen;
1442                         uiop->uio_iov->iov_base =
1443                             (char *)uiop->uio_iov->iov_base -  backup;
1444                         uiop->uio_iov->iov_len += backup;
1445                         uiop->uio_offset -= backup;
1446                         uiop->uio_resid += backup;
1447                         len = rlen;
1448                 }
1449
1450                 commit = write.committed;
1451
1452                 if (committed == NSHFILESYNC ||
1453                     (committed = NSHDATASYNC && commit == NSHUNSTABLE))
1454                         committed = commit;
1455
1456                 verf = (caddr_t)write.wverf;
1457
1458                 if ((nmp->nm_flag & NFSSTA_HASWRITEVERF) == 0) {
1459                         bcopy(verf, nmp->nm_verf, NFSX_V4VERF);
1460                         nmp->nm_flag |= NFSMNT_HASWRITEVERF;
1461                 } else if (bcmp(verf, nmp->nm_verf, NFSX_V4VERF)) {
1462                         *must_commit = 1;
1463                         bcopy(verf, nmp->nm_verf, NFSX_V4VERF);
1464                 }
1465
1466                 /* XXX wccflag */
1467                 if (wccflag)
1468                         VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
1469
1470                 error = nfs_v4postop(&cp, error);
1471
1472                 m_freem(mrep);
1473                 mrep = NULL;
1474                 if (error)
1475                         break;
1476                 tsiz -= len;
1477         }
1478 nfsmout:
1479         if (mrep != NULL)
1480                 m_freem(mrep);
1481         *iomode = committed;
1482         if (error)
1483                 uiop->uio_resid = tsiz;
1484         return (error);
1485 }
1486
1487 /* ARGSUSED */
1488 static int
1489 nfs4_mknod(struct vop_mknod_args *ap)
1490 {
1491         struct vattr *vap = ap->a_vap;
1492         struct vnode *newvp = NULL;
1493         int error;
1494
1495         error = nfs4_createrpc(ap->a_dvp, &newvp,
1496             ap->a_cnp, (nfstype)vap->va_type, vap, NULL);
1497
1498         /* XXX - is this actually referenced here? */
1499         if (error == 0) {
1500                 *ap->a_vpp = newvp;
1501                 vrele(newvp);
1502         }
1503
1504         return (error);
1505 }
1506
1507 static int
1508 nfs4_createrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
1509     nfstype ftype, struct vattr *vap, char *linktarget)
1510 {
1511         struct nfsnode *dnp = VTONFS(dvp);
1512         struct nfsnode *np = NULL;
1513         struct vnode *newvp = NULL;
1514         struct nfs4_compound cp;
1515         struct nfs4_oparg_create c;
1516         struct nfs4_oparg_getattr ga;
1517         struct nfs4_oparg_getfh gfh;
1518         caddr_t bpos, dpos;
1519         struct mbuf *mreq, *mrep = NULL, *md, *mb;
1520         int error = 0;
1521
1522         nfsstats.rpccnt[NFSPROC_CREATE]++;
1523
1524         mreq = nfsm_reqhead(dvp, NFSV4PROC_COMPOUND, 0);
1525         mb = mreq;
1526         bpos = mtod(mb, caddr_t);
1527
1528         bzero(&c, sizeof(c));
1529         bzero(&ga, sizeof(ga));
1530
1531         c.type = ftype;
1532         c.vap = vap;
1533         c.linktext = linktarget;
1534         c.name = cnp->cn_nameptr;
1535         c.namelen = cnp->cn_namelen;
1536
1537         ga.bm = &nfsv4_getattrbm;
1538         nfs_v4initcompound(&cp);
1539
1540         nfsm_v4build_compound(&cp, "nfs4_createrpc()");
1541         nfsm_v4build_putfh(&cp, dvp);
1542         nfsm_v4build_create(&cp, &c);
1543         nfsm_v4build_getattr(&cp, &ga);
1544         nfsm_v4build_getfh(&cp, &gfh);  
1545         nfsm_v4build_finalize(&cp); 
1546
1547         nfsm_request(dvp, NFSV4PROC_COMPOUND, cnp->cn_thread, cnp->cn_cred);
1548         if (error != 0)
1549                 goto nfsmout;
1550
1551         nfsm_v4dissect_compound(&cp);
1552         nfsm_v4dissect_putfh(&cp);
1553         nfsm_v4dissect_create(&cp, &c);
1554         nfsm_v4dissect_getattr(&cp, &ga);
1555         nfsm_v4dissect_getfh(&cp, &gfh);        
1556         
1557         error = nfs_nget(dvp->v_mount, &gfh.fh_val, gfh.fh_len, &np);
1558         if (error != 0)
1559                 goto nfsmout;
1560
1561         newvp = NFSTOV(np);
1562         nfs4_vnop_loadattrcache(newvp, &ga.fa, NULL);
1563
1564         if (cnp->cn_flags & MAKEENTRY)
1565                 cache_enter(dvp, newvp, cnp);
1566
1567         dnp->n_flag |= NMODIFIED;
1568         dnp->n_attrstamp = 0;
1569
1570  nfsmout:
1571         error = nfs_v4postop(&cp, error);
1572
1573         if (mrep != NULL)
1574                 m_freem(mrep);
1575
1576         /* XXX */
1577         /*FREE(cnp->cn_pnbuf, M_NAMEI);*/
1578         if (error != 0 && newvp != NULL)
1579                 vrele(newvp);
1580         else if (error == 0)
1581                 *vpp = newvp;
1582
1583         return (error);
1584 }
1585
1586 static int
1587 nfs4_renamerpc(struct vnode *fdvp, const char *fnameptr, int fnamelen,
1588     struct vnode *tdvp, const char *tnameptr, int tnamelen,
1589     struct ucred *cred, struct thread *td)
1590 {
1591
1592         struct nfsnode *fnp = VTONFS(fdvp), *tnp = VTONFS(tdvp);
1593         caddr_t bpos, dpos;
1594         struct mbuf *mreq, *mrep = NULL, *md, *mb;
1595         struct nfs4_compound cp;
1596         struct nfs4_oparg_rename r;
1597         int error = 0;
1598
1599         nfsstats.rpccnt[NFSPROC_RENAME]++;
1600
1601         r.fname = fnameptr;
1602         r.fnamelen = fnamelen;
1603         r.tname = tnameptr;
1604         r.tnamelen = tnamelen;
1605         nfs_v4initcompound(&cp);
1606
1607         mreq = nfsm_reqhead(fdvp, NFSV4PROC_COMPOUND, 0);
1608         mb = mreq;
1609         bpos = mtod(mb, caddr_t);
1610
1611         nfsm_v4build_compound(&cp, "nfs4_renamerpc()");
1612         nfsm_v4build_putfh(&cp, fdvp);
1613         nfsm_v4build_savefh(&cp);
1614         nfsm_v4build_putfh(&cp, tdvp);
1615         nfsm_v4build_rename(&cp, &r);
1616         nfsm_v4build_finalize(&cp);
1617
1618         nfsm_request(fdvp, NFSV4PROC_COMPOUND, td, cred);
1619         if (error != 0)
1620                 goto nfsmout;
1621
1622         nfsm_v4dissect_compound(&cp);
1623         nfsm_v4dissect_putfh(&cp);
1624         nfsm_v4dissect_savefh(&cp);
1625         nfsm_v4dissect_putfh(&cp);
1626         nfsm_v4dissect_rename(&cp);
1627
1628         /* XXX should this always be performed?  */
1629         fnp->n_flag |= NMODIFIED;
1630         tnp->n_flag |= NMODIFIED;
1631         fnp->n_attrstamp = tnp->n_attrstamp = 0;
1632
1633  nfsmout:
1634         error = nfs_v4postop(&cp, error);
1635
1636         if (mrep != NULL)
1637                 m_freem(mrep);
1638
1639         return (error);
1640 }
1641
1642 /*
1643  * nfs file create call
1644  */
1645 static int
1646 nfs4_create(struct vop_create_args *ap)
1647 {
1648         struct vnode *dvp = ap->a_dvp;
1649         struct vattr *vap = ap->a_vap;
1650         struct nfsnode *dnp = VTONFS(dvp);
1651         struct componentname *cnp = ap->a_cnp;
1652         struct vnode *newvp = NULL;
1653         int error = 0, fmode = (O_CREAT | FREAD | FWRITE);
1654         struct vattr vattr;
1655
1656         if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread)) != 0)
1657                 return (error);
1658
1659         if (vap->va_vaflags & VA_EXCLUSIVE)
1660                 fmode |= O_EXCL;
1661
1662         error = nfs4_openrpc(dvp, &newvp, cnp, fmode, vap);
1663         if (error != 0)
1664                 goto out;
1665
1666         VTONFS(newvp)->n_flag |= NCREATED;
1667
1668         if (cnp->cn_flags & MAKEENTRY)
1669                 cache_enter(dvp, newvp, cnp);
1670
1671         *ap->a_vpp = newvp;
1672
1673         dnp->n_flag |= NMODIFIED;
1674         dnp->n_attrstamp = 0;   /* XXX; wccflag */
1675
1676  out:
1677         return (error);
1678 }
1679
1680 /*
1681  * nfs file remove call
1682  * To try and make nfs semantics closer to ufs semantics, a file that has
1683  * other processes using the vnode is renamed instead of removed and then
1684  * removed later on the last close.
1685  * - If v_usecount > 1
1686  *        If a rename is not already in the works
1687  *           call nfs4_sillyrename() to set it up
1688  *     else
1689  *        do the remove rpc
1690  */
1691 static int
1692 nfs4_remove(struct vop_remove_args *ap)
1693 {
1694         struct vnode *vp = ap->a_vp;
1695         struct vnode *dvp = ap->a_dvp;
1696         struct componentname *cnp = ap->a_cnp;
1697         struct nfsnode *np = VTONFS(vp);
1698         int error = 0;
1699         struct vattr vattr;
1700
1701 #ifndef DIAGNOSTIC
1702         if ((cnp->cn_flags & HASBUF) == 0)
1703                 panic("nfs4_remove: no name");
1704         if (vrefcnt(vp) < 1)
1705                 panic("nfs4_remove: bad v_usecount");
1706 #endif
1707         if (vp->v_type == VDIR)
1708                 error = EPERM;
1709         else if (vrefcnt(vp) == 1 || (np->n_sillyrename &&
1710             VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_thread) == 0 &&
1711             vattr.va_nlink > 1)) {
1712                 /*
1713                  * Purge the name cache so that the chance of a lookup for
1714                  * the name succeeding while the remove is in progress is
1715                  * minimized. Without node locking it can still happen, such
1716                  * that an I/O op returns ESTALE, but since you get this if
1717                  * another host removes the file..
1718                  */
1719                 cache_purge(vp);
1720                 /*
1721                  * throw away biocache buffers, mainly to avoid
1722                  * unnecessary delayed writes later.
1723                  */
1724                 error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_thread, 1);
1725                 /* Do the rpc */
1726                 if (error != EINTR)
1727                         error = nfs4_removerpc(dvp, cnp->cn_nameptr,
1728                                 cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread);
1729                 /*
1730                  * Kludge City: If the first reply to the remove rpc is lost..
1731                  *   the reply to the retransmitted request will be ENOENT
1732                  *   since the file was in fact removed
1733                  *   Therefore, we cheat and return success.
1734                  */
1735                 if (error == ENOENT)
1736                         error = 0;
1737         } else if (!np->n_sillyrename)
1738                 error = nfs4_sillyrename(dvp, vp, cnp);
1739         np->n_attrstamp = 0;
1740         return (error);
1741 }
1742
1743 /*
1744  * nfs file remove rpc called from nfs_inactive
1745  */
1746 int
1747 nfs4_removeit(struct sillyrename *sp)
1748 {
1749         /*
1750          * Make sure that the directory vnode is still valid.
1751          * XXX we should lock sp->s_dvp here.
1752          */
1753         if (sp->s_dvp->v_type == VBAD)
1754                 return (0);
1755         return (nfs4_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
1756                 NULL));
1757 }
1758
1759 /*
1760  * Nfs remove rpc, called from nfs4_remove() and nfs4_removeit().
1761  */
1762 static int
1763 nfs4_removerpc(struct vnode *dvp, const char *name, int namelen,
1764     struct ucred *cred, struct thread *td)
1765 {
1766         caddr_t bpos, dpos;
1767         int error = 0;
1768         struct mbuf *mreq, *mrep = NULL, *md, *mb;
1769         struct nfs4_compound cp;
1770
1771         nfsstats.rpccnt[NFSPROC_REMOVE]++;
1772
1773         mreq = nfsm_reqhead(dvp, NFSV4PROC_COMPOUND, 0);
1774         mb = mreq;
1775         bpos = mtod(mb, caddr_t);
1776
1777         nfs_v4initcompound(&cp);
1778
1779         nfsm_v4build_compound(&cp, "nfs4_removerpc()");
1780         nfsm_v4build_putfh(&cp, dvp);
1781         nfsm_v4build_remove(&cp, name, namelen);
1782         nfsm_v4build_finalize(&cp);
1783
1784         nfsm_request(dvp, NFSV4PROC_COMPOUND, td, cred);
1785         if (error != 0)
1786                 goto nfsmout;
1787
1788         nfsm_v4dissect_compound(&cp);
1789         nfsm_v4dissect_putfh(&cp);
1790         nfsm_v4dissect_remove(&cp);
1791
1792  nfsmout:
1793         error = nfs_v4postop(&cp, error);
1794
1795         if (mrep != NULL)
1796                 m_freem(mrep);
1797
1798         VTONFS(dvp)->n_flag |= NMODIFIED;
1799         VTONFS(dvp)->n_attrstamp = 0; /* XXX wccflag */
1800
1801         return (error);
1802 }
1803
1804 /*
1805  * nfs file rename call
1806  */
1807 static int
1808 nfs4_rename(struct vop_rename_args *ap)
1809 {
1810         struct vnode *fvp = ap->a_fvp;
1811         struct vnode *tvp = ap->a_tvp;
1812         struct vnode *fdvp = ap->a_fdvp;
1813         struct vnode *tdvp = ap->a_tdvp;
1814         struct componentname *tcnp = ap->a_tcnp;
1815         struct componentname *fcnp = ap->a_fcnp;
1816         int error;
1817
1818  #ifndef DIAGNOSTIC
1819         if ((tcnp->cn_flags & HASBUF) == 0 ||
1820             (fcnp->cn_flags & HASBUF) == 0)
1821                 panic("nfs4_rename: no name");
1822 #endif
1823         /* Check for cross-device rename */
1824         if ((fvp->v_mount != tdvp->v_mount) ||
1825             (tvp && (fvp->v_mount != tvp->v_mount))) {
1826                 error = EXDEV;
1827                 goto out;
1828         }
1829
1830         if (fvp == tvp) {
1831                 printf("nfs4_rename: fvp == tvp (can't happen)\n");
1832                 error = 0;
1833                 goto out;
1834         }
1835         if ((error = vn_lock(fvp, LK_EXCLUSIVE, fcnp->cn_thread)) != 0)
1836                 goto out;
1837
1838         /*
1839          * We have to flush B_DELWRI data prior to renaming
1840          * the file.  If we don't, the delayed-write buffers
1841          * can be flushed out later after the file has gone stale
1842          * under NFSV3.  NFSV2 does not have this problem because
1843          * ( as far as I can tell ) it flushes dirty buffers more
1844          * often.
1845          */
1846         VOP_FSYNC(fvp, fcnp->cn_cred, MNT_WAIT, fcnp->cn_thread);
1847         VOP_UNLOCK(fvp, 0, fcnp->cn_thread);
1848         if (tvp)
1849             VOP_FSYNC(tvp, tcnp->cn_cred, MNT_WAIT, tcnp->cn_thread);
1850
1851         /*
1852          * If the tvp exists and is in use, sillyrename it before doing the
1853          * rename of the new file over it.
1854          * XXX Can't sillyrename a directory.
1855          */
1856         if (tvp && vrefcnt(tvp) > 1 && !VTONFS(tvp)->n_sillyrename &&
1857                 tvp->v_type != VDIR && !nfs4_sillyrename(tdvp, tvp, tcnp)) {
1858                 vput(tvp);
1859                 tvp = NULL;
1860         }
1861
1862         error = nfs4_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
1863                 tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
1864                 tcnp->cn_thread);
1865
1866         if (fvp->v_type == VDIR) {
1867                 if (tvp != NULL && tvp->v_type == VDIR)
1868                         cache_purge(tdvp);
1869                 cache_purge(fdvp);
1870         }
1871
1872 out:
1873         if (tdvp == tvp)
1874                 vrele(tdvp);
1875         else
1876                 vput(tdvp);
1877         if (tvp)
1878                 vput(tvp);
1879         vrele(fdvp);
1880         vrele(fvp);
1881         /*
1882          * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
1883          */
1884         if (error == ENOENT)
1885                 error = 0;
1886         return (error);
1887 }
1888
1889 /*
1890  * nfs file rename rpc called from nfs4_remove() above
1891  */
1892 static int
1893 nfs4_renameit(struct vnode *sdvp, struct componentname *scnp,
1894     struct sillyrename *sp)
1895 {
1896         return (nfs4_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen, sdvp,
1897             sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_thread));
1898 }
1899
1900 /*
1901  * nfs hard link create call
1902  */
1903 static int
1904 nfs4_link(struct vop_link_args *ap)
1905 {
1906         struct vnode *vp = ap->a_vp;
1907         struct vnode *tdvp = ap->a_tdvp;
1908         struct componentname *cnp = ap->a_cnp;
1909         caddr_t bpos, dpos;
1910         int error = 0;
1911         struct mbuf *mreq, *mrep = NULL, *md, *mb;
1912         struct nfs4_compound cp;
1913         struct nfs4_oparg_link l;
1914
1915         if (vp->v_mount != tdvp->v_mount) {
1916                 return (EXDEV);
1917         }
1918
1919         /*
1920          * Push all writes to the server, so that the attribute cache
1921          * doesn't get "out of sync" with the server.
1922          * XXX There should be a better way!
1923          */
1924         VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_thread);
1925
1926         nfsstats.rpccnt[NFSPROC_LINK]++;
1927
1928         l.name = cnp->cn_nameptr;
1929         l.namelen = cnp->cn_namelen;
1930         nfs_v4initcompound(&cp);
1931
1932         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
1933         mb = mreq;
1934         bpos = mtod(mb, caddr_t);
1935
1936         nfsm_v4build_compound(&cp, "nfs4_link()");
1937         nfsm_v4build_putfh(&cp, vp);
1938         nfsm_v4build_savefh(&cp);
1939         nfsm_v4build_putfh(&cp, tdvp);
1940         nfsm_v4build_link(&cp, &l);
1941         nfsm_v4build_finalize(&cp);
1942
1943         nfsm_request(vp, NFSV4PROC_COMPOUND, cnp->cn_thread, cnp->cn_cred);
1944         if (error != 0)
1945                 goto nfsmout;
1946
1947         nfsm_v4dissect_compound(&cp);
1948         nfsm_v4dissect_putfh(&cp);
1949         nfsm_v4dissect_savefh(&cp);
1950         nfsm_v4dissect_putfh(&cp);
1951         nfsm_v4dissect_link(&cp);
1952
1953         VTONFS(tdvp)->n_flag |= NMODIFIED;
1954         VTONFS(vp)->n_attrstamp = 0;
1955         VTONFS(tdvp)->n_attrstamp = 0;
1956
1957 nfsmout:
1958         error = nfs_v4postop(&cp, error);
1959
1960         if (mrep != NULL)
1961                 m_freem(mrep);
1962
1963         return (error);
1964 }
1965
1966 /*
1967  * nfs symbolic link create call
1968  */
1969 static int
1970 nfs4_symlink(struct vop_symlink_args *ap)
1971 {
1972         struct vnode *dvp = ap->a_dvp;
1973         int error = 0;
1974         struct vnode *newvp = NULL;
1975
1976         nfsstats.rpccnt[NFSPROC_SYMLINK]++;
1977
1978         error = nfs4_createrpc(ap->a_dvp, &newvp, ap->a_cnp, NFLNK,
1979             ap->a_vap, ap->a_target);
1980
1981         if (error != 0 && newvp != NULL)
1982                 vput(newvp);
1983         else if (error == 0)
1984                  *ap->a_vpp = newvp;
1985
1986         VTONFS(dvp)->n_flag |= NMODIFIED;
1987         VTONFS(dvp)->n_attrstamp = 0; /* XXX wccflags */
1988
1989         return (error);
1990 }
1991
1992 /*
1993  * nfs make dir call
1994  */
1995 static int
1996 nfs4_mkdir(struct vop_mkdir_args *ap)
1997 {
1998         return (nfs4_createrpc(ap->a_dvp, ap->a_vpp, ap->a_cnp, NFDIR,
1999                     ap->a_vap, NULL));
2000 }
2001
2002 /*
2003  * nfs remove directory call
2004  */
2005 static int
2006 nfs4_rmdir(struct vop_rmdir_args *ap)
2007 {
2008         struct vnode *vp = ap->a_vp;
2009         struct vnode *dvp = ap->a_dvp;
2010         struct nfsnode *dnp = VTONFS(dvp);
2011         struct componentname *cnp = ap->a_cnp;
2012         int error = 0;
2013
2014         if (dvp == vp)
2015                 return (EINVAL);
2016
2017         error = (nfs4_removerpc(dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred,
2018                                NULL));
2019         if (error)
2020                 return (error);
2021
2022         dnp->n_flag |= NMODIFIED;
2023         dnp->n_attrstamp = 0;
2024         cache_purge(dvp);
2025         cache_purge(vp);
2026
2027         return (error);
2028 }
2029
2030 /*
2031  * nfs readdir call
2032  */
2033 static int
2034 nfs4_readdir(struct vop_readdir_args *ap)
2035 {
2036         struct vnode *vp = ap->a_vp;
2037         struct nfsnode *np = VTONFS(vp);
2038         struct uio *uio = ap->a_uio;
2039         int tresid, error;
2040         struct vattr vattr;
2041
2042         if (vp->v_type != VDIR)
2043                 return (EPERM);
2044         /*
2045          * First, check for hit on the EOF offset cache
2046          */
2047         if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset &&
2048             (np->n_flag & NMODIFIED) == 0) {
2049                 if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_td) == 0 &&
2050                         np->n_mtime == vattr.va_mtime.tv_sec) {
2051                         nfsstats.direofcache_hits++;
2052                         return (0);
2053                 }
2054         }
2055
2056         /*
2057          * Call nfs_bioread() to do the real work.
2058          */
2059         tresid = uio->uio_resid;
2060         error = nfs_bioread(vp, uio, 0, ap->a_cred);
2061
2062         if (!error && uio->uio_resid == tresid)
2063                 nfsstats.direofcache_misses++;
2064         return (error);
2065 }
2066
2067 static u_char fty_to_dty[] = {
2068         DT_UNKNOWN,             /* NFNON */
2069         DT_REG,                 /* NFREG */
2070         DT_DIR,                 /* NFDIR */
2071         DT_BLK,                 /* NFBLK */
2072         DT_CHR,                 /* NFCHR */
2073         DT_LNK,                 /* NFLNK */
2074         DT_SOCK,                /* NFSOCK */
2075         DT_FIFO,                /* NFFIFO */
2076         DT_UNKNOWN,             /* NFATTRDIT */
2077         DT_UNKNOWN,             /* NFNAMEDATTR */
2078         DT_UNKNOWN,             /* NFBAD */
2079 };
2080
2081 /*
2082  * Readdir rpc call.
2083  * Called from below the buffer cache by nfs_doio().
2084  */
2085 int
2086 nfs4_readdirrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred)
2087 {
2088         int len, left;
2089         struct dirent *dp = NULL;
2090         u_int32_t *tl;
2091         caddr_t p;
2092         uint64_t *cookiep;
2093         caddr_t bpos, dpos;
2094         struct mbuf *mreq, *mrep = NULL, *md, *mb;
2095         uint64_t cookie;
2096         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2097         struct nfsnode *dnp = VTONFS(vp);
2098         int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2099         struct nfs4_compound cp;
2100         struct nfs4_oparg_readdir readdir;
2101         struct nfsv4_fattr fattr;
2102         u_int fty;
2103
2104 #ifndef DIAGNOSTIC
2105         if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) ||
2106                 (uiop->uio_resid & (DIRBLKSIZ - 1)))
2107                 panic("nfs readdirrpc bad uio");
2108 #endif
2109
2110         /*
2111          * If there is no cookie, assume directory was stale.
2112          */
2113         cookiep = nfs4_getcookie(dnp, uiop->uio_offset, 0);
2114         if (cookiep)
2115                 cookie = *cookiep;
2116         else
2117                 return (NFSERR_BAD_COOKIE);
2118
2119         /* Generate fake entries for "." and ".." */
2120         while (cookie < 2 && bigenough) {
2121                 cookie++;
2122                 len = 4 + DIRHDSIZ;
2123
2124                 if (len > uiop->uio_resid) {
2125                         bigenough = 0;
2126                         break;
2127                 }
2128                 dp = (struct dirent *)uiop->uio_iov->iov_base;
2129
2130                 dp->d_namlen = cookie;
2131                 dp->d_reclen = len;
2132                 dp->d_type = DT_DIR;
2133                 if (cookie == 1)
2134                         dp->d_fileno = dnp->n_vattr.va_fileid; /* XXX has problems with pynfs virtualhandles */
2135                 else
2136                         dp->d_fileno = dnp->n_dvp != NULL ?
2137                             VTONFS(dnp->n_dvp)->n_vattr.va_fileid : cookie;
2138
2139                 p = dp->d_name;
2140                 *p++ = '.';
2141                 if (cookie == 2)
2142                         *p++ = '.';
2143                 *p = '\0';
2144
2145                 blksiz += len;
2146                 if (blksiz == DIRBLKSIZ)
2147                         blksiz = 0;
2148                 uiop->uio_offset += len;
2149                 uiop->uio_resid -= len;
2150                 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + len;
2151                 uiop->uio_iov->iov_len -= len;
2152         }
2153
2154         if (cookie == 2)
2155                 cookie = 0;
2156
2157         /* This is sort of ugly, to prevent v4postop() from acting weird */
2158         bzero(&cp, sizeof(cp));
2159
2160         /*
2161          * Loop around doing readdir rpc's of size nm_readdirsize
2162          * truncated to a multiple of DIRBLKSIZ.
2163          * The stopping criteria is EOF or buffer full.
2164          */
2165         /*
2166          * XXX this is sort of ugly for nfsv4; we don't maintain the
2167          * strict abstraction, but do the decoding inline.  that's ok.
2168          */
2169         while (more_dirs && bigenough) {
2170                 nfsstats.rpccnt[NFSPROC_READDIR]++;
2171
2172                 mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
2173                 mb = mreq;
2174                 bpos = mtod(mb, caddr_t);
2175
2176                 readdir.cnt = nmp->nm_readdirsize;
2177                 readdir.cookie = cookie;
2178                 readdir.bm = &nfsv4_readdirbm;
2179                 if (cookie == 0)
2180                         bzero(&readdir.verf, sizeof(readdir.verf));
2181                 else
2182                         bcopy(&dnp->n_cookieverf, &readdir.verf,
2183                             sizeof(readdir.verf));
2184
2185                 nfs_v4initcompound(&cp);
2186
2187                 nfsm_v4build_compound(&cp, "nfs4_readdirrpc()");
2188                 nfsm_v4build_putfh(&cp, vp);
2189                 nfsm_v4build_readdir(&cp, &readdir);
2190                 nfsm_v4build_finalize(&cp);
2191
2192                 nfsm_request(vp, NFSV4PROC_COMPOUND, uiop->uio_td, cred);
2193                 if (error != 0)
2194                         goto nfsmout;
2195
2196                 nfsm_v4dissect_compound(&cp);
2197                 nfsm_v4dissect_putfh(&cp);
2198
2199                 /*
2200                  * XXX - Readdir gets handled inline like in
2201                  * NFSv{2,3}.  This is a nasty inconsistency and
2202                  * should be fixed.
2203                  */
2204
2205                 tl = nfsm_dissect(uint32_t *, 5 * NFSX_UNSIGNED);
2206                 if (fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_READDIR) {
2207                         error = EBADRPC;
2208                         goto nfsmout;
2209                 }
2210                 if (fxdr_unsigned(uint32_t, *tl++) != 0) {
2211                         error = EBADRPC;
2212                         goto nfsmout;
2213                 }
2214
2215                 bcopy(tl, &dnp->n_cookieverf, NFSX_V4VERF);
2216                 tl += 2;
2217                 more_dirs = fxdr_unsigned(int, *tl++);
2218
2219                 /* loop thru the dir entries, doctoring them to 4bsd form */
2220                 while (more_dirs && bigenough) {
2221                         tl = nfsm_dissect(uint32_t *, 3 * NFSX_UNSIGNED);
2222                         cookie = fxdr_hyper(tl);
2223                         tl += 2;
2224                         /* XXX cookie sanity check */
2225                         len = fxdr_unsigned(int, *tl++);
2226                         if (len <= 0 || len > NFS_MAXNAMLEN) {
2227                                 error = EBADRPC;
2228                                 goto nfsmout;
2229                         }
2230                         tlen = nfsm_rndup(len);
2231                         if (tlen == len)
2232                                 tlen += 4;      /* To ensure null termination */
2233                         left = DIRBLKSIZ - blksiz;
2234                         if ((tlen + DIRHDSIZ) > left) {
2235                                 dp->d_reclen += left;
2236                                 uiop->uio_iov->iov_base =
2237                                     (char *)uiop->uio_iov->iov_base + left;
2238                                 uiop->uio_iov->iov_len -= left;
2239                                 uiop->uio_offset += left;
2240                                 uiop->uio_resid -= left;
2241                                 blksiz = 0;
2242                         }
2243                         if ((tlen + DIRHDSIZ) > uiop->uio_resid)
2244                                 bigenough = 0;
2245                         if (bigenough) {
2246                                 dp = (struct dirent *)uiop->uio_iov->iov_base;
2247
2248                                 dp->d_namlen = len;
2249                                 dp->d_reclen = tlen + DIRHDSIZ;
2250
2251                                 blksiz += dp->d_reclen;
2252                                 if (blksiz == DIRBLKSIZ)
2253                                         blksiz = 0;
2254                                 uiop->uio_offset += DIRHDSIZ;
2255                                 uiop->uio_resid -= DIRHDSIZ;
2256                                 uiop->uio_iov->iov_base =
2257                                     (char *)uiop->uio_iov->iov_base + DIRHDSIZ;
2258                                 uiop->uio_iov->iov_len -= DIRHDSIZ;
2259
2260                                 /* Copy name */
2261                                 nfsm_mtouio(uiop, len);
2262                                 p = uiop->uio_iov->iov_base;
2263                                 tlen -= len;
2264                                 *p = '\0';      /* null terminate */
2265                                 /* printf("nfs4_readdirrpc: name: \"%s\" cookie %d\n",
2266                                    p - len, (int) cookie);*/
2267                                 uiop->uio_iov->iov_base =
2268                                     (char *)uiop->uio_iov->iov_base + tlen;
2269                                 uiop->uio_iov->iov_len -= tlen;
2270                                 uiop->uio_offset += tlen;
2271                                 uiop->uio_resid -= tlen;
2272
2273                                 /* Copy attributes */
2274                                 nfsm_v4dissect_attrs(&fattr);
2275
2276                                 dp->d_fileno = nfs_v4fileid4_to_fileid(
2277                                         fattr.fa4_valid & FA4V_FILEID &&
2278                                             fattr.fa4_fileid ?
2279                                             fattr.fa4_fileid : cookie);
2280
2281                                 fty = (u_int)fattr.fa4_type;
2282                                 dp->d_type = fattr.fa4_valid & FA4V_TYPE &&
2283                                     (fty < sizeof(fty_to_dty)) ?
2284                                     fty_to_dty[fty] : DT_UNKNOWN;
2285                         } else
2286                                 nfsm_adv(nfsm_rndup(len));
2287
2288                         tl = nfsm_dissect(uint32_t *, NFSX_UNSIGNED);
2289                         more_dirs = fxdr_unsigned(int, *tl++);
2290                 }
2291                 /*
2292                  * If at end of rpc data, get the eof boolean
2293                  */
2294                 if (!more_dirs) {
2295                         tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
2296                         more_dirs = (fxdr_unsigned(int, *tl) == 0);
2297                 }
2298
2299                 error = nfs_v4postop(&cp, error);
2300
2301                 m_freem(mrep);
2302                 mrep = NULL;
2303         }
2304         /*
2305          * Fill last record, iff any, out to a multiple of DIRBLKSIZ
2306          * by increasing d_reclen for the last record.
2307          */
2308         if (blksiz > 0) {
2309                 left = DIRBLKSIZ - blksiz;
2310                 dp->d_reclen += left;
2311                 uiop->uio_iov->iov_base =
2312                     (char *)uiop->uio_iov->iov_base + left;
2313                 uiop->uio_iov->iov_len -= left;
2314                 uiop->uio_offset += left;
2315                 uiop->uio_resid -= left;
2316         }
2317
2318         /*
2319          * We are now either at the end of the directory or have filled the
2320          * block.
2321          */
2322         if (bigenough)
2323                 dnp->n_direofoffset = uiop->uio_offset;
2324         else {
2325                 if (uiop->uio_resid > 0)
2326                         printf("EEK! readdirrpc resid > 0\n");
2327                 cookiep = nfs4_getcookie(dnp, uiop->uio_offset, 1);
2328                 *cookiep = cookie;
2329         }
2330 nfsmout:
2331         if (mrep != NULL)
2332                 m_freem(mrep);
2333         return (error);
2334 }
2335
2336 /*
2337  * Silly rename. To make the NFS filesystem that is stateless look a little
2338  * more like the "ufs" a remove of an active vnode is translated to a rename
2339  * to a funny looking filename that is removed by nfs_inactive on the
2340  * nfsnode. There is the potential for another process on a different client
2341  * to create the same funny name between the nfs_lookitup() fails and the
2342  * nfs_rename() completes, but...
2343  */
2344 static int
2345 nfs4_sillyrename(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
2346 {
2347         struct sillyrename *sp;
2348         struct nfsnode *np;
2349         int error;
2350         short pid;
2351
2352         cache_purge(dvp);
2353         np = VTONFS(vp);
2354 #ifndef DIAGNOSTIC
2355         if (vp->v_type == VDIR)
2356                 panic("nfs: sillyrename dir");
2357 #endif
2358         MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
2359                 M_NFSREQ, M_WAITOK);
2360         sp->s_cred = crhold(cnp->cn_cred);
2361         sp->s_dvp = dvp;
2362         sp->s_removeit = nfs4_removeit;
2363         VREF(dvp);
2364
2365         /* Fudge together a funny name */
2366         pid = cnp->cn_thread->td_proc->p_pid;
2367         sp->s_namlen = sprintf(sp->s_name, ".nfsA%04x4.4", pid);
2368
2369         /* Try lookitups until we get one that isn't there */
2370         while (nfs4_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
2371                 cnp->cn_thread, NULL) == 0) {
2372                 sp->s_name[4]++;
2373                 if (sp->s_name[4] > 'z') {
2374                         error = EINVAL;
2375                         goto bad;
2376                 }
2377         }
2378         error = nfs4_renameit(dvp, cnp, sp);
2379         if (error)
2380                 goto bad;
2381         error = nfs4_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
2382                 cnp->cn_thread, &np);
2383         np->n_sillyrename = sp;
2384         return (0);
2385 bad:
2386         vrele(sp->s_dvp);
2387         crfree(sp->s_cred);
2388         free((caddr_t)sp, M_NFSREQ);
2389         return (error);
2390 }
2391
2392 /*
2393  * Look up a file name and optionally either update the file handle or
2394  * allocate an nfsnode, depending on the value of npp.
2395  * npp == NULL  --> just do the lookup
2396  * *npp == NULL --> allocate a new nfsnode and make sure attributes are
2397  *                      handled too
2398  * *npp != NULL --> update the file handle in the vnode
2399  */
2400 static int
2401 nfs4_lookitup(struct vnode *dvp, const char *name, int len, struct ucred *cred,
2402     struct thread *td, struct nfsnode **npp)
2403 {
2404         struct vnode *newvp = NULL;
2405         struct nfsnode *np, *dnp = VTONFS(dvp);
2406         caddr_t bpos, dpos;
2407         int error = 0, fhlen;
2408         struct mbuf *mreq, *mrep = NULL, *md, *mb;
2409         nfsfh_t *nfhp;
2410         struct nfs4_compound cp;
2411         struct nfs4_oparg_lookup l;
2412         struct nfs4_oparg_getfh gfh;
2413         struct nfs4_oparg_getattr ga;
2414
2415         nfsstats.rpccnt[NFSPROC_RENAME]++;
2416
2417         mreq = nfsm_reqhead(dvp, NFSV4PROC_COMPOUND, 0);
2418         mb = mreq;
2419         bpos = mtod(mb, caddr_t);
2420
2421         l.name = name;
2422         l.namelen = len;
2423
2424         nfs_v4initcompound(&cp);
2425
2426         ga.bm = &nfsv4_getattrbm;
2427
2428         nfsm_v4build_compound(&cp, "nfs4_renamerpc()");
2429         nfsm_v4build_putfh(&cp, dvp);
2430         nfsm_v4build_lookup(&cp, &l);
2431         nfsm_v4build_getfh(&cp, &gfh);
2432         nfsm_v4build_getattr(&cp, &ga);
2433
2434         nfsm_request(dvp, NFSV4PROC_COMPOUND, td, cred);
2435         if (error != 0)
2436                 goto nfsmout;
2437
2438         nfsm_v4dissect_compound(&cp);
2439         nfsm_v4dissect_putfh(&cp);
2440         nfsm_v4dissect_lookup(&cp);
2441         nfsm_v4dissect_getfh(&cp, &gfh);
2442         nfsm_v4dissect_getattr(&cp, &ga);
2443
2444         if (npp != NULL && error == 0) {
2445                 nfhp = &gfh.fh_val;
2446                 fhlen = gfh.fh_len;
2447
2448                 if (*npp != NULL) {
2449                         np = *npp;
2450                         if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
2451                                 free((caddr_t)np->n_fhp, M_NFSBIGFH);
2452                                 np->n_fhp = &np->n_fh;
2453                         } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH)
2454                                 np->n_fhp =(nfsfh_t *)malloc(fhlen, M_NFSBIGFH, M_WAITOK);
2455                         bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen);
2456                         np->n_fhsize = fhlen;
2457                         newvp = NFSTOV(np);
2458                 } else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
2459                         VREF(dvp);
2460                         newvp = dvp;
2461                 } else {
2462                         error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
2463                         if (error) {
2464                                 m_freem(mrep);
2465                                 return (error);
2466                         }
2467                         newvp = NFSTOV(np);
2468                 }
2469
2470                 if (newvp != dvp) {
2471                         np->n_dvp = dvp;
2472                         np->n_namelen = len;
2473                         if (np->n_name != NULL)
2474                                 FREE(np->n_name, M_NFSREQ);
2475                         MALLOC(np->n_name, u_char *,
2476                             np->n_namelen + 1, M_NFSREQ, M_WAITOK);
2477                         memcpy(np->n_name, name, len);
2478                         np->n_name[len] = '\0';
2479                 }
2480                 nfs4_vnop_loadattrcache(newvp, &ga.fa, NULL);
2481         }
2482
2483 nfsmout:
2484         error = nfs_v4postop(&cp, error);
2485
2486         if (mrep != NULL)
2487                 m_freem(mrep);
2488         if (npp && *npp == NULL) {
2489                 if (error) {
2490                         if (newvp) {
2491                                 if (newvp == dvp)
2492                                         vrele(newvp);
2493                                 else
2494                                         vput(newvp);
2495                         }
2496                 } else
2497                         *npp = np;
2498         }
2499
2500
2501         return (error);
2502 }
2503
2504 /*
2505  * Nfs Version 3 commit rpc
2506  */
2507 int
2508 nfs4_commit(struct vnode *vp, u_quad_t offset, int cnt, struct ucred *cred,
2509     struct thread *td)
2510 {
2511         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2512         caddr_t bpos, dpos;
2513         int error = 0;
2514         struct mbuf *mreq, *mrep = NULL, *md, *mb;
2515         struct nfs4_compound cp;
2516         struct nfs4_oparg_commit commit;
2517
2518         if ((nmp->nm_state & NFSSTA_HASWRITEVERF) == 0)
2519                 return (0);
2520         nfsstats.rpccnt[NFSPROC_COMMIT]++;
2521
2522         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
2523         mb = mreq;
2524         bpos = mtod(mb, caddr_t);
2525
2526         commit.start = offset;
2527         commit.len = cnt;
2528
2529         nfs_v4initcompound(&cp);
2530
2531         nfsm_v4build_compound(&cp, "nfs4_commit()");
2532         nfsm_v4build_putfh(&cp, vp);
2533         nfsm_v4build_commit(&cp, &commit);
2534         nfsm_v4build_finalize(&cp);
2535
2536         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
2537         if (error != 0)
2538                 goto nfsmout;
2539
2540         nfsm_v4dissect_compound(&cp);
2541         nfsm_v4dissect_putfh(&cp);
2542         nfsm_v4dissect_commit(&cp, &commit);
2543         
2544         /* XXX */
2545         /* nfsm_wcc_data(vp, wccflag);*/
2546         if (bcmp(nmp->nm_verf, commit.verf, NFSX_V4VERF)) {
2547                 bcopy(commit.verf, nmp->nm_verf, NFSX_V4VERF);
2548                 error = NFSERR_STALEWRITEVERF;
2549         }
2550
2551 nfsmout:
2552         error = nfs_v4postop(&cp, error);
2553
2554         if (mrep == NULL)
2555                 m_freem(mrep);
2556         return (error);
2557 }
2558
2559 /*
2560  * Strategy routine.
2561  * For async requests when nfsiod(s) are running, queue the request by
2562  * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
2563  * request.
2564  */
2565 static int
2566 nfs4_strategy(struct vop_strategy_args *ap)
2567 {
2568         struct buf *bp = ap->a_bp;
2569         struct ucred *cr;
2570         struct thread *td;
2571         int error = 0;
2572
2573         KASSERT(ap->a_vp == ap->a_bp->b_vp, ("%s(%p != %p)",
2574             __func__, ap->a_vp, ap->a_bp->b_vp));
2575         KASSERT(!(bp->b_flags & B_DONE), ("nfs4_strategy: buffer %p unexpectedly marked B_DONE", bp));
2576         KASSERT(BUF_REFCNT(bp) > 0, ("nfs4_strategy: buffer %p not locked", bp));
2577
2578         if (bp->b_flags & B_ASYNC)
2579                 td = NULL;
2580         else
2581                 td = curthread; /* XXX */
2582
2583         if (bp->b_iocmd == BIO_READ)
2584                 cr = bp->b_rcred;
2585         else
2586                 cr = bp->b_wcred;
2587
2588         /*
2589          * If the op is asynchronous and an i/o daemon is waiting
2590          * queue the request, wake it up and wait for completion
2591          * otherwise just do it ourselves.
2592          */
2593         if ((bp->b_flags & B_ASYNC) == 0 ||
2594                 nfs_asyncio(bp, NOCRED, td))
2595                 error = nfs_doio(bp, cr, td);
2596         return (error);
2597 }
2598
2599 /*
2600  * fsync vnode op. Just call nfs4_flush() with commit == 1.
2601  */
2602 /* ARGSUSED */
2603 static int
2604 nfs4_fsync(struct vop_fsync_args *ap)
2605 {
2606         return (nfs4_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));
2607 }
2608
2609 /*
2610  * Flush all the blocks associated with a vnode.
2611  *      Walk through the buffer pool and push any dirty pages
2612  *      associated with the vnode.
2613  */
2614 static int
2615 nfs4_flush(struct vnode *vp, struct ucred *cred, int waitfor, struct thread *td,
2616     int commit)
2617 {
2618         struct nfsnode *np = VTONFS(vp);
2619         struct buf *bp;
2620         int i;
2621         struct buf *nbp;
2622         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2623         int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
2624         int passone = 1;
2625         u_quad_t off, endoff, toff;
2626         struct ucred* wcred = NULL;
2627         struct buf **bvec = NULL;
2628 #ifndef NFS_COMMITBVECSIZ
2629 #define NFS_COMMITBVECSIZ       20
2630 #endif
2631         struct buf *bvec_on_stack[NFS_COMMITBVECSIZ];
2632         int bvecsize = 0, bveccount;
2633
2634         if (nmp->nm_flag & NFSMNT_INT)
2635                 slpflag = PCATCH;
2636         if (!commit)
2637                 passone = 0;
2638         /*
2639          * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the
2640          * server, but nas not been committed to stable storage on the server
2641          * yet. On the first pass, the byte range is worked out and the commit
2642          * rpc is done. On the second pass, nfs_writebp() is called to do the
2643          * job.
2644          */
2645 again:
2646         off = (u_quad_t)-1;
2647         endoff = 0;
2648         bvecpos = 0;
2649         if (NFS_ISV3(vp) && commit) {
2650                 s = splbio();
2651                 if (bvec != NULL && bvec != bvec_on_stack)
2652                         free(bvec, M_TEMP);
2653                 /*
2654                  * Count up how many buffers waiting for a commit.
2655                  */
2656                 bveccount = 0;
2657                 VI_LOCK(vp);
2658                 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
2659                         nbp = TAILQ_NEXT(bp, b_vnbufs);
2660                         if (BUF_REFCNT(bp) == 0 &&
2661                             (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
2662                                 == (B_DELWRI | B_NEEDCOMMIT))
2663                                 bveccount++;
2664                 }
2665                 /*
2666                  * Allocate space to remember the list of bufs to commit.  It is
2667                  * important to use M_NOWAIT here to avoid a race with nfs4_write.
2668                  * If we can't get memory (for whatever reason), we will end up
2669                  * committing the buffers one-by-one in the loop below.
2670                  */
2671                 if (bveccount > NFS_COMMITBVECSIZ) {
2672                         /*
2673                          * Release the vnode interlock to avoid a lock
2674                          * order reversal.
2675                          */
2676                         VI_UNLOCK(vp);
2677                         bvec = (struct buf **)
2678                                 malloc(bveccount * sizeof(struct buf *),
2679                                        M_TEMP, M_NOWAIT);
2680                         VI_LOCK(vp);
2681                         if (bvec == NULL) {
2682                                 bvec = bvec_on_stack;
2683                                 bvecsize = NFS_COMMITBVECSIZ;
2684                         } else
2685                                 bvecsize = bveccount;
2686                 } else {
2687                         bvec = bvec_on_stack;
2688                         bvecsize = NFS_COMMITBVECSIZ;
2689                 }
2690                 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
2691                         if (bvecpos >= bvecsize)
2692                                 break;
2693                         if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
2694                                 nbp = TAILQ_NEXT(bp, b_vnbufs);
2695                                 continue;
2696                         }
2697                         if ((bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) !=
2698                             (B_DELWRI | B_NEEDCOMMIT)) {
2699                                 BUF_UNLOCK(bp);
2700                                 nbp = TAILQ_NEXT(bp, b_vnbufs);
2701                                 continue;
2702                         }
2703                         VI_UNLOCK(vp);
2704                         bremfree(bp);
2705                         /*
2706                          * Work out if all buffers are using the same cred
2707                          * so we can deal with them all with one commit.
2708                          *
2709                          * NOTE: we are not clearing B_DONE here, so we have
2710                          * to do it later on in this routine if we intend to
2711                          * initiate I/O on the bp.
2712                          *
2713                          * Note: to avoid loopback deadlocks, we do not
2714                          * assign b_runningbufspace.
2715                          */
2716                         if (wcred == NULL)
2717                                 wcred = bp->b_wcred;
2718                         else if (wcred != bp->b_wcred)
2719                                 wcred = NOCRED;
2720                         bp->b_flags |= B_WRITEINPROG;
2721                         vfs_busy_pages(bp, 1);
2722
2723                         VI_LOCK(vp);
2724                         /*
2725                          * bp is protected by being locked, but nbp is not
2726                          * and vfs_busy_pages() may sleep.  We have to
2727                          * recalculate nbp.
2728                          */
2729                         nbp = TAILQ_NEXT(bp, b_vnbufs);
2730
2731                         /*
2732                          * A list of these buffers is kept so that the
2733                          * second loop knows which buffers have actually
2734                          * been committed. This is necessary, since there
2735                          * may be a race between the commit rpc and new
2736                          * uncommitted writes on the file.
2737                          */
2738                         bvec[bvecpos++] = bp;
2739                         toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
2740                                 bp->b_dirtyoff;
2741                         if (toff < off)
2742                                 off = toff;
2743                         toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff);
2744                         if (toff > endoff)
2745                                 endoff = toff;
2746                 }
2747                 splx(s);
2748                 VI_UNLOCK(vp);
2749         }
2750         if (bvecpos > 0) {
2751                 /*
2752                  * Commit data on the server, as required.
2753                  * If all bufs are using the same wcred, then use that with
2754                  * one call for all of them, otherwise commit each one
2755                  * separately.
2756                  */
2757                 if (wcred != NOCRED)
2758                         retv = nfs4_commit(vp, off, (int)(endoff - off),
2759                                           wcred, td);
2760                 else {
2761                         retv = 0;
2762                         for (i = 0; i < bvecpos; i++) {
2763                                 off_t off, size;
2764                                 bp = bvec[i];
2765                                 off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
2766                                         bp->b_dirtyoff;
2767                                 size = (u_quad_t)(bp->b_dirtyend
2768                                                   - bp->b_dirtyoff);
2769                                 retv = nfs4_commit(vp, off, (int)size,
2770                                                   bp->b_wcred, td);
2771                                 if (retv) break;
2772                         }
2773                 }
2774
2775                 if (retv == NFSERR_STALEWRITEVERF)
2776                         nfs_clearcommit(vp->v_mount);
2777
2778                 /*
2779                  * Now, either mark the blocks I/O done or mark the
2780                  * blocks dirty, depending on whether the commit
2781                  * succeeded.
2782                  */
2783                 for (i = 0; i < bvecpos; i++) {
2784                         bp = bvec[i];
2785                         bp->b_flags &= ~(B_NEEDCOMMIT | B_WRITEINPROG | B_CLUSTEROK);
2786                         if (retv) {
2787                                 /*
2788                                  * Error, leave B_DELWRI intact
2789                                  */
2790                                 vfs_unbusy_pages(bp);
2791                                 brelse(bp);
2792                         } else {
2793                                 /*
2794                                  * Success, remove B_DELWRI ( bundirty() ).
2795                                  *
2796                                  * b_dirtyoff/b_dirtyend seem to be NFS
2797                                  * specific.  We should probably move that
2798                                  * into bundirty(). XXX
2799                                  */
2800                                 s = splbio();
2801                                 VI_LOCK(vp);
2802                                 vp->v_numoutput++;
2803                                 VI_UNLOCK(vp);
2804                                 bp->b_flags |= B_ASYNC;
2805                                 bundirty(bp);
2806                                 bp->b_flags &= ~B_DONE;
2807                                 bp->b_ioflags &= ~BIO_ERROR;
2808                                 bp->b_dirtyoff = bp->b_dirtyend = 0;
2809                                 splx(s);
2810                                 bufdone(bp);
2811                         }
2812                 }
2813         }
2814
2815         /*
2816          * Start/do any write(s) that are required.
2817          */
2818 loop:
2819         s = splbio();
2820         VI_LOCK(vp);
2821         for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
2822                 nbp = TAILQ_NEXT(bp, b_vnbufs);
2823                 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
2824                         if (waitfor != MNT_WAIT || passone)
2825                                 continue;
2826
2827                         error = BUF_TIMELOCK(bp,
2828                             LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
2829                             VI_MTX(vp), "nfsfsync", slpflag, slptimeo);
2830                         splx(s);
2831                         if (error == 0)
2832                                 panic("nfs4_fsync: inconsistent lock");
2833                         if (error == ENOLCK)
2834                                 goto loop;
2835                         if (nfs4_sigintr(nmp, NULL, td)) {
2836                                 error = EINTR;
2837                                 goto done;
2838                         }
2839                         if (slpflag == PCATCH) {
2840                                 slpflag = 0;
2841                                 slptimeo = 2 * hz;
2842                         }
2843                         goto loop;
2844                 }
2845                 if ((bp->b_flags & B_DELWRI) == 0)
2846                         panic("nfs4_fsync: not dirty");
2847                 if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT)) {
2848                         BUF_UNLOCK(bp);
2849                         continue;
2850                 }
2851                 VI_UNLOCK(vp);
2852                 bremfree(bp);
2853                 if (passone || !commit)
2854                     bp->b_flags |= B_ASYNC;
2855                 else
2856                     bp->b_flags |= B_ASYNC | B_WRITEINPROG;
2857                 splx(s);
2858                 bwrite(bp);
2859                 goto loop;
2860         }
2861         splx(s);
2862         if (passone) {
2863                 passone = 0;
2864                 VI_UNLOCK(vp);
2865                 goto again;
2866         }
2867         if (waitfor == MNT_WAIT) {
2868                 while (vp->v_numoutput) {
2869                         vp->v_iflag |= VI_BWAIT;
2870                         error = msleep((caddr_t)&vp->v_numoutput, VI_MTX(vp),
2871                                 slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
2872                         if (error) {
2873                             VI_UNLOCK(vp);
2874                             if (nfs4_sigintr(nmp, NULL, td)) {
2875                                 error = EINTR;
2876                                 goto done;
2877                             }
2878                             if (slpflag == PCATCH) {
2879                                 slpflag = 0;
2880                                 slptimeo = 2 * hz;
2881                             }
2882                             VI_LOCK(vp);
2883                         }
2884                 }
2885                 if (!TAILQ_EMPTY(&vp->v_dirtyblkhd) && commit) {
2886                         VI_UNLOCK(vp);
2887                         goto loop;
2888                 }
2889         }
2890         VI_UNLOCK(vp);
2891         if (np->n_flag & NWRITEERR) {
2892                 error = np->n_error;
2893                 np->n_flag &= ~NWRITEERR;
2894         }
2895 done:
2896         if (bvec != NULL && bvec != bvec_on_stack)
2897                 free(bvec, M_TEMP);
2898         return (error);
2899 }
2900
2901 /*
2902  * NFS advisory byte-level locks.
2903  */
2904 static int
2905 nfs4_advlock(struct vop_advlock_args *ap)
2906 {
2907         return (EPERM);
2908
2909         if ((VFSTONFS(ap->a_vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) {
2910                 struct nfsnode *np = VTONFS(ap->a_vp);
2911
2912                 return (lf_advlock(ap, &(np->n_lockf), np->n_size));
2913         }
2914         return (nfs_dolock(ap));
2915 }
2916
2917 /*
2918  * Print out the contents of an nfsnode.
2919  */
2920 static int
2921 nfs4_print(struct vop_print_args *ap)
2922 {
2923         struct vnode *vp = ap->a_vp;
2924         struct nfsnode *np = VTONFS(vp);
2925
2926         printf("\tfileid %ld fsid 0x%x",
2927            np->n_vattr.va_fileid, np->n_vattr.va_fsid);
2928         if (vp->v_type == VFIFO)
2929                 fifo_printinfo(vp);
2930         printf("\n");
2931         return (0);
2932 }
2933
2934 /*
2935  * This is the "real" nfs::bwrite(struct buf*).
2936  * B_WRITEINPROG isn't set unless the force flag is one and it
2937  * handles the B_NEEDCOMMIT flag.
2938  * We set B_CACHE if this is a VMIO buffer.
2939  */
2940 int
2941 nfs4_writebp(struct buf *bp, int force, struct thread *td)
2942 {
2943         int s;
2944         int oldflags = bp->b_flags;
2945 #if 0
2946         int retv = 1;
2947         off_t off;
2948 #endif
2949
2950         if (BUF_REFCNT(bp) == 0)
2951                 panic("bwrite: buffer is not locked???");
2952
2953         if (bp->b_flags & B_INVAL) {
2954                 brelse(bp);
2955                 return(0);
2956         }
2957
2958         bp->b_flags |= B_CACHE;
2959
2960         /*
2961          * Undirty the bp.  We will redirty it later if the I/O fails.
2962          */
2963
2964         s = splbio();
2965         bundirty(bp);
2966         bp->b_flags &= ~B_DONE;
2967         bp->b_ioflags &= ~BIO_ERROR;
2968         bp->b_iocmd = BIO_WRITE;
2969
2970         VI_LOCK(bp->b_vp);
2971         bp->b_vp->v_numoutput++;
2972         VI_UNLOCK(bp->b_vp);
2973         curthread->td_proc->p_stats->p_ru.ru_oublock++;
2974         splx(s);
2975
2976         /*
2977          * Note: to avoid loopback deadlocks, we do not
2978          * assign b_runningbufspace.
2979          */
2980         vfs_busy_pages(bp, 1);
2981
2982         if (force)
2983                 bp->b_flags |= B_WRITEINPROG;
2984         BUF_KERNPROC(bp);
2985         bp->b_iooffset = dbtob(bp->b_blkno);
2986         VOP_STRATEGY(bp->b_vp, bp);
2987
2988         if( (oldflags & B_ASYNC) == 0) {
2989                 int rtval = bufwait(bp);
2990
2991                 if (oldflags & B_DELWRI) {
2992                         s = splbio();
2993                         reassignbuf(bp);
2994                         splx(s);
2995                 }
2996
2997                 brelse(bp);
2998                 return (rtval);
2999         }
3000
3001         return (0);
3002 }
3003
3004 /*
3005  * nfs special file access vnode op.
3006  * Essentially just get vattr and then imitate iaccess() since the device is
3007  * local to the client.
3008  */
3009 static int
3010 nfsspec_access(struct vop_access_args *ap)
3011 {
3012         struct vattr *vap;
3013         struct ucred *cred = ap->a_cred;
3014         struct vnode *vp = ap->a_vp;
3015         mode_t mode = ap->a_mode;
3016         struct vattr vattr;
3017         int error;
3018
3019         /*
3020          * Disallow write attempts on filesystems mounted read-only;
3021          * unless the file is a socket, fifo, or a block or character
3022          * device resident on the filesystem.
3023          */
3024         if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3025                 switch (vp->v_type) {
3026                 case VREG:
3027                 case VDIR:
3028                 case VLNK:
3029                         return (EROFS);
3030                 default:
3031                         break;
3032                 }
3033         }
3034         vap = &vattr;
3035         error = VOP_GETATTR(vp, vap, cred, ap->a_td);
3036         if (error)
3037                 return (error);
3038         return (vaccess(vp->v_type, vap->va_mode, vap->va_uid, vap->va_gid,
3039             mode, cred, NULL));
3040 }
3041
3042 /*
3043  * Read wrapper for special devices.
3044  */
3045 static int
3046 nfsspec_read(struct vop_read_args *ap)
3047 {
3048         struct nfsnode *np = VTONFS(ap->a_vp);
3049
3050         /*
3051          * Set access flag.
3052          */
3053         np->n_flag |= NACC;
3054         getnanotime(&np->n_atim);
3055         return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
3056 }
3057
3058 /*
3059  * Write wrapper for special devices.
3060  */
3061 static int
3062 nfsspec_write(struct vop_write_args *ap)
3063 {
3064         struct nfsnode *np = VTONFS(ap->a_vp);
3065
3066         /*
3067          * Set update flag.
3068          */
3069         np->n_flag |= NUPD;
3070         getnanotime(&np->n_mtim);
3071         return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
3072 }
3073
3074 /*
3075  * Close wrapper for special devices.
3076  *
3077  * Update the times on the nfsnode then do device close.
3078  */
3079 static int
3080 nfsspec_close(struct vop_close_args *ap)
3081 {
3082         struct vnode *vp = ap->a_vp;
3083         struct nfsnode *np = VTONFS(vp);
3084         struct vattr vattr;
3085
3086         if (np->n_flag & (NACC | NUPD)) {
3087                 np->n_flag |= NCHG;
3088                 if (vrefcnt(vp) == 1 &&
3089                     (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
3090                         VATTR_NULL(&vattr);
3091                         if (np->n_flag & NACC)
3092                                 vattr.va_atime = np->n_atim;
3093                         if (np->n_flag & NUPD)
3094                                 vattr.va_mtime = np->n_mtim;
3095                         (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_td);
3096                 }
3097         }
3098         return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
3099 }
3100
3101 /*
3102  * Read wrapper for fifos.
3103  */
3104 static int
3105 nfsfifo_read(struct vop_read_args *ap)
3106 {
3107         struct nfsnode *np = VTONFS(ap->a_vp);
3108
3109         /*
3110          * Set access flag.
3111          */
3112         np->n_flag |= NACC;
3113         getnanotime(&np->n_atim);
3114         return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
3115 }
3116
3117 /*
3118  * Write wrapper for fifos.
3119  */
3120 static int
3121 nfsfifo_write(struct vop_write_args *ap)
3122 {
3123         struct nfsnode *np = VTONFS(ap->a_vp);
3124
3125         /*
3126          * Set update flag.
3127          */
3128         np->n_flag |= NUPD;
3129         getnanotime(&np->n_mtim);
3130         return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
3131 }
3132
3133 /*
3134  * Close wrapper for fifos.
3135  *
3136  * Update the times on the nfsnode then do fifo close.
3137  */
3138 static int
3139 nfsfifo_close(struct vop_close_args *ap)
3140 {
3141         struct vnode *vp = ap->a_vp;
3142         struct nfsnode *np = VTONFS(vp);
3143         struct vattr vattr;
3144         struct timespec ts;
3145
3146         if (np->n_flag & (NACC | NUPD)) {
3147                 getnanotime(&ts);
3148                 if (np->n_flag & NACC)
3149                         np->n_atim = ts;
3150                 if (np->n_flag & NUPD)
3151                         np->n_mtim = ts;
3152                 np->n_flag |= NCHG;
3153                 if (vrefcnt(vp) == 1 &&
3154                     (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
3155                         VATTR_NULL(&vattr);
3156                         if (np->n_flag & NACC)
3157                                 vattr.va_atime = np->n_atim;
3158                         if (np->n_flag & NUPD)
3159                                 vattr.va_mtime = np->n_mtim;
3160                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_td);
3161                         (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_td);
3162                         VOP_UNLOCK(vp, 0, ap->a_td);
3163                 }
3164         }
3165         return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
3166 }
3167