|
|
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: #endif
1.1.1.2 ! root 587: NFS_DPF(SILLY,
! 588: ("nfs_close: %s, dvp=%x, vp=%x, ap=%x, np=%x, sp=%x\n",
! 589: &sp->s_name[0], (unsigned)(sp->s_dvp), (unsigned)vp,
! 590: (unsigned)ap, (unsigned)np, (unsigned)sp));
1.1 root 591: if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
592: (np->n_flag & NMODIFIED)) {
593: if (NFS_ISV3(vp)) {
594: error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 0);
595: np->n_flag &= ~NMODIFIED;
596: } else
597: error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
598: np->n_attrstamp = 0;
599: }
600: if (np->n_flag & NWRITEERR) {
601: np->n_flag &= ~NWRITEERR;
602: error = np->n_error;
603: }
604: }
605: return (error);
606: }
607:
608: /*
609: * nfs getattr call from vfs.
610: */
611: static int
612: nfs_getattr(ap)
613: struct vop_getattr_args /* {
614: struct vnode *a_vp;
615: struct vattr *a_vap;
616: struct ucred *a_cred;
617: struct proc *a_p;
618: } */ *ap;
619: {
620: register struct vnode *vp = ap->a_vp;
621: register struct nfsnode *np = VTONFS(vp);
622: register caddr_t cp;
623: register u_long *tl;
624: register int t1, t2;
625: caddr_t bpos, dpos;
626: int error = 0;
627: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
628: int v3 = NFS_ISV3(vp);
629:
630: /*
631: * Update local times for special files.
632: */
633: if (np->n_flag & (NACC | NUPD))
634: np->n_flag |= NCHG;
635: /*
636: * First look in the cache.
637: */
638: if (nfs_getattrcache(vp, ap->a_vap) == 0)
639: return (0);
640: nfsstats.rpccnt[NFSPROC_GETATTR]++;
641: nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3));
642: nfsm_fhtom(vp, v3);
643: nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
644: if (!error) {
645: nfsm_loadattr(vp, ap->a_vap);
646: #if MACH_NBC
647: if (np->n_mtime != ap->a_vap->va_mtime.tv_sec) {
648: NFSTRACE(NFSTRC_GA_INV, vp);
649: if (vp->v_type == VDIR)
650: nfs_invaldir(vp);
651: error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
652: ap->a_p, 1);
653: if (!error) {
654: NFSTRACE(NFSTRC_GA_INV1, vp);
655: np->n_mtime = ap->a_vap->va_mtime.tv_sec;
656: } else {
657: NFSTRACE(NFSTRC_GA_INV2, error);
658: }
659: }
660: #endif /* MACH_NBC */
661: }
662: nfsm_reqdone;
663: return (error);
664: }
665:
666: /*
667: * nfs setattr call.
668: */
669: static int
670: nfs_setattr(ap)
671: struct vop_setattr_args /* {
672: struct vnodeop_desc *a_desc;
673: struct vnode *a_vp;
674: struct vattr *a_vap;
675: struct ucred *a_cred;
676: struct proc *a_p;
677: } */ *ap;
678: {
679: register struct vnode *vp = ap->a_vp;
680: register struct nfsnode *np = VTONFS(vp);
681: register struct vattr *vap = ap->a_vap;
682: int error = 0;
683: u_quad_t tsize;
684:
685: #ifndef nolint
686: tsize = (u_quad_t)0;
687: #endif
688: /*
689: * Disallow write attempts if the filesystem is mounted read-only.
690: */
691: if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
692: vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
693: vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
694: (vp->v_mount->mnt_flag & MNT_RDONLY))
695: return (EROFS);
696: if (vap->va_size != VNOVAL) {
697: switch (vp->v_type) {
698: case VDIR:
699: return (EISDIR);
700: case VCHR:
701: case VBLK:
702: case VSOCK:
703: case VFIFO:
704: if (vap->va_mtime.tv_sec == VNOVAL &&
705: vap->va_atime.tv_sec == VNOVAL &&
706: vap->va_mode == (u_short)VNOVAL &&
707: vap->va_uid == (uid_t)VNOVAL &&
708: vap->va_gid == (gid_t)VNOVAL)
709: return (0);
710: vap->va_size = VNOVAL;
711: break;
712: default:
713: /*
714: * Disallow write attempts if the filesystem is
715: * mounted read-only.
716: */
717: if (vp->v_mount->mnt_flag & MNT_RDONLY)
718: return (EROFS);
719: np->n_flag |= NMODIFIED;
720: /*
721: * save n_size first as mapfs_trunc can trigger
722: * size change via nfs_bio
723: */
724: tsize = np->n_size;
725: #if MACH_NBC
726: if ((vp->v_type == VREG) && (vp->v_vm_info)
727: && vp->v_vm_info->mapped) {
728: error = mapfs_trunc(vp,vap->va_size);
729: if (error) {
730: #if DIAGNOSTIC
731: kprintf("nfs_setattr: mapfs_trunc %d\n",
732: error);
733: #endif /* DIAGNOSTIC */
734: return (error);
735: }
736: } else {
737: #endif /* MACH_NBC */
738: vnode_pager_setsize(vp, (u_long)vap->va_size);
739: #if MACH_NBC
740: }
741: #endif /* MACH_NBC */
742: if (vap->va_size == 0)
743: error = nfs_vinvalbuf(vp, 0,
744: ap->a_cred, ap->a_p, 1);
745: else
746: error = nfs_vinvalbuf(vp, V_SAVE,
747: ap->a_cred, ap->a_p, 1);
748: if (error) {
749: #if DIAGNOSTIC
750: kprintf("nfs_setattr: nfs_vinvalbuf %d\n",
751: error);
752: #endif /* DIAGNOSTIC */
753: return (error);
754: }
755: np->n_size = np->n_vattr.va_size = vap->va_size;
756:
757: };
758: } else if ((vap->va_mtime.tv_sec != VNOVAL ||
759: vap->va_atime.tv_sec != VNOVAL) && (np->n_flag & NMODIFIED) &&
760: vp->v_type == VREG &&
761: (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
762: ap->a_p, 1)) == EINTR)
763: return (error);
764: error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
765: if (error && vap->va_size != VNOVAL) {
766: /* make every effort to resync file size w/ server... */
767: int err = 0; /* preserve "error" for return */
768:
769: #if DIAGNOSTIC
770: kprintf("nfs_setattr: nfs_setattrrpc %d\n", error);
771: #endif /* DIAGNOSTIC */
772: np->n_size = np->n_vattr.va_size = tsize;
773: #if MACH_NBC
774: if (vp->v_type == VREG && vp->v_vm_info &&
775: vp->v_vm_info->mapped) {
776: err = mapfs_trunc(vp, tsize);
777: #if DIAGNOSTIC
778: if (err)
779: kprintf("nfs_setattr mapfs_trunc %d\n", err);
780: #endif /* DIAGNOSTIC */
781: } else {
782: #endif /* MACH_NBC */
783: vnode_pager_setsize(vp, (u_long)np->n_size);
784: #if MACH_NBC
785: }
786: #endif /* MACH_NBC */
787: vap->va_size = tsize;
788: err = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
789: #if DIAGNOSTIC
790: if (err)
791: kprintf("nfs_setattr nfs_setattrrpc %d\n", err);
792: #endif /* DIAGNOSTIC */
793: }
794: return (error);
795: }
796:
797: /*
798: * Do an nfs setattr rpc.
799: */
800: static int
801: nfs_setattrrpc(vp, vap, cred, procp)
802: register struct vnode *vp;
803: register struct vattr *vap;
804: struct ucred *cred;
805: struct proc *procp;
806: {
807: register struct nfsv2_sattr *sp;
808: register caddr_t cp;
809: register long t1, t2;
810: caddr_t bpos, dpos, cp2;
811: u_long *tl;
812: int error = 0, wccflag = NFSV3_WCCRATTR;
813: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
814: int v3 = NFS_ISV3(vp);
815:
816: nfsstats.rpccnt[NFSPROC_SETATTR]++;
817: nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3));
818: nfsm_fhtom(vp, v3);
819: if (v3) {
820: if (vap->va_mode != (u_short)VNOVAL) {
821: nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
822: *tl++ = nfs_true;
823: *tl = txdr_unsigned(vap->va_mode);
824: } else {
825: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
826: *tl = nfs_false;
827: }
828: if (vap->va_uid != (uid_t)VNOVAL) {
829: nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
830: *tl++ = nfs_true;
831: *tl = txdr_unsigned(vap->va_uid);
832: } else {
833: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
834: *tl = nfs_false;
835: }
836: if (vap->va_gid != (gid_t)VNOVAL) {
837: nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
838: *tl++ = nfs_true;
839: *tl = txdr_unsigned(vap->va_gid);
840: } else {
841: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
842: *tl = nfs_false;
843: }
844: if (vap->va_size != VNOVAL) {
845: nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
846: *tl++ = nfs_true;
847: txdr_hyper(&vap->va_size, tl);
848: } else {
849: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
850: *tl = nfs_false;
851: }
852: if (vap->va_atime.tv_sec != VNOVAL) {
853: if (vap->va_atime.tv_sec != time.tv_sec) {
854: nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
855: *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
856: txdr_nfsv3time(&vap->va_atime, tl);
857: } else {
858: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
859: *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
860: }
861: } else {
862: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
863: *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
864: }
865: if (vap->va_mtime.tv_sec != VNOVAL) {
866: if (vap->va_mtime.tv_sec != time.tv_sec) {
867: nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
868: *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
869: txdr_nfsv3time(&vap->va_mtime, tl);
870: } else {
871: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
872: *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
873: }
874: } else {
875: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
876: *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
877: }
878: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
879: *tl = nfs_false;
880: } else {
881: nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
882: if (vap->va_mode == (u_short)VNOVAL)
883: sp->sa_mode = VNOVAL;
884: else
885: sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode);
886: if (vap->va_uid == (uid_t)VNOVAL)
887: sp->sa_uid = VNOVAL;
888: else
889: sp->sa_uid = txdr_unsigned(vap->va_uid);
890: if (vap->va_gid == (gid_t)VNOVAL)
891: sp->sa_gid = VNOVAL;
892: else
893: sp->sa_gid = txdr_unsigned(vap->va_gid);
894: sp->sa_size = txdr_unsigned(vap->va_size);
895: txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
896: txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
897: }
898: nfsm_request(vp, NFSPROC_SETATTR, procp, cred);
899: if (v3) {
900: nfsm_wcc_data(vp, wccflag);
901: if (!wccflag)
902: VTONFS(vp)->n_attrstamp = 0;
903: } else
904: nfsm_loadattr(vp, (struct vattr *)0);
905: nfsm_reqdone;
906: return (error);
907: }
908:
909: /*
910: * nfs lookup call, one step at a time...
911: * First look in cache
912: * If not found, unlock the directory nfsnode and do the rpc
913: */
914: static int
915: nfs_lookup(ap)
916: struct vop_lookup_args /* {
917: struct vnodeop_desc *a_desc;
918: struct vnode *a_dvp;
919: struct vnode **a_vpp;
920: struct componentname *a_cnp;
921: } */ *ap;
922: {
923: register struct componentname *cnp = ap->a_cnp;
924: register struct vnode *dvp = ap->a_dvp;
925: register struct vnode **vpp = ap->a_vpp;
926: register int flags = cnp->cn_flags;
927: register struct vnode *newvp;
928: register u_long *tl;
929: register caddr_t cp;
930: register long t1, t2;
931: struct nfsmount *nmp;
932: caddr_t bpos, dpos, cp2;
933: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
934: long len;
935: nfsfh_t *fhp;
936: struct nfsnode *np;
937: int lockparent, wantparent, error = 0, attrflag, fhsize;
938: int v3 = NFS_ISV3(dvp);
939: struct proc *p = cnp->cn_proc;
940:
941: if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
942: (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
943: return (EROFS);
944: *vpp = NULLVP;
945: if (dvp->v_type != VDIR)
946: return (ENOTDIR);
947: lockparent = flags & LOCKPARENT;
948: wantparent = flags & (LOCKPARENT|WANTPARENT);
949: nmp = VFSTONFS(dvp->v_mount);
950: np = VTONFS(dvp);
951: if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
952: struct vattr vattr;
953: int vpid;
954:
955: if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p))) {
956: *vpp = NULLVP;
957: return (error);
958: }
959:
960: newvp = *vpp;
961: vpid = newvp->v_id;
962: /*
963: * See the comment starting `Step through' in ufs/ufs_lookup.c
964: * for an explanation of the locking protocol
965: */
966: if (dvp == newvp) {
967: VREF(newvp);
968: error = 0;
969: } else if (flags & ISDOTDOT) {
970: VOP_UNLOCK(dvp, 0, p);
971: error = vget(newvp, LK_EXCLUSIVE, p);
972: if (!error && lockparent && (flags & ISLASTCN))
973: error = vn_lock(dvp, LK_EXCLUSIVE, p);
974: } else {
975: error = vget(newvp, LK_EXCLUSIVE, p);
976: if (!lockparent || error || !(flags & ISLASTCN))
977: VOP_UNLOCK(dvp, 0, p);
978: }
979: if (!error) {
980: if (vpid == newvp->v_id) {
981: if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, p)
982: && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
983: nfsstats.lookupcache_hits++;
984: if (cnp->cn_nameiop != LOOKUP &&
985: (flags & ISLASTCN))
986: cnp->cn_flags |= SAVENAME;
987: return (0);
988: }
989: cache_purge(newvp);
990: }
991: vput(newvp);
992: if (lockparent && dvp != newvp && (flags & ISLASTCN))
993: VOP_UNLOCK(dvp, 0, p);
994: }
995: error = vn_lock(dvp, LK_EXCLUSIVE, p);
996: *vpp = NULLVP;
997: if (error)
998: return (error);
999: }
1000: error = 0;
1001: newvp = NULLVP;
1002: nfsstats.lookupcache_misses++;
1003: nfsstats.rpccnt[NFSPROC_LOOKUP]++;
1004: len = cnp->cn_namelen;
1005: nfsm_reqhead(dvp, NFSPROC_LOOKUP,
1006: NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
1007: nfsm_fhtom(dvp, v3);
1008: nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
1009: nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
1010: if (error) {
1011: nfsm_postop_attr(dvp, attrflag);
1012: m_freem(mrep);
1013: goto nfsmout;
1014: }
1015: nfsm_getfh(fhp, fhsize, v3);
1016:
1017: /*
1018: * Handle RENAME case...
1019: */
1020: if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
1021: if (NFS_CMPFH(np, fhp, fhsize)) {
1022: m_freem(mrep);
1023: return (EISDIR);
1024: }
1025: if ((error = nfs_nget(dvp->v_mount, fhp, fhsize, &np))) {
1026: m_freem(mrep);
1027: return (error);
1028: }
1029: newvp = NFSTOV(np);
1030: if (v3) {
1031: nfsm_postop_attr(newvp, attrflag);
1032: nfsm_postop_attr(dvp, attrflag);
1033: } else
1034: nfsm_loadattr(newvp, (struct vattr *)0);
1035: *vpp = newvp;
1036: m_freem(mrep);
1037: cnp->cn_flags |= SAVENAME;
1038: if (!lockparent)
1039: VOP_UNLOCK(dvp, 0, p);
1040: return (0);
1041: }
1042:
1043: if (flags & ISDOTDOT) {
1044: VOP_UNLOCK(dvp, 0, p);
1045: error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
1046: if (error) {
1047: vn_lock(dvp, LK_EXCLUSIVE + LK_RETRY, p);
1048: return (error);
1049: }
1050: newvp = NFSTOV(np);
1051: if (lockparent && (flags & ISLASTCN) &&
1052: (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
1053: vput(newvp);
1054: return (error);
1055: }
1056: } else if (NFS_CMPFH(np, fhp, fhsize)) {
1057: VREF(dvp);
1058: newvp = dvp;
1059: } else {
1060: if ((error = nfs_nget(dvp->v_mount, fhp, fhsize, &np))) {
1061: m_freem(mrep);
1062: return (error);
1063: }
1064: if (!lockparent || !(flags & ISLASTCN))
1065: VOP_UNLOCK(dvp, 0, p);
1066: newvp = NFSTOV(np);
1067: }
1068: if (v3) {
1069: nfsm_postop_attr(newvp, attrflag);
1070: nfsm_postop_attr(dvp, attrflag);
1071: } else
1072: nfsm_loadattr(newvp, (struct vattr *)0);
1073: if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
1074: cnp->cn_flags |= SAVENAME;
1075: if ((cnp->cn_flags & MAKEENTRY) &&
1076: (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
1077: np->n_ctime = np->n_vattr.va_ctime.tv_sec;
1078: cache_enter(dvp, newvp, cnp);
1079: }
1080: *vpp = newvp;
1081: nfsm_reqdone;
1082: if (error) {
1083: if (newvp != NULLVP) {
1084: vrele(newvp);
1085: *vpp = NULLVP;
1086: }
1087: if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
1088: (flags & ISLASTCN) && error == ENOENT) {
1089: if (!lockparent)
1090: VOP_UNLOCK(dvp, 0, p);
1091: if (dvp->v_mount->mnt_flag & MNT_RDONLY)
1092: error = EROFS;
1093: else
1094: error = EJUSTRETURN;
1095: }
1096: if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
1097: cnp->cn_flags |= SAVENAME;
1098: }
1099: return (error);
1100: }
1101:
1102: /*
1103: * nfs read call.
1104: * Just call nfs_bioread() to do the work.
1105: */
1106: static int
1107: nfs_read(ap)
1108: struct vop_read_args /* {
1109: struct vnode *a_vp;
1110: struct uio *a_uio;
1111: int a_ioflag;
1112: struct ucred *a_cred;
1113: } */ *ap;
1114: {
1115: register struct vnode *vp = ap->a_vp;
1116:
1117: if (vp->v_type != VREG)
1118: return (EPERM);
1119: return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred, 0));
1120: }
1121:
1122: /*
1123: * nfs readlink call
1124: */
1125: static int
1126: nfs_readlink(ap)
1127: struct vop_readlink_args /* {
1128: struct vnode *a_vp;
1129: struct uio *a_uio;
1130: struct ucred *a_cred;
1131: } */ *ap;
1132: {
1133: register struct vnode *vp = ap->a_vp;
1134:
1135: if (vp->v_type != VLNK)
1136: return (EPERM);
1137: return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred, 0));
1138: }
1139:
1140: /*
1141: * Do a readlink rpc.
1142: * Called by nfs_doio() from below the buffer cache.
1143: */
1144: int
1145: nfs_readlinkrpc(vp, uiop, cred)
1146: register struct vnode *vp;
1147: struct uio *uiop;
1148: struct ucred *cred;
1149: {
1150: register u_long *tl;
1151: register caddr_t cp;
1152: register long t1, t2;
1153: caddr_t bpos, dpos, cp2;
1154: int error = 0, len, attrflag;
1155: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1156: int v3 = NFS_ISV3(vp);
1157:
1158: nfsstats.rpccnt[NFSPROC_READLINK]++;
1159: nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
1160: nfsm_fhtom(vp, v3);
1161: nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
1162: if (v3)
1163: nfsm_postop_attr(vp, attrflag);
1164: if (!error) {
1165: nfsm_strsiz(len, NFS_MAXPATHLEN);
1.1.1.2 ! root 1166: if (len == NFS_MAXPATHLEN) {
! 1167: struct nfsnode *np = VTONFS(vp);
! 1168: #if DIAGNOSTIC
! 1169: if (!np)
! 1170: panic("nfs_readlinkrpc: null np\n");
! 1171: #endif
! 1172: if (np->n_size && np->n_size < NFS_MAXPATHLEN)
! 1173: len = np->n_size;
! 1174: }
1.1 root 1175: nfsm_mtouio(uiop, len);
1176: }
1177: nfsm_reqdone;
1178: return (error);
1179: }
1180:
1181: /*
1182: * nfs read rpc call
1183: * Ditto above
1184: */
1185: int
1186: nfs_readrpc(vp, uiop, cred)
1187: register struct vnode *vp;
1188: struct uio *uiop;
1189: struct ucred *cred;
1190: {
1191: register u_long *tl;
1192: register caddr_t cp;
1193: register long t1, t2;
1194: caddr_t bpos, dpos, cp2;
1195: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1196: struct nfsmount *nmp;
1197: int error = 0, len, retlen, tsiz, eof, attrflag;
1198: int v3 = NFS_ISV3(vp);
1199:
1200: #ifndef nolint
1201: eof = 0;
1202: #endif
1203: nmp = VFSTONFS(vp->v_mount);
1204: tsiz = uiop->uio_resid;
1205: if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
1206: return (EFBIG);
1207: while (tsiz > 0) {
1208: nfsstats.rpccnt[NFSPROC_READ]++;
1209: len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
1210: nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3);
1211: nfsm_fhtom(vp, v3);
1212: nfsm_build(tl, u_long *, NFSX_UNSIGNED * 3);
1213: if (v3) {
1214: txdr_hyper(&uiop->uio_offset, tl);
1215: *(tl + 2) = txdr_unsigned(len);
1216: } else {
1217: *tl++ = txdr_unsigned(uiop->uio_offset);
1218: *tl++ = txdr_unsigned(len);
1219: *tl = 0;
1220: }
1221: nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
1222: if (v3) {
1223: nfsm_postop_attr(vp, attrflag);
1224: if (error) {
1225: m_freem(mrep);
1226: goto nfsmout;
1227: }
1228: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1229: eof = fxdr_unsigned(int, *(tl + 1));
1230: } else
1231: nfsm_loadattr(vp, (struct vattr *)0);
1232: nfsm_strsiz(retlen, nmp->nm_rsize);
1233: nfsm_mtouio(uiop, retlen);
1234: m_freem(mrep);
1235: tsiz -= retlen;
1236: if (v3) {
1237: if (eof || retlen == 0)
1238: tsiz = 0;
1239: } else if (retlen < len)
1240: tsiz = 0;
1241: }
1242: nfsmout:
1243: return (error);
1244: }
1245:
1246: /*
1247: * nfs write call
1248: */
1249: int
1250: nfs_writerpc(vp, uiop, cred, iomode, must_commit)
1251: register struct vnode *vp;
1252: register struct uio *uiop;
1253: struct ucred *cred;
1254: int *iomode, *must_commit;
1255: {
1256: register u_long *tl;
1257: register caddr_t cp;
1258: register int t1, t2, backup;
1259: caddr_t bpos, dpos, cp2;
1260: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1261: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1262: int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit;
1263: int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC;
1264:
1265: #if DIAGNOSTIC
1266: if (uiop->uio_iovcnt != 1)
1267: panic("nfs: writerpc iovcnt > 1");
1268: #endif
1269: *must_commit = 0;
1270: tsiz = uiop->uio_resid;
1271: if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
1272: return (EFBIG);
1273: while (tsiz > 0) {
1274: nfsstats.rpccnt[NFSPROC_WRITE]++;
1275: len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
1276: nfsm_reqhead(vp, NFSPROC_WRITE,
1277: NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len));
1278: nfsm_fhtom(vp, v3);
1279: if (v3) {
1280: nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
1281: txdr_hyper(&uiop->uio_offset, tl);
1282: tl += 2;
1283: *tl++ = txdr_unsigned(len);
1284: *tl++ = txdr_unsigned(*iomode);
1285: } else {
1286: nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1287: *++tl = txdr_unsigned(uiop->uio_offset);
1288: tl += 2;
1289: }
1290: *tl = txdr_unsigned(len);
1291: nfsm_uiotom(uiop, len);
1292: nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
1293: if (v3) {
1294: wccflag = NFSV3_WCCCHK;
1295: nfsm_wcc_data(vp, wccflag);
1296: if (!error) {
1297: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED +
1298: NFSX_V3WRITEVERF);
1299: rlen = fxdr_unsigned(int, *tl++);
1300: if (rlen == 0) {
1301: error = NFSERR_IO;
1302: break;
1303: } else if (rlen < len) {
1304: backup = len - rlen;
1305: uiop->uio_iov->iov_base -= backup;
1306: uiop->uio_iov->iov_len += backup;
1307: uiop->uio_offset -= backup;
1308: uiop->uio_resid += backup;
1309: len = rlen;
1310: }
1311: commit = fxdr_unsigned(int, *tl++);
1312:
1313: /*
1314: * Return the lowest committment level
1315: * obtained by any of the RPCs.
1316: */
1317: if (committed == NFSV3WRITE_FILESYNC)
1318: committed = commit;
1319: else if (committed == NFSV3WRITE_DATASYNC &&
1320: commit == NFSV3WRITE_UNSTABLE)
1321: committed = commit;
1322: if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0) {
1323: bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
1324: NFSX_V3WRITEVERF);
1325: nmp->nm_flag |= NFSMNT_HASWRITEVERF;
1326: } else if (bcmp((caddr_t)tl,
1327: (caddr_t)nmp->nm_verf, NFSX_V3WRITEVERF)) {
1328: *must_commit = 1;
1329: bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
1330: NFSX_V3WRITEVERF);
1331: }
1332: }
1333: } else
1334: nfsm_loadattr(vp, (struct vattr *)0);
1335: if (wccflag)
1336: VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
1337: m_freem(mrep);
1338: tsiz -= len;
1339: }
1340: nfsmout:
1341: if (vp->v_mount->mnt_flag & MNT_ASYNC)
1342: committed = NFSV3WRITE_FILESYNC;
1343: *iomode = committed;
1344: if (error)
1345: uiop->uio_resid = tsiz;
1346: return (error);
1347: }
1348:
1349: /*
1350: * nfs mknod rpc
1351: * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1352: * mode set to specify the file type and the size field for rdev.
1353: */
1354: static int
1355: nfs_mknodrpc(dvp, vpp, cnp, vap)
1356: register struct vnode *dvp;
1357: register struct vnode **vpp;
1358: register struct componentname *cnp;
1359: register struct vattr *vap;
1360: {
1361: register struct nfsv2_sattr *sp;
1362: register struct nfsv3_sattr *sp3;
1363: register u_long *tl;
1364: register caddr_t cp;
1365: register long t1, t2;
1366: struct vnode *newvp = (struct vnode *)0;
1367: struct nfsnode *np = (struct nfsnode *)0;
1368: struct vattr vattr;
1369: char *cp2;
1370: caddr_t bpos, dpos;
1371: int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
1372: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1373: u_long rdev;
1374: int v3 = NFS_ISV3(dvp);
1375:
1376: if (vap->va_type == VCHR || vap->va_type == VBLK)
1377: rdev = txdr_unsigned(vap->va_rdev);
1378: else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
1379: rdev = 0xffffffff;
1380: else {
1381: VOP_ABORTOP(dvp, cnp);
1382: vput(dvp);
1383: return (EOPNOTSUPP);
1384: }
1385: if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
1386: VOP_ABORTOP(dvp, cnp);
1387: vput(dvp);
1388: return (error);
1389: }
1390: nfsstats.rpccnt[NFSPROC_MKNOD]++;
1391: nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
1392: + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
1393: nfsm_fhtom(dvp, v3);
1394: nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1395: if (v3) {
1396: nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3SRVSATTR);
1397: *tl++ = vtonfsv3_type(vap->va_type);
1398: sp3 = (struct nfsv3_sattr *)tl;
1399: nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
1400: if (vap->va_type == VCHR || vap->va_type == VBLK) {
1401: nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1402: *tl++ = txdr_unsigned(major(vap->va_rdev));
1403: *tl = txdr_unsigned(minor(vap->va_rdev));
1404: }
1405: } else {
1406: nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1407: sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1408: sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1409: sp->sa_gid = txdr_unsigned(vattr.va_gid);
1410: sp->sa_size = rdev;
1411: txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1412: txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1413: }
1414: nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred);
1415: if (!error) {
1416: nfsm_mtofh(dvp, newvp, v3, gotvp);
1417: if (!gotvp) {
1418: if (newvp) {
1419: vput(newvp);
1420: newvp = (struct vnode *)0;
1421: }
1422: error = nfs_lookitup(dvp, cnp->cn_nameptr,
1423: cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
1424: if (!error)
1425: newvp = NFSTOV(np);
1426: }
1427: }
1428: if (v3)
1429: nfsm_wcc_data(dvp, wccflag);
1430: nfsm_reqdone;
1431: if (error) {
1432: if (newvp)
1433: vput(newvp);
1434: } else {
1435: if (cnp->cn_flags & MAKEENTRY)
1436: cache_enter(dvp, newvp, cnp);
1437: *vpp = newvp;
1438: }
1439: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1440: VTONFS(dvp)->n_flag |= NMODIFIED;
1441: if (!wccflag)
1442: VTONFS(dvp)->n_attrstamp = 0;
1443: vput(dvp);
1444: return (error);
1445: }
1446:
1447: /*
1448: * nfs mknod vop
1449: * just call nfs_mknodrpc() to do the work.
1450: */
1451: /* ARGSUSED */
1452: static int
1453: nfs_mknod(ap)
1454: struct vop_mknod_args /* {
1455: struct vnode *a_dvp;
1456: struct vnode **a_vpp;
1457: struct componentname *a_cnp;
1458: struct vattr *a_vap;
1459: } */ *ap;
1460: {
1461: struct vnode *newvp;
1462: int error;
1463:
1464: error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap);
1465: if (!error)
1466: vput(newvp);
1467: return (error);
1468: }
1469:
1470: static u_long create_verf;
1471: /*
1472: * nfs file create call
1473: */
1474: static int
1475: nfs_create(ap)
1476: struct vop_create_args /* {
1477: struct vnode *a_dvp;
1478: struct vnode **a_vpp;
1479: struct componentname *a_cnp;
1480: struct vattr *a_vap;
1481: } */ *ap;
1482: {
1483: register struct vnode *dvp = ap->a_dvp;
1484: register struct vattr *vap = ap->a_vap;
1485: register struct componentname *cnp = ap->a_cnp;
1486: register struct nfsv2_sattr *sp;
1487: register struct nfsv3_sattr *sp3;
1488: register u_long *tl;
1489: register caddr_t cp;
1490: register long t1, t2;
1491: struct nfsnode *np = (struct nfsnode *)0;
1492: struct vnode *newvp = (struct vnode *)0;
1493: caddr_t bpos, dpos, cp2;
1494: int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0;
1495: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1496: struct vattr vattr;
1497: int v3 = NFS_ISV3(dvp);
1498:
1499: /*
1500: * Oops, not for me..
1501: */
1502: if (vap->va_type == VSOCK)
1503: return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
1504:
1505: if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
1506: VOP_ABORTOP(dvp, cnp);
1507: vput(dvp);
1508: return (error);
1509: }
1510: if (vap->va_vaflags & VA_EXCLUSIVE)
1511: fmode |= O_EXCL;
1512: again:
1513: nfsstats.rpccnt[NFSPROC_CREATE]++;
1514: nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
1515: nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
1516: nfsm_fhtom(dvp, v3);
1517: nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1518: if (v3) {
1519: nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1520: if (fmode & O_EXCL) {
1521: *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE);
1522: nfsm_build(tl, u_long *, NFSX_V3CREATEVERF);
1523: #ifdef notyet
1524: if (!TAILQ_EMPTY(&in_ifaddrhead))
1525: *tl++ = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr.s_addr;
1526: #else
1527: if (in_ifaddr)
1528: *tl++ = IA_SIN(in_ifaddr)->sin_addr.s_addr;
1529: #endif
1530: else
1531: *tl++ = create_verf;
1532: *tl = ++create_verf;
1533: } else {
1534: *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED);
1535: nfsm_build(tl, u_long *, NFSX_V3SRVSATTR);
1536: sp3 = (struct nfsv3_sattr *)tl;
1537: nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
1538: }
1539: } else {
1540: nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1541: sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1542: sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1543: sp->sa_gid = txdr_unsigned(vattr.va_gid);
1544: sp->sa_size = 0;
1545: txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1546: txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1547: }
1548: nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
1549: if (!error) {
1550: nfsm_mtofh(dvp, newvp, v3, gotvp);
1551: if (!gotvp) {
1552: if (newvp) {
1553: vput(newvp);
1554: newvp = (struct vnode *)0;
1555: }
1556: error = nfs_lookitup(dvp, cnp->cn_nameptr,
1557: cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
1558: if (!error)
1559: newvp = NFSTOV(np);
1560: }
1561: }
1562: if (v3)
1563: nfsm_wcc_data(dvp, wccflag);
1564: nfsm_reqdone;
1565: if (error) {
1566: if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) {
1567: fmode &= ~O_EXCL;
1568: goto again;
1569: }
1570: if (newvp)
1571: vput(newvp);
1572: } else if (v3 && (fmode & O_EXCL))
1573: error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
1574: if (!error) {
1575: if (cnp->cn_flags & MAKEENTRY)
1576: cache_enter(dvp, newvp, cnp);
1577: *ap->a_vpp = newvp;
1578: }
1579: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1580: VTONFS(dvp)->n_flag |= NMODIFIED;
1581: if (!wccflag)
1582: VTONFS(dvp)->n_attrstamp = 0;
1583: vput(dvp);
1584: return (error);
1585: }
1586:
1587: /*
1588: * nfs file remove call
1589: * To try and make nfs semantics closer to ufs semantics, a file that has
1590: * other processes using the vnode is renamed instead of removed and then
1591: * removed later on the last close.
1592: * - If v_usecount > 1
1593: * If a rename is not already in the works
1594: * call nfs_sillyrename() to set it up
1595: * else
1596: * do the remove rpc
1597: */
1598: static int
1599: nfs_remove(ap)
1600: struct vop_remove_args /* {
1601: struct vnodeop_desc *a_desc;
1602: struct vnode * a_dvp;
1603: struct vnode * a_vp;
1604: struct componentname * a_cnp;
1605: } */ *ap;
1606: {
1607: register struct vnode *vp = ap->a_vp;
1608: register struct vnode *dvp = ap->a_dvp;
1609: register struct componentname *cnp = ap->a_cnp;
1610: register struct nfsnode *np = VTONFS(vp);
1611: int error = 0;
1612: struct vattr vattr;
1613:
1614: #if DIAGNOSTIC
1615: if ((cnp->cn_flags & HASBUF) == 0)
1616: panic("nfs_remove: no name");
1617: if (vp->v_usecount < 1)
1618: panic("nfs_remove: bad v_usecount");
1619: #endif
1620: if (vp->v_usecount == 1 || (np->n_sillyrename &&
1621: VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 &&
1622: vattr.va_nlink > 1)) {
1623: /*
1624: * Purge the name cache so that the chance of a lookup for
1625: * the name succeeding while the remove is in progress is
1626: * minimized. Without node locking it can still happen, such
1627: * that an I/O op returns ESTALE, but since you get this if
1628: * another host removes the file..
1629: */
1630: cache_purge(vp);
1631: /*
1632: * throw away biocache buffers, mainly to avoid
1633: * unnecessary delayed writes later.
1634: */
1635: error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
1636: /* Do the rpc */
1637: if (error != EINTR)
1638: error = nfs_removerpc(dvp, cnp->cn_nameptr,
1639: cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc);
1640: /*
1641: * Kludge City: If the first reply to the remove rpc is lost..
1642: * the reply to the retransmitted request will be ENOENT
1643: * since the file was in fact removed
1644: * Therefore, we cheat and return success.
1645: */
1646: if (error == ENOENT)
1647: error = 0;
1648: } else if (!np->n_sillyrename)
1649: error = nfs_sillyrename(dvp, vp, cnp);
1650: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1651: np->n_attrstamp = 0;
1652: vput(dvp);
1653: if (vp == dvp)
1654: vrele(vp);
1655: else
1656: vput(vp);
1657: return (error);
1658: }
1659:
1660: /*
1661: * nfs file remove rpc called from nfs_inactive
1662: */
1663: int
1664: nfs_removeit(sp)
1665: register struct sillyrename *sp;
1666: {
1667:
1668: return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
1669: (struct proc *)0));
1670: }
1671:
1672: /*
1673: * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
1674: */
1675: static int
1676: nfs_removerpc(dvp, name, namelen, cred, proc)
1677: register struct vnode *dvp;
1678: char *name;
1679: int namelen;
1680: struct ucred *cred;
1681: struct proc *proc;
1682: {
1683: register u_long *tl;
1684: register caddr_t cp;
1685: register long t1, t2;
1686: caddr_t bpos, dpos, cp2;
1687: int error = 0, wccflag = NFSV3_WCCRATTR;
1688: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1689: int v3 = NFS_ISV3(dvp);
1690:
1691: nfsstats.rpccnt[NFSPROC_REMOVE]++;
1692: nfsm_reqhead(dvp, NFSPROC_REMOVE,
1693: NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
1694: nfsm_fhtom(dvp, v3);
1695: nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
1696: nfsm_request(dvp, NFSPROC_REMOVE, proc, cred);
1697: if (v3)
1698: nfsm_wcc_data(dvp, wccflag);
1699: nfsm_reqdone;
1700: VTONFS(dvp)->n_flag |= NMODIFIED;
1701: if (!wccflag)
1702: VTONFS(dvp)->n_attrstamp = 0;
1703: return (error);
1704: }
1705:
1706: /*
1707: * nfs file rename call
1708: */
1709: static int
1710: nfs_rename(ap)
1711: struct vop_rename_args /* {
1712: struct vnode *a_fdvp;
1713: struct vnode *a_fvp;
1714: struct componentname *a_fcnp;
1715: struct vnode *a_tdvp;
1716: struct vnode *a_tvp;
1717: struct componentname *a_tcnp;
1718: } */ *ap;
1719: {
1720: register struct vnode *fvp = ap->a_fvp;
1721: register struct vnode *tvp = ap->a_tvp;
1722: register struct vnode *fdvp = ap->a_fdvp;
1723: register struct vnode *tdvp = ap->a_tdvp;
1724: register struct componentname *tcnp = ap->a_tcnp;
1725: register struct componentname *fcnp = ap->a_fcnp;
1726: int error;
1727:
1728: #if DIAGNOSTIC
1729: if ((tcnp->cn_flags & HASBUF) == 0 ||
1730: (fcnp->cn_flags & HASBUF) == 0)
1731: panic("nfs_rename: no name");
1732: #endif
1733: /* Check for cross-device rename */
1734: if ((fvp->v_mount != tdvp->v_mount) ||
1735: (tvp && (fvp->v_mount != tvp->v_mount))) {
1736: error = EXDEV;
1737: goto out;
1738: }
1739:
1740: /*
1741: * If the tvp exists and is in use, sillyrename it before doing the
1742: * rename of the new file over it.
1743: * XXX Can't sillyrename a directory.
1744: */
1745: if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename &&
1746: tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) {
1747: vput(tvp);
1748: tvp = NULL;
1749: }
1750:
1751: error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
1752: tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
1753: tcnp->cn_proc);
1754:
1755: if (fvp->v_type == VDIR) {
1756: if (tvp != NULL && tvp->v_type == VDIR)
1757: cache_purge(tdvp);
1758: cache_purge(fdvp);
1759: }
1760: out:
1761: if (tdvp == tvp)
1762: vrele(tdvp);
1763: else
1764: vput(tdvp);
1765: if (tvp)
1766: vput(tvp);
1767: vrele(fdvp);
1768: vrele(fvp);
1769: /*
1770: * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
1771: */
1772: if (error == ENOENT)
1773: error = 0;
1774: return (error);
1775: }
1776:
1777: /*
1778: * nfs file rename rpc called from nfs_remove() above
1779: */
1780: static int
1781: nfs_renameit(sdvp, scnp, sp)
1782: struct vnode *sdvp;
1783: struct componentname *scnp;
1784: register struct sillyrename *sp;
1785: {
1786: return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen,
1787: sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_proc));
1788: }
1789:
1790: /*
1791: * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
1792: */
1793: static int
1794: nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc)
1795: register struct vnode *fdvp;
1796: char *fnameptr;
1797: int fnamelen;
1798: register struct vnode *tdvp;
1799: char *tnameptr;
1800: int tnamelen;
1801: struct ucred *cred;
1802: struct proc *proc;
1803: {
1804: register u_long *tl;
1805: register caddr_t cp;
1806: register long t1, t2;
1807: caddr_t bpos, dpos, cp2;
1808: int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
1809: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1810: int v3 = NFS_ISV3(fdvp);
1811:
1812: nfsstats.rpccnt[NFSPROC_RENAME]++;
1813: nfsm_reqhead(fdvp, NFSPROC_RENAME,
1814: (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
1815: nfsm_rndup(tnamelen));
1816: nfsm_fhtom(fdvp, v3);
1817: nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
1818: nfsm_fhtom(tdvp, v3);
1819: nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
1820: nfsm_request(fdvp, NFSPROC_RENAME, proc, cred);
1821: if (v3) {
1822: nfsm_wcc_data(fdvp, fwccflag);
1823: nfsm_wcc_data(tdvp, twccflag);
1824: }
1825: nfsm_reqdone;
1826: VTONFS(fdvp)->n_flag |= NMODIFIED;
1827: VTONFS(tdvp)->n_flag |= NMODIFIED;
1828: if (!fwccflag)
1829: VTONFS(fdvp)->n_attrstamp = 0;
1830: if (!twccflag)
1831: VTONFS(tdvp)->n_attrstamp = 0;
1832: return (error);
1833: }
1834:
1835: /*
1836: * nfs hard link create call
1837: */
1838: static int
1839: nfs_link(ap)
1840: struct vop_link_args /* {
1841: struct vnode *a_vp;
1842: struct vnode *a_tdvp;
1843: struct componentname *a_cnp;
1844: } */ *ap;
1845: {
1846: register struct vnode *vp = ap->a_vp;
1847: register struct vnode *tdvp = ap->a_tdvp;
1848: register struct componentname *cnp = ap->a_cnp;
1849: register u_long *tl;
1850: register caddr_t cp;
1851: register long t1, t2;
1852: caddr_t bpos, dpos, cp2;
1853: int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
1854: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1855: int v3 = NFS_ISV3(vp);
1856:
1857: if (vp->v_mount != tdvp->v_mount) {
1858: VOP_ABORTOP(vp, cnp);
1859: if (tdvp == vp)
1860: vrele(tdvp);
1861: else
1862: vput(tdvp);
1863: return (EXDEV);
1864: }
1865:
1866: /*
1867: * Push all writes to the server, so that the attribute cache
1868: * doesn't get "out of sync" with the server.
1869: * XXX There should be a better way!
1870: */
1871: VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc);
1872:
1873: nfsstats.rpccnt[NFSPROC_LINK]++;
1874: nfsm_reqhead(vp, NFSPROC_LINK,
1875: NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
1876: nfsm_fhtom(vp, v3);
1877: nfsm_fhtom(tdvp, v3);
1878: nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1879: nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
1880: if (v3) {
1881: nfsm_postop_attr(vp, attrflag);
1882: nfsm_wcc_data(tdvp, wccflag);
1883: }
1884: nfsm_reqdone;
1885: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1886: VTONFS(tdvp)->n_flag |= NMODIFIED;
1887: if (!attrflag)
1888: VTONFS(vp)->n_attrstamp = 0;
1889: if (!wccflag)
1890: VTONFS(tdvp)->n_attrstamp = 0;
1891: vput(tdvp);
1892: /*
1893: * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1894: */
1895: if (error == EEXIST)
1896: error = 0;
1897: return (error);
1898: }
1899:
1900: /*
1901: * nfs symbolic link create call
1902: */
1903: static int
1904: nfs_symlink(ap)
1905: struct vop_symlink_args /* {
1906: struct vnode *a_dvp;
1907: struct vnode **a_vpp;
1908: struct componentname *a_cnp;
1909: struct vattr *a_vap;
1910: char *a_target;
1911: } */ *ap;
1912: {
1913: register struct vnode *dvp = ap->a_dvp;
1914: register struct vattr *vap = ap->a_vap;
1915: register struct componentname *cnp = ap->a_cnp;
1916: register struct nfsv2_sattr *sp;
1917: register struct nfsv3_sattr *sp3;
1918: register u_long *tl;
1919: register caddr_t cp;
1920: register long t1, t2;
1921: caddr_t bpos, dpos, cp2;
1922: int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
1923: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1924: struct vnode *newvp = (struct vnode *)0;
1925: int v3 = NFS_ISV3(dvp);
1926:
1927: nfsstats.rpccnt[NFSPROC_SYMLINK]++;
1928: slen = strlen(ap->a_target);
1929: nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED +
1930: nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
1931: nfsm_fhtom(dvp, v3);
1932: nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1933: if (v3) {
1934: nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
1935: nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid,
1936: cnp->cn_cred->cr_gid);
1937: }
1938: nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
1939: if (!v3) {
1940: nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1941: sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode);
1942: sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1943: sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
1944: sp->sa_size = -1;
1945: txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1946: txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1947: }
1948: nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
1949: if (v3) {
1950: if (!error)
1951: nfsm_mtofh(dvp, newvp, v3, gotvp);
1952: nfsm_wcc_data(dvp, wccflag);
1953: }
1954: nfsm_reqdone;
1955: if (newvp)
1956: vput(newvp);
1957: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1958: VTONFS(dvp)->n_flag |= NMODIFIED;
1959: if (!wccflag)
1960: VTONFS(dvp)->n_attrstamp = 0;
1961: vput(dvp);
1962: /*
1963: * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1964: */
1965: if (error == EEXIST)
1966: error = 0;
1967: return (error);
1968: }
1969:
1970: /*
1971: * nfs make dir call
1972: */
1973: static int
1974: nfs_mkdir(ap)
1975: struct vop_mkdir_args /* {
1976: struct vnode *a_dvp;
1977: struct vnode **a_vpp;
1978: struct componentname *a_cnp;
1979: struct vattr *a_vap;
1980: } */ *ap;
1981: {
1982: register struct vnode *dvp = ap->a_dvp;
1983: register struct vattr *vap = ap->a_vap;
1984: register struct componentname *cnp = ap->a_cnp;
1985: register struct nfsv2_sattr *sp;
1986: register struct nfsv3_sattr *sp3;
1987: register u_long *tl;
1988: register caddr_t cp;
1989: register long t1, t2;
1990: register int len;
1991: struct nfsnode *np = (struct nfsnode *)0;
1992: struct vnode *newvp = (struct vnode *)0;
1993: caddr_t bpos, dpos, cp2;
1994: int error = 0, wccflag = NFSV3_WCCRATTR;
1995: int gotvp = 0;
1996: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1997: struct vattr vattr;
1998: int v3 = NFS_ISV3(dvp);
1999:
2000: if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
2001: VOP_ABORTOP(dvp, cnp);
2002: vput(dvp);
2003: return (error);
2004: }
2005: len = cnp->cn_namelen;
2006: nfsstats.rpccnt[NFSPROC_MKDIR]++;
2007: nfsm_reqhead(dvp, NFSPROC_MKDIR,
2008: NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
2009: nfsm_fhtom(dvp, v3);
2010: nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
2011: if (v3) {
2012: nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
2013: nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
2014: } else {
2015: nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2016: sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode);
2017: sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
2018: sp->sa_gid = txdr_unsigned(vattr.va_gid);
2019: sp->sa_size = -1;
2020: txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
2021: txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
2022: }
2023: nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
2024: if (!error)
2025: nfsm_mtofh(dvp, newvp, v3, gotvp);
2026: if (v3)
2027: nfsm_wcc_data(dvp, wccflag);
2028: nfsm_reqdone;
2029: VTONFS(dvp)->n_flag |= NMODIFIED;
2030: if (!wccflag)
2031: VTONFS(dvp)->n_attrstamp = 0;
2032: /*
2033: * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
2034: * if we can succeed in looking up the directory.
2035: */
2036: if (error == EEXIST || (!error && !gotvp)) {
2037: if (newvp) {
2038: vrele(newvp);
2039: newvp = (struct vnode *)0;
2040: }
2041: error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
2042: cnp->cn_proc, &np);
2043: if (!error) {
2044: newvp = NFSTOV(np);
2045: if (newvp->v_type != VDIR)
2046: error = EEXIST;
2047: }
2048: }
2049: if (error) {
2050: if (newvp)
2051: vrele(newvp);
2052: } else
2053: *ap->a_vpp = newvp;
2054: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
2055: vput(dvp);
2056: return (error);
2057: }
2058:
2059: /*
2060: * nfs remove directory call
2061: */
2062: static int
2063: nfs_rmdir(ap)
2064: struct vop_rmdir_args /* {
2065: struct vnode *a_dvp;
2066: struct vnode *a_vp;
2067: struct componentname *a_cnp;
2068: } */ *ap;
2069: {
2070: register struct vnode *vp = ap->a_vp;
2071: register struct vnode *dvp = ap->a_dvp;
2072: register struct componentname *cnp = ap->a_cnp;
2073: register u_long *tl;
2074: register caddr_t cp;
2075: register long t1, t2;
2076: caddr_t bpos, dpos, cp2;
2077: int error = 0, wccflag = NFSV3_WCCRATTR;
2078: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2079: int v3 = NFS_ISV3(dvp);
2080:
2081: nfsstats.rpccnt[NFSPROC_RMDIR]++;
2082: nfsm_reqhead(dvp, NFSPROC_RMDIR,
2083: NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
2084: nfsm_fhtom(dvp, v3);
2085: nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
2086: nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
2087: if (v3)
2088: nfsm_wcc_data(dvp, wccflag);
2089: nfsm_reqdone;
2090: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
2091: VTONFS(dvp)->n_flag |= NMODIFIED;
2092: if (!wccflag)
2093: VTONFS(dvp)->n_attrstamp = 0;
2094: cache_purge(dvp);
2095: cache_purge(vp);
2096: vput(vp);
2097: vput(dvp);
2098: /*
2099: * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2100: */
2101: if (error == ENOENT)
2102: error = 0;
2103: return (error);
2104: }
2105:
2106: /*
2107: * nfs readdir call
2108: */
2109: static int
2110: nfs_readdir(ap)
2111: struct vop_readdir_args /* {
2112: struct vnode *a_vp;
2113: struct uio *a_uio;
2114: struct ucred *a_cred;
2115: } */ *ap;
2116: {
2117: register struct vnode *vp = ap->a_vp;
2118: register struct nfsnode *np = VTONFS(vp);
2119: register struct uio *uio = ap->a_uio;
2120: int tresid, error;
2121: struct vattr vattr;
2122:
2123: if (vp->v_type != VDIR)
2124: return (EPERM);
2125: /*
2126: * First, check for hit on the EOF offset cache
2127: */
2128: if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset &&
2129: (np->n_flag & NMODIFIED) == 0) {
2130: if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
2131: if (NQNFS_CKCACHABLE(vp, ND_READ)) {
2132: nfsstats.direofcache_hits++;
2133: return (0);
2134: }
2135: } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
2136: np->n_mtime == vattr.va_mtime.tv_sec) {
2137: nfsstats.direofcache_hits++;
2138: return (0);
2139: }
2140: }
2141:
2142: /*
2143: * Call nfs_bioread() to do the real work.
2144: */
2145: tresid = uio->uio_resid;
2146: error = nfs_bioread(vp, uio, 0, ap->a_cred, 0);
2147:
2148: if (!error && uio->uio_resid == tresid)
2149: nfsstats.direofcache_misses++;
2150: return (error);
2151: }
2152:
2153: /*
2154: * Readdir rpc call.
2155: * Called from below the buffer cache by nfs_doio().
2156: */
2157: int
2158: nfs_readdirrpc(vp, uiop, cred)
2159: struct vnode *vp;
2160: register struct uio *uiop;
2161: struct ucred *cred;
2162:
2163: {
2164: register int len, left;
2165: register struct dirent *dp;
2166: register u_long *tl;
2167: register caddr_t cp;
2168: register long t1, t2;
2169: register nfsuint64 *cookiep;
2170: caddr_t bpos, dpos, cp2;
2171: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2172: nfsuint64 cookie;
2173: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2174: struct nfsnode *dnp = VTONFS(vp);
2175: u_quad_t fileno;
2176: int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2177: int attrflag;
2178: int v3 = NFS_ISV3(vp);
2179:
2180: #ifndef nolint
2181: dp = (struct dirent *)0;
2182: #endif
2183: #if DIAGNOSTIC
2184: if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (NFS_DIRBLKSIZ - 1)) ||
2185: (uiop->uio_resid & (NFS_DIRBLKSIZ - 1)))
2186: panic("nfs readdirrpc bad uio");
2187: #endif
2188:
2189: /*
2190: * If there is no cookie, assume directory was stale.
2191: */
2192: cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
2193: if (cookiep)
2194: cookie = *cookiep;
2195: else
2196: return (NFSERR_BAD_COOKIE);
2197: /*
2198: * Loop around doing readdir rpc's of size nm_readdirsize
2199: * truncated to a multiple of DIRBLKSIZ.
2200: * The stopping criteria is EOF or buffer full.
2201: */
2202: while (more_dirs && bigenough) {
2203: nfsstats.rpccnt[NFSPROC_READDIR]++;
2204: nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) +
2205: NFSX_READDIR(v3));
2206: nfsm_fhtom(vp, v3);
2207: if (v3) {
2208: nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
2209: *tl++ = cookie.nfsuquad[0];
2210: *tl++ = cookie.nfsuquad[1];
2211: *tl++ = dnp->n_cookieverf.nfsuquad[0];
2212: *tl++ = dnp->n_cookieverf.nfsuquad[1];
2213: } else {
2214: nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2215: *tl++ = cookie.nfsuquad[0];
2216: }
2217: *tl = txdr_unsigned(nmp->nm_readdirsize);
2218: nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
2219: if (v3) {
2220: nfsm_postop_attr(vp, attrflag);
2221: if (!error) {
2222: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2223: dnp->n_cookieverf.nfsuquad[0] = *tl++;
2224: dnp->n_cookieverf.nfsuquad[1] = *tl;
2225: } else {
2226: m_freem(mrep);
2227: goto nfsmout;
2228: }
2229: }
2230: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2231: more_dirs = fxdr_unsigned(int, *tl);
2232:
2233: /* loop thru the dir entries, doctoring them to 4bsd form */
2234: while (more_dirs && bigenough) {
2235: if (v3) {
2236: nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2237: fxdr_hyper(tl, &fileno);
2238: len = fxdr_unsigned(int, *(tl + 2));
2239: } else {
2240: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2241: fileno = fxdr_unsigned(u_quad_t, *tl++);
2242: len = fxdr_unsigned(int, *tl);
2243: }
2244: if (len <= 0 || len > NFS_MAXNAMLEN) {
2245: error = EBADRPC;
2246: m_freem(mrep);
2247: goto nfsmout;
2248: }
2249: tlen = nfsm_rndup(len);
2250: if (tlen == len)
2251: tlen += 4; /* To ensure null termination */
2252: left = DIRBLKSIZ - blksiz;
2253: if ((tlen + DIRHDSIZ) > left) {
2254: dp->d_reclen += left;
2255: uiop->uio_iov->iov_base += left;
2256: uiop->uio_iov->iov_len -= left;
2257: uiop->uio_offset += left;
2258: uiop->uio_resid -= left;
2259: blksiz = 0;
2260: }
2261: if ((tlen + DIRHDSIZ) > uiop->uio_resid)
2262: bigenough = 0;
2263: if (bigenough) {
2264: dp = (struct dirent *)uiop->uio_iov->iov_base;
2265: dp->d_fileno = (int)fileno;
2266: dp->d_namlen = len;
2267: dp->d_reclen = tlen + DIRHDSIZ;
2268: dp->d_type = DT_UNKNOWN;
2269: blksiz += dp->d_reclen;
2270: if (blksiz == DIRBLKSIZ)
2271: blksiz = 0;
2272: uiop->uio_offset += DIRHDSIZ;
2273: uiop->uio_resid -= DIRHDSIZ;
2274: uiop->uio_iov->iov_base += DIRHDSIZ;
2275: uiop->uio_iov->iov_len -= DIRHDSIZ;
2276: nfsm_mtouio(uiop, len);
2277: cp = uiop->uio_iov->iov_base;
2278: tlen -= len;
2279: *cp = '\0'; /* null terminate */
2280: uiop->uio_iov->iov_base += tlen;
2281: uiop->uio_iov->iov_len -= tlen;
2282: uiop->uio_offset += tlen;
2283: uiop->uio_resid -= tlen;
2284: } else
2285: nfsm_adv(nfsm_rndup(len));
2286: if (v3) {
2287: nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2288: } else {
2289: nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2290: }
2291: if (bigenough) {
2292: cookie.nfsuquad[0] = *tl++;
2293: if (v3)
2294: cookie.nfsuquad[1] = *tl++;
2295: } else if (v3)
2296: tl += 2;
2297: else
2298: tl++;
2299: more_dirs = fxdr_unsigned(int, *tl);
2300: }
2301: /*
2302: * If at end of rpc data, get the eof boolean
2303: */
2304: if (!more_dirs) {
2305: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2306: more_dirs = (fxdr_unsigned(int, *tl) == 0);
2307: }
2308: m_freem(mrep);
2309: }
2310: /*
2311: * Fill last record, iff any, out to a multiple of DIRBLKSIZ
2312: * by increasing d_reclen for the last record.
2313: */
2314: if (blksiz > 0) {
2315: left = DIRBLKSIZ - blksiz;
2316: dp->d_reclen += left;
2317: uiop->uio_iov->iov_base += left;
2318: uiop->uio_iov->iov_len -= left;
2319: uiop->uio_offset += left;
2320: uiop->uio_resid -= left;
2321: }
2322:
2323: /*
2324: * We are now either at the end of the directory or have filled the
2325: * block.
2326: */
2327: if (bigenough)
2328: dnp->n_direofoffset = uiop->uio_offset;
2329: else {
2330: if (uiop->uio_resid > 0)
2331: printf("EEK! readdirrpc resid > 0\n");
2332: cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
2333: *cookiep = cookie;
2334: }
2335: nfsmout:
2336: return (error);
2337: }
2338:
2339: /*
2340: * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
2341: */
2342: int
2343: nfs_readdirplusrpc(vp, uiop, cred)
2344: struct vnode *vp;
2345: register struct uio *uiop;
2346: struct ucred *cred;
2347: {
2348: register int len, left;
2349: register struct dirent *dp;
2350: register u_long *tl;
2351: register caddr_t cp;
2352: register long t1, t2;
2353: register struct vnode *newvp;
2354: register nfsuint64 *cookiep;
2355: caddr_t bpos, dpos, cp2, dpossav1, dpossav2;
2356: struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2;
2357: struct nameidata nami, *ndp = &nami;
2358: struct componentname *cnp = &ndp->ni_cnd;
2359: nfsuint64 cookie;
2360: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2361: struct nfsnode *dnp = VTONFS(vp), *np;
2362: nfsfh_t *fhp;
2363: u_quad_t fileno;
2364: int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
2365: int attrflag, fhsize;
2366:
2367: #ifndef nolint
2368: dp = (struct dirent *)0;
2369: #endif
2370: #if DIAGNOSTIC
2371: if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) ||
2372: (uiop->uio_resid & (DIRBLKSIZ - 1)))
2373: panic("nfs readdirplusrpc bad uio");
2374: #endif
2375: ndp->ni_dvp = vp;
2376: newvp = NULLVP;
2377:
2378: /*
2379: * If there is no cookie, assume directory was stale.
2380: */
2381: cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
2382: if (cookiep)
2383: cookie = *cookiep;
2384: else
2385: return (NFSERR_BAD_COOKIE);
2386: /*
2387: * Loop around doing readdir rpc's of size nm_readdirsize
2388: * truncated to a multiple of DIRBLKSIZ.
2389: * The stopping criteria is EOF or buffer full.
2390: */
2391: while (more_dirs && bigenough) {
2392: nfsstats.rpccnt[NFSPROC_READDIRPLUS]++;
2393: nfsm_reqhead(vp, NFSPROC_READDIRPLUS,
2394: NFSX_FH(1) + 6 * NFSX_UNSIGNED);
2395: nfsm_fhtom(vp, 1);
2396: nfsm_build(tl, u_long *, 6 * NFSX_UNSIGNED);
2397: *tl++ = cookie.nfsuquad[0];
2398: *tl++ = cookie.nfsuquad[1];
2399: *tl++ = dnp->n_cookieverf.nfsuquad[0];
2400: *tl++ = dnp->n_cookieverf.nfsuquad[1];
2401: *tl++ = txdr_unsigned(nmp->nm_readdirsize);
2402: *tl = txdr_unsigned(nmp->nm_rsize);
2403: nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred);
2404: nfsm_postop_attr(vp, attrflag);
2405: if (error) {
2406: m_freem(mrep);
2407: goto nfsmout;
2408: }
2409: nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2410: dnp->n_cookieverf.nfsuquad[0] = *tl++;
2411: dnp->n_cookieverf.nfsuquad[1] = *tl++;
2412: more_dirs = fxdr_unsigned(int, *tl);
2413:
2414: /* loop thru the dir entries, doctoring them to 4bsd form */
2415: while (more_dirs && bigenough) {
2416: nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2417: fxdr_hyper(tl, &fileno);
2418: len = fxdr_unsigned(int, *(tl + 2));
2419: if (len <= 0 || len > NFS_MAXNAMLEN) {
2420: error = EBADRPC;
2421: m_freem(mrep);
2422: goto nfsmout;
2423: }
2424: tlen = nfsm_rndup(len);
2425: if (tlen == len)
2426: tlen += 4; /* To ensure null termination*/
2427: left = DIRBLKSIZ - blksiz;
2428: if ((tlen + DIRHDSIZ) > left) {
2429: dp->d_reclen += left;
2430: uiop->uio_iov->iov_base += left;
2431: uiop->uio_iov->iov_len -= left;
2432: uiop->uio_offset += left;
2433: uiop->uio_resid -= left;
2434: blksiz = 0;
2435: }
2436: if ((tlen + DIRHDSIZ) > uiop->uio_resid)
2437: bigenough = 0;
2438: if (bigenough) {
2439: dp = (struct dirent *)uiop->uio_iov->iov_base;
2440: dp->d_fileno = (int)fileno;
2441: dp->d_namlen = len;
2442: dp->d_reclen = tlen + DIRHDSIZ;
2443: dp->d_type = DT_UNKNOWN;
2444: blksiz += dp->d_reclen;
2445: if (blksiz == DIRBLKSIZ)
2446: blksiz = 0;
2447: uiop->uio_offset += DIRHDSIZ;
2448: uiop->uio_resid -= DIRHDSIZ;
2449: uiop->uio_iov->iov_base += DIRHDSIZ;
2450: uiop->uio_iov->iov_len -= DIRHDSIZ;
2451: cnp->cn_nameptr = uiop->uio_iov->iov_base;
2452: cnp->cn_namelen = len;
2453: nfsm_mtouio(uiop, len);
2454: cp = uiop->uio_iov->iov_base;
2455: tlen -= len;
2456: *cp = '\0';
2457: uiop->uio_iov->iov_base += tlen;
2458: uiop->uio_iov->iov_len -= tlen;
2459: uiop->uio_offset += tlen;
2460: uiop->uio_resid -= tlen;
2461: } else
2462: nfsm_adv(nfsm_rndup(len));
2463: nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2464: if (bigenough) {
2465: cookie.nfsuquad[0] = *tl++;
2466: cookie.nfsuquad[1] = *tl++;
2467: } else
2468: tl += 2;
2469:
2470: /*
2471: * Since the attributes are before the file handle
2472: * (sigh), we must skip over the attributes and then
2473: * come back and get them.
2474: */
2475: attrflag = fxdr_unsigned(int, *tl);
2476: if (attrflag) {
2477: dpossav1 = dpos;
2478: mdsav1 = md;
2479: nfsm_adv(NFSX_V3FATTR);
2480: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2481: doit = fxdr_unsigned(int, *tl);
2482: if (doit) {
2483: nfsm_getfh(fhp, fhsize, 1);
2484: if (NFS_CMPFH(dnp, fhp, fhsize)) {
2485: VREF(vp);
2486: newvp = vp;
2487: np = dnp;
2488: } else {
2489: if ((error = nfs_nget(vp->v_mount, fhp,
2490: fhsize, &np)))
2491: doit = 0;
2492: else
2493: newvp = NFSTOV(np);
2494: }
2495: }
2496: if (doit) {
2497: dpossav2 = dpos;
2498: dpos = dpossav1;
2499: mdsav2 = md;
2500: md = mdsav1;
2501: nfsm_loadattr(newvp, (struct vattr *)0);
2502: dpos = dpossav2;
2503: md = mdsav2;
2504: dp->d_type =
2505: IFTODT(VTTOIF(np->n_vattr.va_type));
2506: ndp->ni_vp = newvp;
2507: cnp->cn_hash = 0;
2508: for (cp = cnp->cn_nameptr, i = 1; i <= len;
2509: i++, cp++)
2510: cnp->cn_hash += (unsigned char)*cp * i;
2511: if (cnp->cn_namelen <= NCHNAMLEN)
2512: cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
2513: }
2514: } else {
2515: /* Just skip over the file handle */
2516: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2517: i = fxdr_unsigned(int, *tl);
2518: nfsm_adv(nfsm_rndup(i));
2519: }
2520: if (newvp != NULLVP) {
2521: vrele(newvp);
2522: newvp = NULLVP;
2523: }
2524: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2525: more_dirs = fxdr_unsigned(int, *tl);
2526: }
2527: /*
2528: * If at end of rpc data, get the eof boolean
2529: */
2530: if (!more_dirs) {
2531: nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2532: more_dirs = (fxdr_unsigned(int, *tl) == 0);
2533: }
2534: m_freem(mrep);
2535: }
2536: /*
2537: * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
2538: * by increasing d_reclen for the last record.
2539: */
2540: if (blksiz > 0) {
2541: left = DIRBLKSIZ - blksiz;
2542: dp->d_reclen += left;
2543: uiop->uio_iov->iov_base += left;
2544: uiop->uio_iov->iov_len -= left;
2545: uiop->uio_offset += left;
2546: uiop->uio_resid -= left;
2547: }
2548:
2549: /*
2550: * We are now either at the end of the directory or have filled the
2551: * block.
2552: */
2553: if (bigenough)
2554: dnp->n_direofoffset = uiop->uio_offset;
2555: else {
2556: if (uiop->uio_resid > 0)
2557: printf("EEK! readdirplusrpc resid > 0\n");
2558: cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
2559: *cookiep = cookie;
2560: }
2561: nfsmout:
2562: if (newvp != NULLVP) {
2563: if (newvp == vp)
2564: vrele(newvp);
2565: else
2566: vput(newvp);
2567: newvp = NULLVP;
2568: }
2569: return (error);
2570: }
2571:
2572: /*
2573: * Silly rename. To make the NFS filesystem that is stateless look a little
2574: * more like the "ufs" a remove of an active vnode is translated to a rename
2575: * to a funny looking filename that is removed by nfs_inactive on the
2576: * nfsnode. There is the potential for another process on a different client
2577: * to create the same funny name between the nfs_lookitup() fails and the
2578: * nfs_rename() completes, but...
2579: */
2580: static int
2581: nfs_sillyrename(dvp, vp, cnp)
2582: struct vnode *dvp, *vp;
2583: struct componentname *cnp;
2584: {
2585: register struct sillyrename *sp;
2586: struct nfsnode *np;
2587: int error;
2588: short pid;
1.1.1.2 ! root 2589: struct ucred *cred;
1.1 root 2590:
2591: cache_purge(dvp);
2592: np = VTONFS(vp);
2593: #if DIAGNOSTIC
2594: if (vp->v_type == VDIR)
2595: panic("nfs: sillyrename dir");
2596: #endif
2597: MALLOC_ZONE(sp, struct sillyrename *,
2598: sizeof (struct sillyrename), M_NFSREQ, M_WAITOK);
2599: sp->s_cred = crdup(cnp->cn_cred);
2600: sp->s_dvp = dvp;
2601: VREF(dvp);
2602:
2603: /* Fudge together a funny name */
2604: pid = cnp->cn_proc->p_pid;
2605: sp->s_namlen = sprintf(sp->s_name, ".nfsA%04x4.4", pid);
2606:
2607: /* Try lookitups until we get one that isn't there */
2608: while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
2609: cnp->cn_proc, (struct nfsnode **)0) == 0) {
2610: sp->s_name[4]++;
2611: if (sp->s_name[4] > 'z') {
2612: error = EINVAL;
2613: goto bad;
2614: }
2615: }
2616: if ((error = nfs_renameit(dvp, cnp, sp)))
2617: goto bad;
2618: error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
2619: cnp->cn_proc, &np);
1.1.1.2 ! root 2620: NFS_DPF(SILLY,
! 2621: ("nfs_sillyrename: %s, vp=%x, np=%x, dvp=%x\n",
! 2622: &sp->s_name[0], (unsigned)vp, (unsigned)np, (unsigned)dvp));
1.1 root 2623: np->n_sillyrename = sp;
2624: return (0);
2625: bad:
2626: vrele(sp->s_dvp);
2627: cred = sp->s_cred;
2628: sp->s_cred = NOCRED;
2629: crfree(cred);
2630: _FREE_ZONE((caddr_t)sp, sizeof (struct sillyrename), M_NFSREQ);
2631: return (error);
2632: }
2633:
2634: /*
2635: * Look up a file name and optionally either update the file handle or
2636: * allocate an nfsnode, depending on the value of npp.
2637: * npp == NULL --> just do the lookup
2638: * *npp == NULL --> allocate a new nfsnode and make sure attributes are
2639: * handled too
2640: * *npp != NULL --> update the file handle in the vnode
2641: */
2642: static int
2643: nfs_lookitup(dvp, name, len, cred, procp, npp)
2644: register struct vnode *dvp;
2645: char *name;
2646: int len;
2647: struct ucred *cred;
2648: struct proc *procp;
2649: struct nfsnode **npp;
2650: {
2651: register u_long *tl;
2652: register caddr_t cp;
2653: register long t1, t2;
2654: struct vnode *newvp = (struct vnode *)0;
2655: struct nfsnode *np, *dnp = VTONFS(dvp);
2656: caddr_t bpos, dpos, cp2;
2657: int error = 0, fhlen, attrflag;
2658: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2659: nfsfh_t *nfhp;
2660: int v3 = NFS_ISV3(dvp);
2661:
2662: nfsstats.rpccnt[NFSPROC_LOOKUP]++;
2663: nfsm_reqhead(dvp, NFSPROC_LOOKUP,
2664: NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
2665: nfsm_fhtom(dvp, v3);
2666: nfsm_strtom(name, len, NFS_MAXNAMLEN);
2667: nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred);
2668: if (npp && !error) {
2669: nfsm_getfh(nfhp, fhlen, v3);
2670: if (*npp) {
2671: np = *npp;
2672: if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
2673: _FREE_ZONE((caddr_t)np->n_fhp,
2674: np->n_fhsize, M_NFSBIGFH);
2675: np->n_fhp = &np->n_fh;
2676: } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH)
2677: MALLOC_ZONE(np->n_fhp, nfsfh_t *,
2678: fhlen, M_NFSBIGFH, M_WAITOK);
2679: bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen);
2680: np->n_fhsize = fhlen;
2681: newvp = NFSTOV(np);
2682: } else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
2683: VREF(dvp);
2684: newvp = dvp;
2685: } else {
2686: error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
2687: if (error) {
2688: m_freem(mrep);
2689: return (error);
2690: }
2691: newvp = NFSTOV(np);
2692: }
2693: if (v3) {
2694: nfsm_postop_attr(newvp, attrflag);
2695: if (!attrflag && *npp == NULL) {
2696: m_freem(mrep);
2697: if (newvp == dvp)
2698: vrele(newvp);
2699: else
2700: vput(newvp);
2701: return (ENOENT);
2702: }
2703: } else
2704: nfsm_loadattr(newvp, (struct vattr *)0);
2705: }
2706: nfsm_reqdone;
2707: if (npp && *npp == NULL) {
2708: if (error) {
2709: if (newvp)
2710: if (newvp == dvp)
2711: vrele(newvp);
2712: else
2713: vput(newvp);
2714: } else
2715: *npp = np;
2716: }
2717: return (error);
2718: }
2719:
2720: /*
2721: * Nfs Version 3 commit rpc
2722: */
2723: static int
2724: nfs_commit(vp, offset, cnt, cred, procp)
2725: register struct vnode *vp;
2726: u_quad_t offset;
2727: int cnt;
2728: struct ucred *cred;
2729: struct proc *procp;
2730: {
2731: register caddr_t cp;
2732: register u_long *tl;
2733: register int t1, t2;
2734: register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2735: caddr_t bpos, dpos, cp2;
2736: int error = 0, wccflag = NFSV3_WCCRATTR;
2737: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2738:
2739: if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0)
2740: return (0);
2741: nfsstats.rpccnt[NFSPROC_COMMIT]++;
2742: nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1));
2743: nfsm_fhtom(vp, 1);
2744: nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
2745: txdr_hyper(&offset, tl);
2746: tl += 2;
2747: *tl = txdr_unsigned(cnt);
2748: nfsm_request(vp, NFSPROC_COMMIT, procp, cred);
2749: nfsm_wcc_data(vp, wccflag);
2750: if (!error) {
2751: nfsm_dissect(tl, u_long *, NFSX_V3WRITEVERF);
2752: if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl,
2753: NFSX_V3WRITEVERF)) {
2754: bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
2755: NFSX_V3WRITEVERF);
2756: error = NFSERR_STALEWRITEVERF;
2757: }
2758: }
2759: nfsm_reqdone;
2760: return (error);
2761: }
2762:
2763: /*
2764: * Kludge City..
2765: * - make nfs_bmap() essentially a no-op that does no translation
2766: * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc
2767: * (Maybe I could use the process's page mapping, but I was concerned that
2768: * Kernel Write might not be enabled and also figured copyout() would do
2769: * a lot more work than bcopy() and also it currently happens in the
2770: * context of the swapper process (2).
2771: */
2772: static int
2773: nfs_bmap(ap)
2774: struct vop_bmap_args /* {
2775: struct vnode *a_vp;
2776: daddr_t a_bn;
2777: struct vnode **a_vpp;
2778: daddr_t *a_bnp;
2779: int *a_runp;
2780: int *a_runb;
2781: } */ *ap;
2782: {
2783: register struct vnode *vp = ap->a_vp;
2784: #ifdef NeXT
2785: #warning nfs_bmap hardcoded devblocksize
2786: int devBlockSize=1024;
2787: #endif /* NeXT */
2788:
2789: if (ap->a_vpp != NULL)
2790: *ap->a_vpp = vp;
2791: if (ap->a_bnp != NULL)
2792: #ifdef NeXT
2793: *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize,
2794: devBlockSize);
2795: #else
2796: *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
2797: #endif /* NeXT */
2798: if (ap->a_runp != NULL)
2799: *ap->a_runp = 0;
2800: #ifdef notyet
2801: if (ap->a_runb != NULL)
2802: *ap->a_runb = 0;
2803: #endif
2804: return (0);
2805: }
2806:
2807: /*
2808: * Strategy routine.
2809: * For async requests when nfsiod(s) are running, queue the request by
2810: * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
2811: * request.
2812: */
2813: static int
2814: nfs_strategy(ap)
2815: struct vop_strategy_args *ap;
2816: {
2817: register struct buf *bp = ap->a_bp;
2818: struct ucred *cr;
2819: struct proc *p;
2820: int error = 0;
2821:
2822: if (bp->b_flags & B_PHYS)
2823: panic("nfs physio");
2824: if (bp->b_flags & B_ASYNC)
2825: p = (struct proc *)0;
2826: else
2827: p = current_proc(); /* XXX */
2828: if (bp->b_flags & B_READ)
2829: cr = bp->b_rcred;
2830: else
2831: cr = bp->b_wcred;
2832: /*
2833: * If the op is asynchronous and an i/o daemon is waiting
2834: * queue the request, wake it up and wait for completion
2835: * otherwise just do it ourselves.
2836: */
2837: if ((bp->b_flags & B_ASYNC) == 0 ||
2838: nfs_asyncio(bp, NOCRED))
2839: error = nfs_doio(bp, cr, p);
2840: return (error);
2841: }
2842:
2843: /*
2844: * Mmap a file
2845: *
2846: * NB Currently unsupported.
2847: */
2848: /* ARGSUSED */
2849: static int
2850: nfs_mmap(ap)
2851: struct vop_mmap_args /* {
2852: struct vnode *a_vp;
2853: int a_fflags;
2854: struct ucred *a_cred;
2855: struct proc *a_p;
2856: } */ *ap;
2857: {
2858:
2859: return (EINVAL);
2860: }
2861:
2862: /*
2863: * fsync vnode op. Just call nfs_flush() with commit == 1.
2864: */
2865: /* ARGSUSED */
2866: static int
2867: nfs_fsync(ap)
2868: struct vop_fsync_args /* {
2869: struct vnodeop_desc *a_desc;
2870: struct vnode * a_vp;
2871: struct ucred * a_cred;
2872: int a_waitfor;
2873: struct proc * a_p;
2874: } */ *ap;
2875: {
2876:
2877: return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));
2878: }
2879:
2880: /*
2881: * Flush all the blocks associated with a vnode.
2882: * Walk through the buffer pool and push any dirty pages
2883: * associated with the vnode.
2884: */
2885: static int
2886: nfs_flush(vp, cred, waitfor, p, commit)
2887: register struct vnode *vp;
2888: struct ucred *cred;
2889: int waitfor;
2890: struct proc *p;
2891: int commit;
2892: {
2893: register struct nfsnode *np = VTONFS(vp);
2894: register struct buf *bp;
2895: register int i;
2896: struct buf *nbp;
2897: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2898: int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
2899: int passone = 1;
2900: u_quad_t off, endoff, toff;
2901: struct ucred* wcred = NULL;
2902: struct buf **bvec = NULL;
2903: #ifndef NFS_COMMITBVECSIZ
2904: #define NFS_COMMITBVECSIZ 20
2905: #endif
2906: struct buf *bvec_on_stack[NFS_COMMITBVECSIZ];
2907: int bvecsize = 0, bveccount;
2908:
2909: if (nmp->nm_flag & NFSMNT_INT)
2910: slpflag = PCATCH;
2911: if (!commit)
2912: passone = 0;
2913: /*
2914: * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the
2915: * server, but nas not been committed to stable storage on the server
2916: * yet. On the first pass, the byte range is worked out and the commit
2917: * rpc is done. On the second pass, nfs_writebp() is called to do the
2918: * job.
2919: */
2920: again:
2921: if (vp->v_dirtyblkhd.lh_first)
2922: np->n_flag |= NMODIFIED;
2923: off = (u_quad_t)-1;
2924: endoff = 0;
2925: bvecpos = 0;
2926: if (NFS_ISV3(vp) && commit) {
2927: s = splbio();
2928: /*
2929: * Count up how many buffers waiting for a commit.
2930: */
2931: bveccount = 0;
2932: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2933: nbp = bp->b_vnbufs.le_next;
2934: if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
2935: == (B_DELWRI | B_NEEDCOMMIT))
2936: bveccount++;
2937: }
2938: /*
2939: * Allocate space to remember the list of bufs to commit. It is
2940: * important to use M_NOWAIT here to avoid a race with nfs_write.
2941: * If we can't get memory (for whatever reason), we will end up
2942: * committing the buffers one-by-one in the loop below.
2943: */
2944: if (bveccount > NFS_COMMITBVECSIZ) {
2945: if (bvec != NULL && bvec != bvec_on_stack)
2946: _FREE(bvec, M_TEMP);
2947: MALLOC(bvec, struct buf **,
2948: bveccount * sizeof(struct buf *), M_TEMP, M_NOWAIT);
2949: if (bvec == NULL) {
2950: bvec = bvec_on_stack;
2951: bvecsize = NFS_COMMITBVECSIZ;
2952: } else
2953: bvecsize = bveccount;
2954: } else {
2955: bvec = bvec_on_stack;
2956: bvecsize = NFS_COMMITBVECSIZ;
2957: }
2958: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2959: nbp = bp->b_vnbufs.le_next;
2960: if (bvecpos >= bvecsize)
2961: break;
2962: if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
2963: != (B_DELWRI | B_NEEDCOMMIT))
2964: continue;
2965: bremfree(bp);
2966: /*
2967: * Work out if all buffers are using the same cred
2968: * so we can deal with them all with one commit.
2969: */
2970: if (wcred == NULL)
2971: wcred = bp->b_wcred;
2972: else if (wcred != bp->b_wcred)
2973: wcred = NOCRED;
2974: bp->b_flags |= (B_BUSY | B_WRITEINPROG);
2975: vfs_busy_pages(bp, 1);
2976: /*
2977: * A list of these buffers is kept so that the
2978: * second loop knows which buffers have actually
2979: * been committed. This is necessary, since there
2980: * may be a race between the commit rpc and new
2981: * uncommitted writes on the file.
2982: */
2983: bvec[bvecpos++] = bp;
2984: toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
2985: bp->b_dirtyoff;
2986: if (toff < off)
2987: off = toff;
2988: toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff);
2989: if (toff > endoff)
2990: endoff = toff;
2991: }
2992: splx(s);
2993: }
2994: if (bvecpos > 0) {
2995: /*
2996: * Commit data on the server, as required.
2997: * If all bufs are using the same wcred, then use that with
2998: * one call for all of them, otherwise commit each one
2999: * separately.
3000: */
3001: if (wcred != NOCRED)
3002: retv = nfs_commit(vp, off, (int)(endoff - off),
3003: wcred, p);
3004: else {
3005: retv = 0;
3006: for (i = 0; i < bvecpos; i++) {
3007: off_t off, size;
3008: bp = bvec[i];
3009: off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
3010: bp->b_dirtyoff;
3011: size = (u_quad_t)(bp->b_dirtyend
3012: - bp->b_dirtyoff);
3013: retv = nfs_commit(vp, off, (int)size,
3014: bp->b_wcred, p);
3015: if (retv) break;
3016: }
3017: }
3018:
3019: if (retv == NFSERR_STALEWRITEVERF)
3020: nfs_clearcommit(vp->v_mount);
3021: /*
3022: * Now, either mark the blocks I/O done or mark the
3023: * blocks dirty, depending on whether the commit
3024: * succeeded.
3025: */
3026: for (i = 0; i < bvecpos; i++) {
3027: bp = bvec[i];
3028: bp->b_flags &= ~(B_NEEDCOMMIT | B_WRITEINPROG);
3029: if (retv) {
3030: vfs_unbusy_pages(bp);
3031: brelse(bp);
3032: } else {
3033: vp->v_numoutput++;
3034: bp->b_flags |= B_ASYNC;
3035: /* XXX CSM 12/4/97 Revisit when buffer cache upgraded */
3036: #ifdef notyet
3037: if (bp->b_flags & B_DELWRI) {
3038: --numdirtybuffers;
3039: if (needsbuffer) {
3040: vfs_bio_need_satisfy();
3041: }
3042: }
3043: #endif
3044: s = splbio();
3045: bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
3046: bp->b_dirtyoff = bp->b_dirtyend = 0;
3047: reassignbuf(bp, vp);
3048: splx(s);
3049: biodone(bp);
3050: }
3051: }
3052: }
3053:
3054: /*
3055: * Start/do any write(s) that are required.
3056: */
3057: loop:
3058: s = splbio();
3059: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
3060: nbp = bp->b_vnbufs.le_next;
3061: if (bp->b_flags & B_BUSY) {
3062: if (waitfor != MNT_WAIT || passone)
3063: continue;
3064: bp->b_flags |= B_WANTED;
3065: error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
3066: "nfsfsync", slptimeo);
3067: splx(s);
3068: if (error) {
3069: if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) {
3070: error = EINTR;
3071: goto done;
3072: }
3073: if (slpflag == PCATCH) {
3074: slpflag = 0;
3075: slptimeo = 2 * hz;
3076: }
3077: }
3078: goto loop;
3079: }
3080: if ((bp->b_flags & B_DELWRI) == 0)
3081: panic("nfs_fsync: not dirty");
3082: if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT))
3083: continue;
3084: bremfree(bp);
3085: if (passone || !commit)
3086: bp->b_flags |= (B_BUSY|B_ASYNC);
3087: else
3088: bp->b_flags |= (B_BUSY|B_ASYNC|B_WRITEINPROG|B_NEEDCOMMIT);
3089: splx(s);
3090: VOP_BWRITE(bp);
3091: goto loop;
3092: }
3093: splx(s);
3094: if (passone) {
3095: passone = 0;
3096: goto again;
3097: }
3098: if (waitfor == MNT_WAIT) {
3099: while (vp->v_numoutput) {
3100: vp->v_flag |= VBWAIT;
3101: error = tsleep((caddr_t)&vp->v_numoutput,
3102: slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
3103: if (error) {
3104: if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) {
3105: error = EINTR;
3106: goto done;
3107: }
3108: if (slpflag == PCATCH) {
3109: slpflag = 0;
3110: slptimeo = 2 * hz;
3111: }
3112: }
3113: }
3114: if (vp->v_dirtyblkhd.lh_first && commit) {
3115: goto loop;
3116: }
3117: }
3118: if (np->n_flag & NWRITEERR) {
3119: error = np->n_error;
3120: np->n_flag &= ~NWRITEERR;
3121: }
3122: done:
3123: if (bvec != NULL && bvec != bvec_on_stack)
3124: _FREE(bvec, M_TEMP);
3125: return (error);
3126: }
3127:
3128: /*
3129: * Return POSIX pathconf information applicable to nfs.
3130: *
3131: * The NFS V2 protocol doesn't support this, so just return EINVAL
3132: * for V2.
3133: */
3134: /* ARGSUSED */
3135: static int
3136: nfs_pathconf(ap)
3137: struct vop_pathconf_args /* {
3138: struct vnode *a_vp;
3139: int a_name;
3140: int *a_retval;
3141: } */ *ap;
3142: {
3143:
3144: return (EINVAL);
3145: }
3146:
3147: /*
3148: * NFS advisory byte-level locks.
3149: * Currently unsupported.
3150: */
3151: static int
3152: nfs_advlock(ap)
3153: struct vop_advlock_args /* {
3154: struct vnode *a_vp;
3155: caddr_t a_id;
3156: int a_op;
3157: struct flock *a_fl;
3158: int a_flags;
3159: } */ *ap;
3160: {
3161: #ifdef __FreeBSD__
3162: register struct nfsnode *np = VTONFS(ap->a_vp);
3163:
3164: /*
3165: * The following kludge is to allow diskless support to work
3166: * until a real NFS lockd is implemented. Basically, just pretend
3167: * that this is a local lock.
3168: */
3169: return (lf_advlock(ap, &(np->n_lockf), np->n_size));
3170: #else
3171: #if DIAGNOSTIC
1.1.1.2 ! root 3172: printf("nfs_advlock: pid %d comm %s\n", current_proc()->p_pid, current_proc()->p_comm);
1.1 root 3173: #endif
3174: return (EOPNOTSUPP);
3175: #endif
3176: }
3177:
3178: /*
3179: * Print out the contents of an nfsnode.
3180: */
3181: static int
3182: nfs_print(ap)
3183: struct vop_print_args /* {
3184: struct vnode *a_vp;
3185: } */ *ap;
3186: {
3187: register struct vnode *vp = ap->a_vp;
3188: register struct nfsnode *np = VTONFS(vp);
3189:
3190: printf("tag VT_NFS, fileid %ld fsid 0x%lx",
3191: np->n_vattr.va_fileid, np->n_vattr.va_fsid);
3192: if (vp->v_type == VFIFO)
3193: fifo_printinfo(vp);
3194: printf("\n");
3195: return (0);
3196: }
3197:
3198: /*
3199: * NFS directory offset lookup.
3200: * Currently unsupported.
3201: */
3202: static int
3203: nfs_blkatoff(ap)
3204: struct vop_blkatoff_args /* {
3205: struct vnode *a_vp;
3206: off_t a_offset;
3207: char **a_res;
3208: struct buf **a_bpp;
3209: } */ *ap;
3210: {
3211:
3212: #if DIAGNOSTIC
3213: printf("nfs_blkatoff: unimplemented!!");
3214: #endif
3215: return (EOPNOTSUPP);
3216: }
3217:
3218: /*
3219: * NFS flat namespace allocation.
3220: * Currently unsupported.
3221: */
3222: static int
3223: nfs_valloc(ap)
3224: struct vop_valloc_args /* {
3225: struct vnode *a_pvp;
3226: int a_mode;
3227: struct ucred *a_cred;
3228: struct vnode **a_vpp;
3229: } */ *ap;
3230: {
3231:
3232: return (EOPNOTSUPP);
3233: }
3234:
3235: /*
3236: * NFS flat namespace free.
3237: * Currently unsupported.
3238: */
3239: static int
3240: nfs_vfree(ap)
3241: struct vop_vfree_args /* {
3242: struct vnode *a_pvp;
3243: ino_t a_ino;
3244: int a_mode;
3245: } */ *ap;
3246: {
3247:
3248: #if DIAGNOSTIC
3249: printf("nfs_vfree: unimplemented!!");
3250: #endif
3251: return (EOPNOTSUPP);
3252: }
3253:
3254: /*
3255: * NFS file truncation.
3256: */
3257: static int
3258: nfs_truncate(ap)
3259: struct vop_truncate_args /* {
3260: struct vnode *a_vp;
3261: off_t a_length;
3262: int a_flags;
3263: struct ucred *a_cred;
3264: struct proc *a_p;
3265: } */ *ap;
3266: {
3267:
3268: /* Use nfs_setattr */
3269: #if DIAGNOSTIC
3270: printf("nfs_truncate: unimplemented!!");
3271: #endif
3272: return (EOPNOTSUPP);
3273: }
3274:
3275: /*
3276: * NFS update.
3277: */
3278: static int
3279: nfs_update(ap)
3280: struct vop_update_args /* {
3281: struct vnode *a_vp;
3282: struct timeval *a_ta;
3283: struct timeval *a_tm;
3284: int a_waitfor;
3285: } */ *ap;
3286: {
3287:
3288: /* Use nfs_setattr */
3289: #if DIAGNOSTIC
3290: printf("nfs_update: unimplemented!!");
3291: #endif
3292: return (EOPNOTSUPP);
3293: }
3294:
1.1.1.2 ! root 3295: int nfs_aio_threads = 0; /* 1 per nfd (arbitrary) */
! 3296: struct slock nfs_aio_slock;
! 3297: TAILQ_HEAD(bqueues, buf) nfs_aio_bufq;
! 3298: int nfs_aio_bufq_len = 0; /* diagnostic only */
! 3299:
! 3300: void
! 3301: nfs_aio_thread()
! 3302: { /* see comment below in nfs_bwrite() for some rationale */
! 3303: struct buf *bp;
! 3304:
! 3305: for(;;) {
! 3306: simple_lock(&nfs_aio_slock);
! 3307: if ((bp = nfs_aio_bufq.tqh_first)) {
! 3308: TAILQ_REMOVE(&nfs_aio_bufq, bp, b_freelist);
! 3309: nfs_aio_bufq_len--;
! 3310: simple_unlock(&nfs_aio_slock);
! 3311: nfs_writebp(bp, 1);
! 3312: } else { /* nothing to do - goodnight */
! 3313: assert_wait((event_t)&nfs_aio_bufq, FALSE);
! 3314: simple_unlock(&nfs_aio_slock);
! 3315: (void)tsleep((caddr_t)0, PRIBIO+1, "nfs_aio_bufq", 0);
! 3316: }
! 3317: }
! 3318: }
! 3319:
! 3320:
! 3321: void
! 3322: nfs_aio_thread_init()
! 3323: {
! 3324: if (nfs_aio_threads++ == 0) {
! 3325: simple_lock_init(&nfs_aio_slock);
! 3326: TAILQ_INIT(&nfs_aio_bufq);
! 3327: }
! 3328: kernel_thread(kernel_task, nfs_aio_thread, (void *)0);
! 3329: }
! 3330:
! 3331:
1.1 root 3332: /*
3333: * Just call nfs_writebp() with the force argument set to 1.
3334: */
3335: static int
3336: nfs_bwrite(ap)
3337: struct vop_bwrite_args /* {
3338: struct vnode *a_bp;
3339: } */ *ap;
3340: {
1.1.1.2 ! root 3341: extern void wakeup_one(caddr_t chan);
1.1 root 3342:
1.1.1.2 ! root 3343: /*
! 3344: * nfs_writebp will issue a synchronous rpc to if B_ASYNC then
! 3345: * to avoid distributed deadlocks we handoff the write to the
! 3346: * nfs_aio threads. Doing so allows us to complete the
! 3347: * current request, rather than blocking on a server which may
! 3348: * be ourself (or blocked on ourself).
! 3349: *
! 3350: * Note the loopback deadlocks happened when the thread
! 3351: * invoking us was nfsd, and also when it was the pagedaemon.
! 3352: *
! 3353: * This solution has one known problem. If *ALL* buffers get
! 3354: * on the nfs_aio queue then no forward progress can be made
! 3355: * until one of those writes complete. And if the current
! 3356: * nfs_aio writes-in-progress block due to a non-responsive server we
! 3357: * are in a deadlock circle. Probably the cure is to limit the
! 3358: * async write concurrency in getnewbuf as in FreeBSD 3.2.
! 3359: */
! 3360: if (nfs_aio_threads && (ap->a_bp->b_flags & B_ASYNC)) {
! 3361: simple_lock(&nfs_aio_slock);
! 3362: nfs_aio_bufq_len++;
! 3363: TAILQ_INSERT_TAIL(&nfs_aio_bufq, ap->a_bp, b_freelist);
! 3364: simple_unlock(&nfs_aio_slock);
! 3365: wakeup_one((caddr_t)&nfs_aio_bufq);
! 3366: return (0);
! 3367: }
1.1 root 3368: return (nfs_writebp(ap->a_bp, 1));
3369: }
3370:
3371: /*
3372: * This is a clone of vn_bwrite(), except that B_WRITEINPROG isn't set unless
3373: * the force flag is one and it also handles the B_NEEDCOMMIT flag.
3374: */
3375: int
3376: nfs_writebp(bp, force)
3377: register struct buf *bp;
3378: int force;
3379: {
3380: int s;
3381: register int oldflags = bp->b_flags, retv = 1;
3382: off_t off;
3383:
3384: if(!(bp->b_flags & B_BUSY))
3385: panic("nfs_writebp: buffer is not busy???");
3386:
3387: /* XXX CSM 12/4/97 Revisit when buffer cache upgraded */
3388: #ifdef notyet
3389: if (bp->b_flags & B_DELWRI) {
3390: --numdirtybuffers;
3391: if (needsbuffer)
3392: vfs_bio_need_satisfy();
3393: }
3394: #endif
3395: s = splbio();
3396: bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
3397:
3398: if ((oldflags & (B_ASYNC|B_DELWRI)) == (B_ASYNC|B_DELWRI)) {
3399: reassignbuf(bp, bp->b_vp);
3400: }
3401:
3402: bp->b_vp->v_numoutput++;
3403: current_proc()->p_stats->p_ru.ru_oublock++;
3404: splx(s);
3405:
3406: /*
3407: * If B_NEEDCOMMIT is set, a commit rpc may do the trick. If not
3408: * an actual write will have to be scheduled via. VOP_STRATEGY().
3409: * If B_WRITEINPROG is already set, then push it with a write anyhow.
3410: */
3411: vfs_busy_pages(bp, 1);
3412: if ((oldflags & (B_NEEDCOMMIT | B_WRITEINPROG)) == B_NEEDCOMMIT) {
3413: off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
3414: bp->b_flags |= B_WRITEINPROG;
3415: retv = nfs_commit(bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff,
3416: bp->b_wcred, bp->b_proc);
3417: bp->b_flags &= ~B_WRITEINPROG;
3418: if (!retv) {
3419: bp->b_dirtyoff = bp->b_dirtyend = 0;
3420: bp->b_flags &= ~B_NEEDCOMMIT;
3421: biodone(bp);
3422: } else if (retv == NFSERR_STALEWRITEVERF)
3423: nfs_clearcommit(bp->b_vp->v_mount);
3424: }
3425: if (retv) {
3426: if (force)
3427: bp->b_flags |= B_WRITEINPROG;
3428: VOP_STRATEGY(bp);
3429: }
3430:
3431: if( (oldflags & B_ASYNC) == 0) {
3432: int rtval = biowait(bp);
3433:
3434: if (oldflags & B_DELWRI) {
3435: s = splbio();
3436: reassignbuf(bp, bp->b_vp);
3437: splx(s);
3438: }
3439: brelse(bp);
3440: return (rtval);
3441: }
3442:
3443: return (0);
3444: }
3445:
3446: /*
3447: * nfs special file access vnode op.
3448: * Essentially just get vattr and then imitate iaccess() since the device is
3449: * local to the client.
3450: */
3451: static int
3452: nfsspec_access(ap)
3453: struct vop_access_args /* {
3454: struct vnode *a_vp;
3455: int a_mode;
3456: struct ucred *a_cred;
3457: struct proc *a_p;
3458: } */ *ap;
3459: {
3460: register struct vattr *vap;
3461: register gid_t *gp;
3462: register struct ucred *cred = ap->a_cred;
3463: struct vnode *vp = ap->a_vp;
3464: mode_t mode = ap->a_mode;
3465: struct vattr vattr;
3466: register int i;
3467: int error;
3468:
3469: /*
3470: * Disallow write attempts on filesystems mounted read-only;
3471: * unless the file is a socket, fifo, or a block or character
3472: * device resident on the filesystem.
3473: */
3474: if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3475: switch (vp->v_type) {
3476: case VREG: case VDIR: case VLNK:
3477: return (EROFS);
3478: }
3479: }
3480: /*
3481: * If you're the super-user,
3482: * you always get access.
3483: */
3484: if (cred->cr_uid == 0)
3485: return (0);
3486: vap = &vattr;
3487: error = VOP_GETATTR(vp, vap, cred, ap->a_p);
3488: if (error)
3489: return (error);
3490: /*
3491: * Access check is based on only one of owner, group, public.
3492: * If not owner, then check group. If not a member of the
3493: * group, then check public access.
3494: */
3495: if (cred->cr_uid != vap->va_uid) {
3496: mode >>= 3;
3497: gp = cred->cr_groups;
3498: for (i = 0; i < cred->cr_ngroups; i++, gp++)
3499: if (vap->va_gid == *gp)
3500: goto found;
3501: mode >>= 3;
3502: found:
3503: ;
3504: }
3505: error = (vap->va_mode & mode) == mode ? 0 : EACCES;
3506: return (error);
3507: }
3508:
3509: /*
3510: * Read wrapper for special devices.
3511: */
3512: static int
3513: nfsspec_read(ap)
3514: struct vop_read_args /* {
3515: struct vnode *a_vp;
3516: struct uio *a_uio;
3517: int a_ioflag;
3518: struct ucred *a_cred;
3519: } */ *ap;
3520: {
3521: register struct nfsnode *np = VTONFS(ap->a_vp);
3522:
3523: /*
3524: * Set access flag.
3525: */
3526: np->n_flag |= NACC;
3527: np->n_atim.tv_sec = time.tv_sec;
3528: np->n_atim.tv_nsec = time.tv_usec * 1000;
3529: return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
3530: }
3531:
3532: /*
3533: * Write wrapper for special devices.
3534: */
3535: static int
3536: nfsspec_write(ap)
3537: struct vop_write_args /* {
3538: struct vnode *a_vp;
3539: struct uio *a_uio;
3540: int a_ioflag;
3541: struct ucred *a_cred;
3542: } */ *ap;
3543: {
3544: register struct nfsnode *np = VTONFS(ap->a_vp);
3545:
3546: /*
3547: * Set update flag.
3548: */
3549: np->n_flag |= NUPD;
3550: np->n_mtim.tv_sec = time.tv_sec;
3551: np->n_mtim.tv_nsec = time.tv_usec * 1000;
3552: return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
3553: }
3554:
3555: /*
3556: * Close wrapper for special devices.
3557: *
3558: * Update the times on the nfsnode then do device close.
3559: */
3560: static int
3561: nfsspec_close(ap)
3562: struct vop_close_args /* {
3563: struct vnode *a_vp;
3564: int a_fflag;
3565: struct ucred *a_cred;
3566: struct proc *a_p;
3567: } */ *ap;
3568: {
3569: register struct vnode *vp = ap->a_vp;
3570: register struct nfsnode *np = VTONFS(vp);
3571: struct vattr vattr;
3572:
3573: if (np->n_flag & (NACC | NUPD)) {
3574: np->n_flag |= NCHG;
3575: if (vp->v_usecount == 1 &&
3576: (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
3577: VATTR_NULL(&vattr);
3578: if (np->n_flag & NACC)
3579: vattr.va_atime = np->n_atim;
3580: if (np->n_flag & NUPD)
3581: vattr.va_mtime = np->n_mtim;
3582: (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
3583: }
3584: }
3585: return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
3586: }
3587:
3588: /*
3589: * Read wrapper for fifos.
3590: */
3591: static int
3592: nfsfifo_read(ap)
3593: struct vop_read_args /* {
3594: struct vnode *a_vp;
3595: struct uio *a_uio;
3596: int a_ioflag;
3597: struct ucred *a_cred;
3598: } */ *ap;
3599: {
3600: extern int (**fifo_vnodeop_p)();
3601: register struct nfsnode *np = VTONFS(ap->a_vp);
3602:
3603: /*
3604: * Set access flag.
3605: */
3606: np->n_flag |= NACC;
3607: np->n_atim.tv_sec = time.tv_sec;
3608: np->n_atim.tv_nsec = time.tv_usec * 1000;
3609: return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
3610: }
3611:
3612: /*
3613: * Write wrapper for fifos.
3614: */
3615: static int
3616: nfsfifo_write(ap)
3617: struct vop_write_args /* {
3618: struct vnode *a_vp;
3619: struct uio *a_uio;
3620: int a_ioflag;
3621: struct ucred *a_cred;
3622: } */ *ap;
3623: {
3624: extern int (**fifo_vnodeop_p)();
3625: register struct nfsnode *np = VTONFS(ap->a_vp);
3626:
3627: /*
3628: * Set update flag.
3629: */
3630: np->n_flag |= NUPD;
3631: np->n_mtim.tv_sec = time.tv_sec;
3632: np->n_mtim.tv_nsec = time.tv_usec * 1000;
3633: return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
3634: }
3635:
3636: /*
3637: * Close wrapper for fifos.
3638: *
3639: * Update the times on the nfsnode then do fifo close.
3640: */
3641: static int
3642: nfsfifo_close(ap)
3643: struct vop_close_args /* {
3644: struct vnode *a_vp;
3645: int a_fflag;
3646: struct ucred *a_cred;
3647: struct proc *a_p;
3648: } */ *ap;
3649: {
3650: register struct vnode *vp = ap->a_vp;
3651: register struct nfsnode *np = VTONFS(vp);
3652: struct vattr vattr;
3653: extern int (**fifo_vnodeop_p)();
3654:
3655: if (np->n_flag & (NACC | NUPD)) {
3656: if (np->n_flag & NACC) {
3657: np->n_atim.tv_sec = time.tv_sec;
3658: np->n_atim.tv_nsec = time.tv_usec * 1000;
3659: }
3660: if (np->n_flag & NUPD) {
3661: np->n_mtim.tv_sec = time.tv_sec;
3662: np->n_mtim.tv_nsec = time.tv_usec * 1000;
3663: }
3664: np->n_flag |= NCHG;
3665: if (vp->v_usecount == 1 &&
3666: (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
3667: VATTR_NULL(&vattr);
3668: if (np->n_flag & NACC)
3669: vattr.va_atime = np->n_atim;
3670: if (np->n_flag & NUPD)
3671: vattr.va_mtime = np->n_mtim;
3672: (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
3673: }
3674: }
3675: return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
3676: }
3677:
3678: static int
3679: nfs_ioctl(ap)
3680: struct vop_ioctl_args *ap;
3681: {
3682:
3683: /*
3684: * XXX we were once bogusly enoictl() which returned this (ENOTTY).
3685: * Probably we should return ENODEV.
3686: */
3687: return (ENOTTY);
3688: }
3689:
3690: static int
3691: nfs_select(ap)
3692: struct vop_select_args *ap;
3693: {
3694:
3695: /*
3696: * We were once bogusly seltrue() which returns 1. Is this right?
3697: */
3698: return (1);
3699: }
1.1.1.2 ! root 3700:
1.1 root 3701: /* Pagein */
3702: nfs_pagein(ap)
3703: struct vop_pagein_args /* {
3704: struct vnode *a_vp;
3705: struct uio *a_uio;
3706: int a_ioflag;
3707: struct ucred *a_cred;
3708: } */ *ap;
3709: {
3710: struct vnode *vp=ap->a_vp;
3711: struct vm_info * vmp=vp->v_vm_info;
3712: struct ucred *reader_cred=ap->a_cred;
3713: if ((vp->v_vm_info) && vp->v_vm_info->cred) {
3714: reader_cred = vp->v_vm_info->cred;
3715: }
3716:
3717: return (VOP_READ(ap->a_vp, ap->a_uio, ap->a_ioflag, reader_cred));
3718: }
3719:
3720: /* Pageout */
3721: nfs_pageout(ap)
3722: struct vop_pageout_args /* {
3723: struct vnode *a_vp;
3724: struct uio *a_uio;
3725: int a_ioflag;
3726: struct ucred *a_cred;
3727: } */ *ap;
3728: {
3729: struct vnode *vp=ap->a_vp;
3730: struct vm_info * vmp=vp->v_vm_info;
3731: struct ucred *writer_cred=ap->a_cred;
3732: if ((vp->v_vm_info) && vp->v_vm_info->cred) {
3733: writer_cred = vp->v_vm_info->cred;
3734: }
3735:
3736: return (VOP_WRITE(ap->a_vp, ap->a_uio, ap->a_ioflag, writer_cred));
3737: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.