1 /* $FreeBSD: releng/5.3/sys/nfs4client/nfs4_vnops.c 132780 2004-07-28 06:59:55Z kan $ */
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: releng/5.3/sys/nfs4client/nfs4_vnops.c 132780 2004-07-28 06:59:55Z kan $");
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
Cache object: 8919ed51941fc0aab7723ba2592debb2
|