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