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