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