[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs4client/nfs4_vnops.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /* $Id: nfs_vnops.c,v 1.45 2003/11/05 14:59:02 rees Exp $ */
  2 
  3 /*-
  4  * copyright (c) 2003
  5  * the regents of the university of michigan
  6  * all rights reserved
  7  * 
  8  * permission is granted to use, copy, create derivative works and redistribute
  9  * this software and such derivative works for any purpose, so long as the name
 10  * of the university of michigan is not used in any advertising or publicity
 11  * pertaining to the use or distribution of this software without specific,
 12  * written prior authorization.  if the above copyright notice or any other
 13  * identification of the university of michigan is included in any copy of any
 14  * portion of this software, then the disclaimer below must also be included.
 15  * 
 16  * this software is provided as is, without representation from the university
 17  * of michigan as to its fitness for any purpose, and without warranty by the
 18  * university of michigan of any kind, either express or implied, including
 19  * without limitation the implied warranties of merchantability and fitness for
 20  * a particular purpose. the regents of the university of michigan shall not be
 21  * liable for any damages, including special, indirect, incidental, or
 22  * consequential damages, with respect to any claim arising out of or in
 23  * connection with the use of the software, even if it has been or is hereafter
 24  * advised of the possibility of such damages.
 25  */
 26 
 27 /*
 28  * Copyright (c) 1989, 1993
 29  *      The Regents of the University of California.  All rights reserved.
 30  *
 31  * This code is derived from software contributed to Berkeley by
 32  * Rick Macklem at The University of Guelph.
 33  *
 34  * Redistribution and use in source and binary forms, with or without
 35  * modification, are permitted provided that the following conditions
 36  * are met:
 37  * 1. Redistributions of source code must retain the above copyright
 38  *    notice, this list of conditions and the following disclaimer.
 39  * 2. Redistributions in binary form must reproduce the above copyright
 40  *    notice, this list of conditions and the following disclaimer in the
 41  *    documentation and/or other materials provided with the distribution.
 42  * 4. Neither the name of the University nor the names of its contributors
 43  *    may be used to endorse or promote products derived from this software
 44  *    without specific prior written permission.
 45  *
 46  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 49  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 50  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 51  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 52  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 53  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 54  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 56  * SUCH DAMAGE.
 57  *
 58  *      @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
 59  */
 60 
 61 #include <sys/cdefs.h>
 62 __FBSDID("$FreeBSD: src/sys/nfs4client/nfs4_vnops.c,v 1.49 2008/10/28 13:44:11 trasz Exp $");
 63 
 64 /*
 65  * vnode op calls for Sun NFS version 2 and 3
 66  */
 67 
 68 #include "opt_inet.h"
 69 
 70 #include <sys/param.h>
 71 #include <sys/kernel.h>
 72 #include <sys/systm.h>
 73 #include <sys/resourcevar.h>
 74 #include <sys/proc.h>
 75 #include <sys/mount.h>
 76 #include <sys/bio.h>
 77 #include <sys/buf.h>
 78 #include <sys/malloc.h>
 79 #include <sys/mbuf.h>
 80 #include <sys/namei.h>
 81 #include <sys/socket.h>
 82 #include <sys/vnode.h>
 83 #include <sys/dirent.h>
 84 #include <sys/fcntl.h>
 85 #include <sys/lockf.h>
 86 #include <sys/stat.h>
 87 #include <sys/sysctl.h>
 88 #include <sys/lockmgr.h>
 89 #include <sys/signalvar.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      nfs4_flush(struct vnode *, int, struct thread *,
130                     int);
131 static int      nfs4_setattrrpc(struct vnode *, struct vattr *, struct ucred *);
132 static int      nfs4_closerpc(struct vnode *, struct ucred *, int);
133 
134 static vop_lookup_t     nfs4_lookup;
135 static vop_create_t     nfs4_create;
136 static vop_mknod_t      nfs4_mknod;
137 static vop_open_t       nfs4_open;
138 static vop_close_t      nfs4_close;
139 static vop_access_t     nfs4_access;
140 static vop_getattr_t    nfs4_getattr;
141 static vop_setattr_t    nfs4_setattr;
142 static vop_read_t       nfs4_read;
143 static vop_fsync_t      nfs4_fsync;
144 static vop_remove_t     nfs4_remove;
145 static vop_link_t       nfs4_link;
146 static vop_rename_t     nfs4_rename;
147 static vop_mkdir_t      nfs4_mkdir;
148 static vop_rmdir_t      nfs4_rmdir;
149 static vop_symlink_t    nfs4_symlink;
150 static vop_readdir_t    nfs4_readdir;
151 static vop_strategy_t   nfs4_strategy;
152 static  int     nfs4_lookitup(struct vnode *, const char *, int,
153                     struct ucred *, struct thread *, struct nfsnode **);
154 static  int     nfs4_sillyrename(struct vnode *, struct vnode *,
155                     struct componentname *);
156 static vop_readlink_t   nfs4_readlink;
157 static vop_print_t      nfs4_print;
158 static vop_advlock_t    nfs4_advlock;
159 static vop_advlockasync_t nfs4_advlockasync;
160 
161 /*
162  * Global vfs data structures for nfs
163  */
164 struct vop_vector nfs4_vnodeops = {
165         .vop_default =          &default_vnodeops,
166         .vop_access =           nfs4_access,
167         .vop_advlock =          nfs4_advlock,
168         .vop_advlockasync =     nfs4_advlockasync,
169         .vop_close =            nfs4_close,
170         .vop_create =           nfs4_create,
171         .vop_fsync =            nfs4_fsync,
172         .vop_getattr =          nfs4_getattr,
173         .vop_getpages =         nfs_getpages,
174         .vop_putpages =         nfs_putpages,
175         .vop_inactive =         nfs_inactive,
176         .vop_lease =            VOP_NULL,
177         .vop_link =             nfs4_link,
178         .vop_lookup =           nfs4_lookup,
179         .vop_mkdir =            nfs4_mkdir,
180         .vop_mknod =            nfs4_mknod,
181         .vop_open =             nfs4_open,
182         .vop_print =            nfs4_print,
183         .vop_read =             nfs4_read,
184         .vop_readdir =          nfs4_readdir,
185         .vop_readlink =         nfs4_readlink,
186         .vop_reclaim =          nfs_reclaim,
187         .vop_remove =           nfs4_remove,
188         .vop_rename =           nfs4_rename,
189         .vop_rmdir =            nfs4_rmdir,
190         .vop_setattr =          nfs4_setattr,
191         .vop_strategy =         nfs4_strategy,
192         .vop_symlink =          nfs4_symlink,
193         .vop_write =            nfs_write,
194 };
195 
196 static int      nfs4_removerpc(struct vnode *dvp, const char *name, int namelen,
197                               struct ucred *cred, struct thread *td);
198 static int      nfs4_renamerpc(struct vnode *fdvp, const char *fnameptr,
199                               int fnamelen, struct vnode *tdvp,
200                               const char *tnameptr, int tnamelen,
201                               struct ucred *cred, struct thread *td);
202 static int      nfs4_renameit(struct vnode *sdvp, struct componentname *scnp,
203                              struct sillyrename *sp);
204 static int      nfs4_openrpc(struct vnode *, struct vnode **,
205                             struct componentname *, int, struct vattr *);
206 static int      nfs4_open_confirm(struct vnode *vp, struct nfs4_compound *cpp,
207                                  struct nfs4_oparg_open *openap,
208                                  struct nfs4_oparg_getfh *gfh,
209                                  struct ucred *cred, struct thread *td);
210 static int      nfs4_createrpc(struct vnode *, struct vnode **,
211                               struct componentname *, nfstype,
212                               struct vattr *, char *);
213 
214 /*
215  * Global variables
216  */
217 struct nfs4_lowner nfs4_masterlowner;
218 
219 #define DIRHDSIZ        (sizeof (struct dirent) - (MAXNAMLEN + 1))
220 
221 SYSCTL_DECL(_vfs_nfs4);
222 
223 static int      nfs4_access_cache_timeout = NFS_MAXATTRTIMO;
224 SYSCTL_INT(_vfs_nfs4, OID_AUTO, access_cache_timeout, CTLFLAG_RW,
225            &nfs4_access_cache_timeout, 0, "NFS ACCESS cache timeout");
226 
227 #if 0
228 static int      nfsv3_commit_on_close = 0;
229 SYSCTL_INT(_vfs_nfs4, OID_AUTO, nfsv3_commit_on_close, CTLFLAG_RW,
230            &nfsv3_commit_on_close, 0, "write+commit on close, else only write");
231 
232 SYSCTL_INT(_vfs_nfs4, OID_AUTO, access_cache_hits, CTLFLAG_RD,
233            &nfsstats.accesscache_hits, 0, "NFS ACCESS cache hit count");
234 
235 SYSCTL_INT(_vfs_nfs4, OID_AUTO, access_cache_misses, CTLFLAG_RD,
236            &nfsstats.accesscache_misses, 0, "NFS ACCESS cache miss count");
237 #endif
238 
239 #define NFSV3ACCESS_ALL (NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY          \
240                          | NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE     \
241                          | NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP)
242 static int
243 nfs4_v3_access_otw(struct vnode *vp, int wmode, struct thread *td,
244     struct ucred *cred)
245 {
246         const int v3 = 1;
247         u_int32_t *tl;
248         int error = 0, attrflag;
249 
250         return (0);
251 
252         struct mbuf *mreq, *mrep = NULL, *md, *mb;
253         caddr_t bpos, dpos;
254         u_int32_t rmode;
255         struct nfsnode *np = VTONFS(vp);
256 
257         nfsstats.rpccnt[NFSPROC_ACCESS]++;
258         mreq = nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
259         mb = mreq;
260         bpos = mtod(mb, caddr_t);
261         nfsm_fhtom(vp, v3);
262         tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
263         *tl = txdr_unsigned(wmode);
264         nfsm_request(vp, NFSPROC_ACCESS, td, cred);
265         nfsm_postop_attr(vp, attrflag);
266         if (!error) {
267                 tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
268                 rmode = fxdr_unsigned(u_int32_t, *tl);
269                 np->n_mode = rmode;
270                 np->n_modeuid = cred->cr_uid;
271                 np->n_modestamp = time_second;
272         }
273         m_freem(mrep);
274 nfsmout:
275         return error;
276 }
277 
278 /*
279  * nfs access vnode op.
280  * For nfs version 2, just return ok. File accesses may fail later.
281  * For nfs version 3, use the access rpc to check accessibility. If file modes
282  * are changed on the server, accesses might still fail later.
283  */
284 static int
285 nfs4_access(struct vop_access_args *ap)
286 {
287         struct vnode *vp = ap->a_vp;
288         int error = 0;
289         u_int32_t mode, wmode;
290         int v3 = NFS_ISV3(vp);  /* v3 \in v4 */
291         struct nfsnode *np = VTONFS(vp);
292         caddr_t bpos, dpos;
293         struct mbuf *mreq, *mrep = NULL, *md, *mb;
294         struct nfs4_compound cp;
295         struct nfs4_oparg_access acc;
296         struct thread *td = ap->a_td;
297         struct ucred *cred = ap->a_cred;
298 
299         /*
300          * Disallow write attempts on filesystems mounted read-only;
301          * unless the file is a socket, fifo, or a block or character
302          * device resident on the filesystem.
303          */
304         if ((ap->a_accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
305                 switch (vp->v_type) {
306                 case VREG:
307                 case VDIR:
308                 case VLNK:
309                         return (EROFS);
310                 default:
311                         break;
312                 }
313         }
314         /*
315          * For nfs v3, check to see if we have done this recently, and if
316          * so return our cached result instead of making an ACCESS call.
317          * If not, do an access rpc, otherwise you are stuck emulating
318          * ufs_access() locally using the vattr. This may not be correct,
319          * since the server may apply other access criteria such as
320          * client uid-->server uid mapping that we do not know about.
321          */
322         /* XXX Disable this for now; needs fixing of _access_otw() */
323         if (0 && v3) {
324                 if (ap->a_accmode & VREAD)
325                         mode = NFSV3ACCESS_READ;
326                 else
327                         mode = 0;
328                 if (vp->v_type != VDIR) {
329                         if (ap->a_accmode & VWRITE)
330                                 mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
331                         if (ap->a_accmode & VEXEC)
332                                 mode |= NFSV3ACCESS_EXECUTE;
333                 } else {
334                         if (ap->a_accmode & VWRITE)
335                                 mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
336                                     NFSV3ACCESS_DELETE);
337                         if (ap->a_accmode & VEXEC)
338                                 mode |= NFSV3ACCESS_LOOKUP;
339                 }
340                 /* XXX safety belt, only make blanket request if caching */
341                 if (nfs4_access_cache_timeout > 0) {
342                         wmode = NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY |
343                             NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE |
344                             NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP;
345                 } else {
346                         wmode = mode;
347                 }
348 
349                 /*
350                  * Does our cached result allow us to give a definite yes to
351                  * this request?
352                  */
353                 if (time_second < np->n_modestamp + nfs4_access_cache_timeout &&
354                     ap->a_cred->cr_uid == np->n_modeuid &&
355                     (np->n_mode & mode) == mode) {
356                         nfsstats.accesscache_hits++;
357                 } else {
358                         /*
359                          * Either a no, or a don't know.  Go to the wire.
360                          */
361                         nfsstats.accesscache_misses++;
362                         error = nfs4_v3_access_otw(vp, wmode, ap->a_td,
363                             ap->a_cred);
364                         if (error == 0) {
365                                 if ((np->n_mode & mode) != mode)
366                                         error = EACCES;
367                         }
368                 }
369                 return (error);
370         }
371 
372         /* XXX use generic access code here? */
373         mode = ap->a_accmode & VREAD ? NFSV4ACCESS_READ : 0;
374         if (vp->v_type == VDIR) {
375                 if (ap->a_accmode & VWRITE)
376                         mode |= NFSV4ACCESS_MODIFY | NFSV4ACCESS_EXTEND | NFSV4ACCESS_DELETE;
377                 if (ap->a_accmode & VEXEC)
378                         mode |= NFSV4ACCESS_LOOKUP;
379         } else {
380                 if (ap->a_accmode & VWRITE)
381                         mode |= NFSV4ACCESS_MODIFY | NFSV4ACCESS_EXTEND;
382                 if (ap->a_accmode & VEXEC)
383                         mode |= NFSV4ACCESS_EXECUTE;
384         }
385 
386         nfs_v4initcompound(&cp);
387         acc.mode = mode;
388 
389         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
390         mb = mreq;
391         bpos = mtod(mb, caddr_t);
392 
393         nfsm_v4build_compound(&cp, "nfs4_access()");
394         nfsm_v4build_putfh(&cp, vp);
395         nfsm_v4build_access(&cp, &acc);
396         nfsm_v4build_finalize(&cp);
397 
398         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
399         if (error != 0)
400                 goto nfsmout;
401 
402         nfsm_v4dissect_compound(&cp);
403         nfsm_v4dissect_putfh(&cp);
404         nfsm_v4dissect_access(&cp, &acc);
405 
406         if ((acc.rmode & mode) != mode)
407                 error = EACCES;
408 
409  nfsmout:
410         error = nfs_v4postop(&cp, error);
411 
412         if (mrep != NULL)
413                 m_freem(mrep);
414 
415         return (error);
416 }
417 
418 static int
419 nfs4_openrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
420     int flags, struct vattr *vap)
421 {
422         struct vnode *vp = *vpp;
423         struct nfs4_oparg_getattr getattr;
424         struct nfs4_oparg_getfh getfh;
425         struct nfs4_oparg_open opena;
426         struct nfs4_compound cp;
427         caddr_t bpos, dpos;
428         int error = 0;
429         struct mbuf *mreq, *mrep = NULL, *md, *mb;
430         struct ucred *cred = cnp->cn_cred;
431         struct thread *td = cnp->cn_thread;
432         struct nfs4_fctx xfc, *fcp;
433         struct nfsnode *np;
434 
435         if (vp == NULL) {
436                 /* Create a new file */
437                 np = NULL;
438                 fcp = &xfc;
439                 bzero(fcp, sizeof(*fcp));
440         } else {
441                 np = VTONFS(vp);
442                 fcp = flags & FWRITE ? &np->n_wfc : &np->n_rfc;
443         }
444 
445         /*
446          * Since we are currently only one lockowner; we only open the
447          * file once each for reading and writing.
448          */
449         if (fcp->refcnt++ != 0) {
450                 *vpp = vp;
451                 /*printf("not opening %s\n", np->n_name != NULL ? np->n_name : "");*/
452                 return (0);
453         }
454 
455         fcp->lop = &nfs4_masterlowner;
456         fcp->np = np;
457 
458         nfs_v4initcompound(&cp);
459         cp.nmp = VFSTONFS(dvp->v_mount);
460 
461         opena.ctype = NCLNULL;
462         opena.flags = flags;
463         opena.vap = vap;
464         opena.fcp = fcp;                /* For lockowner */
465         opena.cnp = cnp;
466 
467         getattr.bm = &nfsv4_getattrbm;
468 
469         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
470         mb = mreq;
471         bpos = mtod(mb, caddr_t);
472 
473         nfsm_v4build_compound(&cp, "nfs4_openrpc()");
474         nfsm_v4build_putfh(&cp, dvp);
475         nfsm_v4build_open(&cp, &opena);
476         nfsm_v4build_getattr(&cp, &getattr);
477         nfsm_v4build_getfh(&cp, &getfh);
478         nfsm_v4build_finalize(&cp);
479 
480         nfsm_request(vp != NULL ? vp : dvp, NFSV4PROC_COMPOUND, td, cred);
481         if (error != 0)
482                 goto nfsmout;
483 
484         nfsm_v4dissect_compound(&cp);
485         nfsm_v4dissect_putfh(&cp);
486         nfsm_v4dissect_open(&cp, &opena);
487         nfsm_v4dissect_getattr(&cp, &getattr);
488         nfsm_v4dissect_getfh(&cp, &getfh);
489 
490         error = nfs_v4postop(&cp, error);
491 
492         if (opena.rflags & NFSV4OPENRES_CONFIRM) {
493                 error = nfs4_open_confirm(vp ? vp : dvp, &cp, &opena, &getfh, cred, td);
494                 if (error != 0)
495                         goto nfsmout;
496         }
497 
498         if (vp == NULL) {
499                 /* New file */
500                 error = nfs_nget(dvp->v_mount, &getfh.fh_val,
501                                  getfh.fh_len, &np, LK_EXCLUSIVE);
502                 if (error != 0)
503                         goto nfsmout;
504 
505                 vp = NFSTOV(np);
506                 np->n_dvp = dvp;
507                 np->n_namelen = cnp->cn_namelen; /* XXX memory leaks on these; track! */
508                 if (np->n_name != NULL)
509                         free(np->n_name, M_NFSREQ);
510                 np->n_name = malloc(np->n_namelen + 1, M_NFSREQ, M_WAITOK);
511                 bcopy(cnp->cn_nameptr, np->n_name, np->n_namelen);
512                 np->n_name[np->n_namelen] = '\0';
513                 if (flags & FWRITE)
514                         np->n_wfc = *fcp;
515                 else
516                         np->n_rfc = *fcp;
517 
518                 /*printf("opened new file %s\n", np->n_name);*/
519 
520                 nfs4_vnop_loadattrcache(vp, &getattr.fa, NULL);
521                 *vpp = vp;
522         } else {
523                 /*printf("openend \"old\" %s\n", np->n_name != NULL ? np->n_name : "");*/
524 
525                 if (flags & O_TRUNC && np->n_size != 0) {
526                         struct vattr va;
527 
528                         VATTR_NULL(&va);
529                         va.va_size = 0;
530                         error = nfs4_setattrrpc(vp, &va, cnp->cn_cred);
531                 }
532                 np->n_attrstamp = 0;
533         }
534 
535  nfsmout:
536         if (mrep != NULL)
537                 m_freem(mrep);
538 
539         return (error);
540 }
541 
542 static int
543 nfs4_open_confirm(struct vnode *vp, struct nfs4_compound *cpp,
544     struct nfs4_oparg_open *openap, struct nfs4_oparg_getfh *gfh,
545     struct ucred *cred, struct thread *td)
546 {
547         caddr_t bpos, dpos;
548         int error = 0;
549         struct mbuf *mreq, *mrep = NULL, *md, *mb;
550 
551         nfs_v4initcompound(cpp);
552         cpp->nmp = VFSTONFS(vp->v_mount);
553 
554         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
555         mb = mreq;
556         bpos = mtod(mb, caddr_t);
557 
558         nfsm_v4build_compound(cpp, "nfs4_open_confirm()");
559         nfsm_v4build_putfh_nv(cpp, gfh);
560         nfsm_v4build_open_confirm(cpp, openap);
561         nfsm_v4build_finalize(cpp);
562 
563         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
564         if (error != 0)
565                 goto nfsmout;
566 
567         nfsm_v4dissect_compound(cpp);
568         nfsm_v4dissect_putfh(cpp);
569         nfsm_v4dissect_open_confirm(cpp, openap);
570 
571  nfsmout:
572         error = nfs_v4postop(cpp, error);
573 
574         if (mrep != NULL)
575                 m_freem(mrep);
576 
577         return (error);
578 }
579 
580 
581 /*
582  * nfs open vnode op
583  * Check to see if the type is ok
584  * and that deletion is not in progress.
585  * For paged in text files, you will need to flush the page cache
586  * if consistency is lost.
587  */
588 /* ARGSUSED */
589 static int
590 nfs4_open(struct vop_open_args *ap)
591 {
592         struct vnode *vp = ap->a_vp;
593         struct nfsnode *np = VTONFS(vp);
594         enum vtype vtype = vp->v_type;
595         int mode = ap->a_mode;
596         struct componentname cn;
597 
598         if (vtype != VREG) {
599                 if (vtype != VDIR && vtype != VLNK) {
600 #ifdef DIAGNOSTIC
601                         printf("open eacces vtyp=%d\n", vp->v_type);
602 #endif
603                         return (EACCES);
604                 } else
605                         return (0);
606         }
607 
608         if (np->n_flag & NCREATED) {
609                 np->n_flag &= ~NCREATED;
610                 return (0);
611         }
612 
613         cn.cn_nameptr = np->n_name;
614         cn.cn_namelen = np->n_namelen;
615         cn.cn_cred = ap->a_cred;
616         cn.cn_thread = ap->a_td;
617 
618         return (nfs4_openrpc(np->n_dvp, &vp, &cn, mode, NULL));
619 }
620 
621 static int
622 nfs4_closerpc(struct vnode *vp, struct ucred *cred, int flags)
623 {
624         caddr_t bpos, dpos;
625         int error = 0;
626         struct mbuf *mreq, *mrep = NULL, *md, *mb;
627         struct thread *td;
628         struct nfs4_fctx *fcp;
629         struct nfs4_compound cp;
630         struct nfsnode *np = VTONFS(vp);
631 
632         td = curthread;
633         fcp = flags & FWRITE ? &np->n_wfc : &np->n_rfc;
634 
635         nfs_v4initcompound(&cp);
636 
637         if (--fcp->refcnt != 0)
638                 return (0);
639 
640         /*printf("closing %s\n", np->n_name != NULL ? np->n_name : "");*/
641 
642         cp.fcp = fcp;
643 
644         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
645         mb = mreq;
646         bpos = mtod(mb, caddr_t);
647 
648         nfsm_v4build_compound(&cp, "nfs4_closerpc()");
649         nfsm_v4build_putfh(&cp, vp);
650         nfsm_v4build_close(&cp, fcp);
651         nfsm_v4build_finalize(&cp);
652 
653         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
654         if (error != 0)
655                 goto nfsmout;
656 
657         nfsm_v4dissect_compound(&cp);
658         nfsm_v4dissect_putfh(&cp);
659         nfsm_v4dissect_close(&cp, fcp);
660 
661  nfsmout:
662         error = nfs_v4postop(&cp, error);
663 
664         if (mrep != NULL)
665                 m_freem(mrep);
666 
667         return (error);
668 }
669 
670 /*
671  * nfs close vnode op
672  * play it safe for now (see comments in v2/v3 nfs_close regarding dirty buffers)
673  */
674 /* ARGSUSED */
675 static int
676 nfs4_close(struct vop_close_args *ap)
677 {
678         struct vnode *vp = ap->a_vp;
679         struct nfsnode *np = VTONFS(vp);
680         int error = 0;
681 
682         if (vp->v_type != VREG)
683                 return (0);
684 
685         if (np->n_flag & NMODIFIED) {
686                 error = nfs_vinvalbuf(vp, V_SAVE, ap->a_td, 1);
687                 np->n_attrstamp = 0;
688         }
689 
690         error = nfs4_closerpc(vp, ap->a_cred, ap->a_fflag);
691 
692         if (!error && np->n_flag & NWRITEERR) {
693                 np->n_flag &= ~NWRITEERR;
694                 error = np->n_error;
695         }
696         return (error);
697 }
698 
699 /*
700  * nfs getattr call from vfs.
701  */
702 static int
703 nfs4_getattr(struct vop_getattr_args *ap)
704 {
705         struct vnode *vp = ap->a_vp;
706         struct nfsnode *np = VTONFS(vp);
707         caddr_t bpos, dpos;
708         int error = 0;
709         struct mbuf *mreq, *mrep = NULL, *md, *mb;
710         struct nfs4_oparg_getattr ga;
711         struct nfs4_compound cp;
712 
713         /*
714          * Update local times for special files.
715          */
716         if (np->n_flag & (NACC | NUPD))
717                 np->n_flag |= NCHG;
718         /*
719          * First look in the cache.
720          */
721         if (nfs_getattrcache(vp, ap->a_vap) == 0)
722                 return (0);
723 
724         nfsstats.rpccnt[NFSPROC_GETATTR]++;
725 
726         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, NFSX_FH(1));
727         mb = mreq;
728         bpos = mtod(mb, caddr_t);
729 
730         ga.bm = &nfsv4_getattrbm;
731         nfs_v4initcompound(&cp);
732 
733         nfsm_v4build_compound(&cp, "nfs4_getattr()");
734         nfsm_v4build_putfh(&cp, vp);
735         nfsm_v4build_getattr(&cp, &ga);
736         nfsm_v4build_finalize(&cp);
737 
738         nfsm_request(vp, NFSV4PROC_COMPOUND, curthread, ap->a_cred);
739         if (error != 0)
740                 goto nfsmout;
741 
742         nfsm_v4dissect_compound(&cp);
743         nfsm_v4dissect_putfh(&cp);
744         nfsm_v4dissect_getattr(&cp, &ga);
745 
746         nfs4_vnop_loadattrcache(vp, &ga.fa, ap->a_vap);
747 
748 nfsmout:
749         error = nfs_v4postop(&cp, error);
750 
751         if (mrep != NULL)
752                 m_freem(mrep);
753         return (error);
754 }
755 
756 /*
757  * nfs setattr call.
758  */
759 static int
760 nfs4_setattr(struct vop_setattr_args *ap)
761 {
762         struct vnode *vp = ap->a_vp;
763         struct nfsnode *np = VTONFS(vp);
764         struct vattr *vap = ap->a_vap;
765         struct thread *td = curthread;
766         int error = 0;
767         u_quad_t tsize;
768 
769 #ifndef nolint
770         tsize = (u_quad_t)0;
771 #endif
772 
773         /*
774          * Setting of flags is not supported.
775          */
776         if (vap->va_flags != VNOVAL)
777                 return (EOPNOTSUPP);
778 
779         /*
780          * Disallow write attempts if the filesystem is mounted read-only.
781          */
782         if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
783             vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
784             vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
785             (vp->v_mount->mnt_flag & MNT_RDONLY))
786                 return (EROFS);
787         if (vap->va_size != VNOVAL) {
788                 switch (vp->v_type) {
789                 case VDIR:
790                         return (EISDIR);
791                 case VCHR:
792                 case VBLK:
793                 case VSOCK:
794                 case VFIFO:
795                         if (vap->va_mtime.tv_sec == VNOVAL &&
796                             vap->va_atime.tv_sec == VNOVAL &&
797                             vap->va_mode == (mode_t)VNOVAL &&
798                             vap->va_uid == (uid_t)VNOVAL &&
799                             vap->va_gid == (gid_t)VNOVAL)
800                                 return (0);
801                         vap->va_size = VNOVAL;
802                         break;
803                 default:
804                         /*
805                          * Disallow write attempts if the filesystem is
806                          * mounted read-only.
807                          */
808                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
809                                 return (EROFS);
810 
811                         /*
812                          *  We run vnode_pager_setsize() early (why?),
813                          * we must set np->n_size now to avoid vinvalbuf
814                          * V_SAVE races that might setsize a lower
815                          * value.
816                          */
817 
818                         tsize = np->n_size;
819                         error = nfs_meta_setsize(vp, ap->a_cred, td,
820                             vap->va_size);
821 
822                         if (np->n_flag & NMODIFIED) {
823                             if (vap->va_size == 0)
824                                 error = nfs_vinvalbuf(vp, 0, td, 1);
825                             else
826                                 error = nfs_vinvalbuf(vp, V_SAVE, td, 1);
827                             if (error) {
828                                 vnode_pager_setsize(vp, np->n_size);
829                                 return (error);
830                             }
831                         }
832                         /*
833                          * np->n_size has already been set to vap->va_size
834                          * in nfs_meta_setsize(). We must set it again since
835                          * nfs_loadattrcache() could be called through
836                          * nfs_meta_setsize() and could modify np->n_size.
837                          */
838                         np->n_vattr.va_size = np->n_size = vap->va_size;
839                 };
840         } else if ((vap->va_mtime.tv_sec != VNOVAL ||
841                 vap->va_atime.tv_sec != VNOVAL) && (np->n_flag & NMODIFIED) &&
842                 vp->v_type == VREG &&
843                 (error = nfs_vinvalbuf(vp, V_SAVE, td, 1)) == EINTR)
844                 return (error);
845 
846         if (vap->va_size != VNOVAL && np->n_wfc.refcnt == 0) {
847                 /* Have to open the file before we can truncate it */
848                 struct componentname cn;
849 
850                 cn.cn_nameptr = np->n_name;
851                 cn.cn_namelen = np->n_namelen;
852                 cn.cn_cred = ap->a_cred;
853                 cn.cn_thread = td;
854                 error = nfs4_openrpc(np->n_dvp, &vp, &cn, FWRITE, NULL);
855                 if (error)
856                         return error;
857                 np->n_flag |= NTRUNCATE;
858         }
859 
860         error = nfs4_setattrrpc(vp, vap, ap->a_cred);
861         if (error && vap->va_size != VNOVAL) {
862                 np->n_size = np->n_vattr.va_size = tsize;
863                 vnode_pager_setsize(vp, np->n_size);
864         }
865         return (error);
866 }
867 
868 /*
869  * Do an nfs setattr rpc.
870  */
871 static int
872 nfs4_setattrrpc(struct vnode *vp, struct vattr *vap, struct ucred *cred)
873 {
874         caddr_t bpos, dpos;
875         int error = 0;
876         struct mbuf *mreq, *mrep = NULL, *md, *mb;
877         struct thread *td;
878         struct nfs4_compound cp;
879         struct nfs4_oparg_getattr ga;
880         struct nfsnode *np = VTONFS(vp);
881         struct nfs4_fctx *fcp;
882 
883         td = curthread;
884         nfsstats.rpccnt[NFSPROC_SETATTR]++;
885         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
886         mb = mreq;
887         bpos = mtod(mb, caddr_t);
888 
889         ga.bm = &nfsv4_getattrbm;
890         fcp = (vap->va_size != VNOVAL) ? &np->n_wfc : NULL;
891         nfs_v4initcompound(&cp);
892 
893         nfsm_v4build_compound(&cp, "nfs4_setattrrpc");
894         nfsm_v4build_putfh(&cp, vp);
895         nfsm_v4build_setattr(&cp, vap, fcp);
896         nfsm_v4build_getattr(&cp, &ga);
897         nfsm_v4build_finalize(&cp);
898 
899         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
900         if (error != 0)
901                 goto nfsmout;
902 
903         nfsm_v4dissect_compound(&cp);
904         nfsm_v4dissect_putfh(&cp);
905         nfsm_v4dissect_setattr(&cp);
906         nfsm_v4dissect_getattr(&cp, &ga);
907 
908         nfs4_vnop_loadattrcache(vp, &ga.fa, NULL);
909 
910         /* TODO: do the settatr and close in a single compound rpc */
911         if (np->n_flag & NTRUNCATE) {
912                 error = nfs4_closerpc(vp, cred, FWRITE);
913                 np->n_flag &= ~NTRUNCATE;
914         }
915 
916 nfsmout:
917         error = nfs_v4postop(&<