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