]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_vnops.c
8b64b7d245d393da577cf9dbaada02407b9deb41
[apple/xnu.git] / bsd / nfs / nfs_vnops.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23 /*
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * This code is derived from software contributed to Berkeley by
28 * Rick Macklem at The University of Guelph.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 *
58 * @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
59 * FreeBSD-Id: nfs_vnops.c,v 1.72 1997/11/07 09:20:48 phk Exp $
60 */
61
62
63 /*
64 * vnode op calls for Sun NFS version 2 and 3
65 */
66 #include <sys/param.h>
67 #include <sys/kernel.h>
68 #include <sys/systm.h>
69 #include <sys/resourcevar.h>
70 #include <sys/proc.h>
71 #include <sys/mount.h>
72 #include <sys/buf.h>
73 #include <sys/malloc.h>
74 #include <sys/mbuf.h>
75 #include <sys/conf.h>
76 #include <sys/namei.h>
77 #include <sys/vnode.h>
78 #include <sys/dirent.h>
79 #include <sys/fcntl.h>
80 #include <sys/lockf.h>
81 #include <sys/ubc.h>
82
83 #include <ufs/ufs/dir.h>
84 #include <vfs/vfs_support.h>
85
86 #include <sys/vm.h>
87 #include <machine/spl.h>
88 #include <vm/vm_pageout.h>
89
90 #include <sys/time.h>
91 #include <kern/clock.h>
92
93 #include <miscfs/fifofs/fifo.h>
94 #include <miscfs/specfs/specdev.h>
95
96 #include <nfs/rpcv2.h>
97 #include <nfs/nfsproto.h>
98 #include <nfs/nfs.h>
99 #include <nfs/nfsnode.h>
100 #include <nfs/nfsmount.h>
101 #include <nfs/xdr_subs.h>
102 #include <nfs/nfsm_subs.h>
103 #include <nfs/nqnfs.h>
104
105 #include <net/if.h>
106 #include <netinet/in.h>
107 #include <netinet/in_var.h>
108 #include <kern/task.h>
109 #include <vm/vm_kern.h>
110
111 #include <sys/kdebug.h>
112
113 #define FSDBG(A, B, C, D, E) \
114 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_NONE, \
115 (int)(B), (int)(C), (int)(D), (int)(E), 0)
116 #define FSDBG_TOP(A, B, C, D, E) \
117 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_START, \
118 (int)(B), (int)(C), (int)(D), (int)(E), 0)
119 #define FSDBG_BOT(A, B, C, D, E) \
120 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_END, \
121 (int)(B), (int)(C), (int)(D), (int)(E), 0)
122
123 #define TRUE 1
124 #define FALSE 0
125
126 static int nfsspec_read __P((struct vop_read_args *));
127 static int nfsspec_write __P((struct vop_write_args *));
128 static int nfsfifo_read __P((struct vop_read_args *));
129 static int nfsfifo_write __P((struct vop_write_args *));
130 static int nfsspec_close __P((struct vop_close_args *));
131 static int nfsfifo_close __P((struct vop_close_args *));
132 #define nfs_poll vop_nopoll
133 static int nfs_ioctl __P((struct vop_ioctl_args *));
134 static int nfs_select __P((struct vop_select_args *));
135 static int nfs_flush __P((struct vnode *,struct ucred *,int,struct proc *,int));
136 static int nfs_setattrrpc __P((struct vnode *,struct vattr *,struct ucred *,struct proc *));
137 static int nfs_lookup __P((struct vop_lookup_args *));
138 static int nfs_create __P((struct vop_create_args *));
139 static int nfs_mknod __P((struct vop_mknod_args *));
140 static int nfs_open __P((struct vop_open_args *));
141 static int nfs_close __P((struct vop_close_args *));
142 static int nfs_access __P((struct vop_access_args *));
143 static int nfs_getattr __P((struct vop_getattr_args *));
144 static int nfs_setattr __P((struct vop_setattr_args *));
145 static int nfs_read __P((struct vop_read_args *));
146 static int nfs_mmap __P((struct vop_mmap_args *));
147 static int nfs_fsync __P((struct vop_fsync_args *));
148 static int nfs_remove __P((struct vop_remove_args *));
149 static int nfs_link __P((struct vop_link_args *));
150 static int nfs_rename __P((struct vop_rename_args *));
151 static int nfs_mkdir __P((struct vop_mkdir_args *));
152 static int nfs_rmdir __P((struct vop_rmdir_args *));
153 static int nfs_symlink __P((struct vop_symlink_args *));
154 static int nfs_readdir __P((struct vop_readdir_args *));
155 static int nfs_bmap __P((struct vop_bmap_args *));
156 static int nfs_strategy __P((struct vop_strategy_args *));
157 static int nfs_lookitup __P((struct vnode *,char *,int,struct ucred *,struct proc *,struct nfsnode **));
158 static int nfs_sillyrename __P((struct vnode *,struct vnode *,struct componentname *));
159 static int nfsspec_access __P((struct vop_access_args *));
160 static int nfs_readlink __P((struct vop_readlink_args *));
161 static int nfs_print __P((struct vop_print_args *));
162 static int nfs_pathconf __P((struct vop_pathconf_args *));
163 static int nfs_advlock __P((struct vop_advlock_args *));
164 static int nfs_blkatoff __P((struct vop_blkatoff_args *));
165 static int nfs_bwrite __P((struct vop_bwrite_args *));
166 static int nfs_valloc __P((struct vop_valloc_args *));
167 static int nfs_vfree __P((struct vop_vfree_args *));
168 static int nfs_truncate __P((struct vop_truncate_args *));
169 static int nfs_update __P((struct vop_update_args *));
170 static int nfs_pagein __P((struct vop_pagein_args *));
171 static int nfs_pageout __P((struct vop_pageout_args *));
172 static int nfs_blktooff __P((struct vop_blktooff_args *));
173 static int nfs_offtoblk __P((struct vop_offtoblk_args *));
174 static int nfs_cmap __P((struct vop_cmap_args *));
175
176 /*
177 * Global vfs data structures for nfs
178 */
179 vop_t **nfsv2_vnodeop_p;
180 static struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
181 { &vop_default_desc, (vop_t *)vn_default_error },
182 { &vop_lookup_desc, (vop_t *)nfs_lookup }, /* lookup */
183 { &vop_create_desc, (vop_t *)nfs_create }, /* create */
184 { &vop_mknod_desc, (vop_t *)nfs_mknod }, /* mknod */
185 { &vop_open_desc, (vop_t *)nfs_open }, /* open */
186 { &vop_close_desc, (vop_t *)nfs_close }, /* close */
187 { &vop_access_desc, (vop_t *)nfs_access }, /* access */
188 { &vop_getattr_desc, (vop_t *)nfs_getattr }, /* getattr */
189 { &vop_setattr_desc, (vop_t *)nfs_setattr }, /* setattr */
190 { &vop_read_desc, (vop_t *)nfs_read }, /* read */
191 { &vop_write_desc, (vop_t *)nfs_write }, /* write */
192 { &vop_lease_desc, (vop_t *)nfs_lease_check }, /* lease */
193 { &vop_ioctl_desc, (vop_t *)nfs_ioctl }, /* ioctl */
194 { &vop_select_desc, (vop_t *)nfs_select }, /* select */
195 { &vop_revoke_desc, (vop_t *)nfs_revoke }, /* revoke */
196 { &vop_mmap_desc, (vop_t *)nfs_mmap }, /* mmap */
197 { &vop_fsync_desc, (vop_t *)nfs_fsync }, /* fsync */
198 { &vop_seek_desc, (vop_t *)nfs_seek }, /* seek */
199 { &vop_remove_desc, (vop_t *)nfs_remove }, /* remove */
200 { &vop_link_desc, (vop_t *)nfs_link }, /* link */
201 { &vop_rename_desc, (vop_t *)nfs_rename }, /* rename */
202 { &vop_mkdir_desc, (vop_t *)nfs_mkdir }, /* mkdir */
203 { &vop_rmdir_desc, (vop_t *)nfs_rmdir }, /* rmdir */
204 { &vop_symlink_desc, (vop_t *)nfs_symlink }, /* symlink */
205 { &vop_readdir_desc, (vop_t *)nfs_readdir }, /* readdir */
206 { &vop_readlink_desc, (vop_t *)nfs_readlink }, /* readlink */
207 { &vop_abortop_desc, (vop_t *)nfs_abortop }, /* abortop */
208 { &vop_inactive_desc, (vop_t *)nfs_inactive }, /* inactive */
209 { &vop_reclaim_desc, (vop_t *)nfs_reclaim }, /* reclaim */
210 { &vop_lock_desc, (vop_t *)nfs_lock }, /* lock */
211 { &vop_unlock_desc, (vop_t *)nfs_unlock }, /* unlock */
212 { &vop_bmap_desc, (vop_t *)nfs_bmap }, /* bmap */
213 { &vop_strategy_desc, (vop_t *)nfs_strategy }, /* strategy */
214 { &vop_print_desc, (vop_t *)nfs_print }, /* print */
215 { &vop_islocked_desc, (vop_t *)nfs_islocked }, /* islocked */
216 { &vop_pathconf_desc, (vop_t *)nfs_pathconf }, /* pathconf */
217 { &vop_advlock_desc, (vop_t *)nfs_advlock }, /* advlock */
218 { &vop_blkatoff_desc, (vop_t *)nfs_blkatoff }, /* blkatoff */
219 { &vop_valloc_desc, (vop_t *)nfs_valloc }, /* valloc */
220 { &vop_reallocblks_desc, (vop_t *)nfs_reallocblks }, /* reallocblks */
221 { &vop_vfree_desc, (vop_t *)nfs_vfree }, /* vfree */
222 { &vop_truncate_desc, (vop_t *)nfs_truncate }, /* truncate */
223 { &vop_update_desc, (vop_t *)nfs_update }, /* update */
224 { &vop_bwrite_desc, (vop_t *)nfs_bwrite }, /* bwrite */
225 { &vop_pagein_desc, (vop_t *)nfs_pagein }, /* Pagein */
226 { &vop_pageout_desc, (vop_t *)nfs_pageout }, /* Pageout */
227 { &vop_copyfile_desc, (vop_t *)err_copyfile }, /* Copyfile */
228 { &vop_blktooff_desc, (vop_t *)nfs_blktooff }, /* blktooff */
229 { &vop_offtoblk_desc, (vop_t *)nfs_offtoblk }, /* offtoblk */
230 { &vop_cmap_desc, (vop_t *)nfs_cmap }, /* cmap */
231 { NULL, NULL }
232 };
233 struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
234 { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
235 #ifdef __FreeBSD__
236 VNODEOP_SET(nfsv2_vnodeop_opv_desc);
237 #endif
238
239 /*
240 * Special device vnode ops
241 */
242 vop_t **spec_nfsv2nodeop_p;
243 static struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
244 { &vop_default_desc, (vop_t *)vn_default_error },
245 { &vop_lookup_desc, (vop_t *)spec_lookup }, /* lookup */
246 { &vop_create_desc, (vop_t *)spec_create }, /* create */
247 { &vop_mknod_desc, (vop_t *)spec_mknod }, /* mknod */
248 { &vop_open_desc, (vop_t *)spec_open }, /* open */
249 { &vop_close_desc, (vop_t *)nfsspec_close }, /* close */
250 { &vop_access_desc, (vop_t *)nfsspec_access }, /* access */
251 { &vop_getattr_desc, (vop_t *)nfs_getattr }, /* getattr */
252 { &vop_setattr_desc, (vop_t *)nfs_setattr }, /* setattr */
253 { &vop_read_desc, (vop_t *)nfsspec_read }, /* read */
254 { &vop_write_desc, (vop_t *)nfsspec_write }, /* write */
255 { &vop_lease_desc, (vop_t *)spec_lease_check }, /* lease */
256 { &vop_ioctl_desc, (vop_t *)spec_ioctl }, /* ioctl */
257 { &vop_select_desc, (vop_t *)spec_select }, /* select */
258 { &vop_revoke_desc, (vop_t *)spec_revoke }, /* revoke */
259 { &vop_mmap_desc, (vop_t *)spec_mmap }, /* mmap */
260 { &vop_fsync_desc, (vop_t *)nfs_fsync }, /* fsync */
261 { &vop_seek_desc, (vop_t *)spec_seek }, /* seek */
262 { &vop_remove_desc, (vop_t *)spec_remove }, /* remove */
263 { &vop_link_desc, (vop_t *)spec_link }, /* link */
264 { &vop_rename_desc, (vop_t *)spec_rename }, /* rename */
265 { &vop_mkdir_desc, (vop_t *)spec_mkdir }, /* mkdir */
266 { &vop_rmdir_desc, (vop_t *)spec_rmdir }, /* rmdir */
267 { &vop_symlink_desc, (vop_t *)spec_symlink }, /* symlink */
268 { &vop_readdir_desc, (vop_t *)spec_readdir }, /* readdir */
269 { &vop_readlink_desc, (vop_t *)spec_readlink }, /* readlink */
270 { &vop_abortop_desc, (vop_t *)spec_abortop }, /* abortop */
271 { &vop_inactive_desc, (vop_t *)nfs_inactive }, /* inactive */
272 { &vop_reclaim_desc, (vop_t *)nfs_reclaim }, /* reclaim */
273 { &vop_lock_desc, (vop_t *)nfs_lock }, /* lock */
274 { &vop_unlock_desc, (vop_t *)nfs_unlock }, /* unlock */
275 { &vop_bmap_desc, (vop_t *)spec_bmap }, /* bmap */
276 { &vop_strategy_desc, (vop_t *)spec_strategy }, /* strategy */
277 { &vop_print_desc, (vop_t *)nfs_print }, /* print */
278 { &vop_islocked_desc, (vop_t *)nfs_islocked }, /* islocked */
279 { &vop_pathconf_desc, (vop_t *)spec_pathconf }, /* pathconf */
280 { &vop_advlock_desc, (vop_t *)spec_advlock }, /* advlock */
281 { &vop_blkatoff_desc, (vop_t *)spec_blkatoff }, /* blkatoff */
282 { &vop_valloc_desc, (vop_t *)spec_valloc }, /* valloc */
283 { &vop_reallocblks_desc, (vop_t *)spec_reallocblks }, /* reallocblks */
284 { &vop_vfree_desc, (vop_t *)spec_vfree }, /* vfree */
285 { &vop_truncate_desc, (vop_t *)spec_truncate }, /* truncate */
286 { &vop_update_desc, (vop_t *)nfs_update }, /* update */
287 { &vop_bwrite_desc, (vop_t *)vn_bwrite }, /* bwrite */
288 { &vop_devblocksize_desc, (vop_t *)spec_devblocksize }, /* devblocksize */
289 { &vop_pagein_desc, (vop_t *)nfs_pagein }, /* Pagein */
290 { &vop_pageout_desc, (vop_t *)nfs_pageout }, /* Pageout */
291 { &vop_blktooff_desc, (vop_t *)nfs_blktooff }, /* blktooff */
292 { &vop_offtoblk_desc, (vop_t *)nfs_offtoblk }, /* offtoblk */
293 { &vop_cmap_desc, (vop_t *)nfs_cmap }, /* cmap */
294 { NULL, NULL }
295 };
296 struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
297 { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
298 #ifdef __FreeBSD__
299 VNODEOP_SET(spec_nfsv2nodeop_opv_desc);
300 #endif
301
302 vop_t **fifo_nfsv2nodeop_p;
303 static struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
304 { &vop_default_desc, (vop_t *)vn_default_error },
305 { &vop_lookup_desc, (vop_t *)fifo_lookup }, /* lookup */
306 { &vop_create_desc, (vop_t *)fifo_create }, /* create */
307 { &vop_mknod_desc, (vop_t *)fifo_mknod }, /* mknod */
308 { &vop_open_desc, (vop_t *)fifo_open }, /* open */
309 { &vop_close_desc, (vop_t *)nfsfifo_close }, /* close */
310 { &vop_access_desc, (vop_t *)nfsspec_access }, /* access */
311 { &vop_getattr_desc, (vop_t *)nfs_getattr }, /* getattr */
312 { &vop_setattr_desc, (vop_t *)nfs_setattr }, /* setattr */
313 { &vop_read_desc, (vop_t *)nfsfifo_read }, /* read */
314 { &vop_write_desc, (vop_t *)nfsfifo_write }, /* write */
315 { &vop_lease_desc, (vop_t *)fifo_lease_check }, /* lease */
316 { &vop_ioctl_desc, (vop_t *)fifo_ioctl }, /* ioctl */
317 { &vop_select_desc, (vop_t *)fifo_select }, /* select */
318 { &vop_revoke_desc, (vop_t *)fifo_revoke }, /* revoke */
319 { &vop_mmap_desc, (vop_t *)fifo_mmap }, /* mmap */
320 { &vop_fsync_desc, (vop_t *)nfs_fsync }, /* fsync */
321 { &vop_seek_desc, (vop_t *)fifo_seek }, /* seek */
322 { &vop_remove_desc, (vop_t *)fifo_remove }, /* remove */
323 { &vop_link_desc, (vop_t *)fifo_link }, /* link */
324 { &vop_rename_desc, (vop_t *)fifo_rename }, /* rename */
325 { &vop_mkdir_desc, (vop_t *)fifo_mkdir }, /* mkdir */
326 { &vop_rmdir_desc, (vop_t *)fifo_rmdir }, /* rmdir */
327 { &vop_symlink_desc, (vop_t *)fifo_symlink }, /* symlink */
328 { &vop_readdir_desc, (vop_t *)fifo_readdir }, /* readdir */
329 { &vop_readlink_desc, (vop_t *)fifo_readlink }, /* readlink */
330 { &vop_abortop_desc, (vop_t *)fifo_abortop }, /* abortop */
331 { &vop_inactive_desc, (vop_t *)nfs_inactive }, /* inactive */
332 { &vop_reclaim_desc, (vop_t *)nfs_reclaim }, /* reclaim */
333 { &vop_lock_desc, (vop_t *)nfs_lock }, /* lock */
334 { &vop_unlock_desc, (vop_t *)nfs_unlock }, /* unlock */
335 { &vop_bmap_desc, (vop_t *)fifo_bmap }, /* bmap */
336 { &vop_strategy_desc, (vop_t *)fifo_strategy }, /* strategy */
337 { &vop_print_desc, (vop_t *)nfs_print }, /* print */
338 { &vop_islocked_desc, (vop_t *)nfs_islocked }, /* islocked */
339 { &vop_pathconf_desc, (vop_t *)fifo_pathconf }, /* pathconf */
340 { &vop_advlock_desc, (vop_t *)fifo_advlock }, /* advlock */
341 { &vop_blkatoff_desc, (vop_t *)fifo_blkatoff }, /* blkatoff */
342 { &vop_valloc_desc, (vop_t *)fifo_valloc }, /* valloc */
343 { &vop_reallocblks_desc, (vop_t *)fifo_reallocblks }, /* reallocblks */
344 { &vop_vfree_desc, (vop_t *)fifo_vfree }, /* vfree */
345 { &vop_truncate_desc, (vop_t *)fifo_truncate }, /* truncate */
346 { &vop_update_desc, (vop_t *)nfs_update }, /* update */
347 { &vop_bwrite_desc, (vop_t *)vn_bwrite }, /* bwrite */
348 { &vop_pagein_desc, (vop_t *)nfs_pagein }, /* Pagein */
349 { &vop_pageout_desc, (vop_t *)nfs_pageout }, /* Pageout */
350 { &vop_blktooff_desc, (vop_t *)nfs_blktooff }, /* blktooff */
351 { &vop_offtoblk_desc, (vop_t *)nfs_offtoblk }, /* offtoblk */
352 { &vop_cmap_desc, (vop_t *)nfs_cmap }, /* cmap */
353 { NULL, NULL }
354 };
355 struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
356 { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
357 #ifdef __FreeBSD__
358 VNODEOP_SET(fifo_nfsv2nodeop_opv_desc);
359 #endif
360
361 static int nfs_commit __P((struct vnode *vp, u_quad_t offset, int cnt,
362 struct ucred *cred, struct proc *procp));
363 static int nfs_mknodrpc __P((struct vnode *dvp, struct vnode **vpp,
364 struct componentname *cnp,
365 struct vattr *vap));
366 static int nfs_removerpc __P((struct vnode *dvp, char *name, int namelen,
367 struct ucred *cred, struct proc *proc));
368 static int nfs_renamerpc __P((struct vnode *fdvp, char *fnameptr,
369 int fnamelen, struct vnode *tdvp,
370 char *tnameptr, int tnamelen,
371 struct ucred *cred, struct proc *proc));
372 static int nfs_renameit __P((struct vnode *sdvp,
373 struct componentname *scnp,
374 struct sillyrename *sp));
375
376 /*
377 * Global variables
378 */
379 extern u_long nfs_true, nfs_false;
380 extern struct nfsstats nfsstats;
381 extern nfstype nfsv3_type[9];
382 struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
383 struct nfsmount *nfs_iodmount[NFS_MAXASYNCDAEMON];
384 int nfs_numasync = 0;
385 #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
386
387 static int nfsaccess_cache_timeout = NFS_MAXATTRTIMO;
388 /* SYSCTL_INT(_vfs_nfs, OID_AUTO, access_cache_timeout, CTLFLAG_RW,
389 &nfsaccess_cache_timeout, 0, "NFS ACCESS cache timeout");
390 */
391 #define NFSV3ACCESS_ALL (NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY \
392 | NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE \
393 | NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP)
394
395
396 /*
397 * the following are needed only by nfs_pageout to know how to handle errors
398 * see nfs_pageout comments on explanation of actions.
399 * the errors here are copied from errno.h and errors returned by servers
400 * are expected to match the same numbers here. If not, our actions maybe
401 * erroneous.
402 */
403 enum actiontype {NOACTION, DUMP, DUMPANDLOG, RETRY, RETRYWITHSLEEP, SEVER};
404
405 static int errorcount[ELAST+1]; /* better be zeros when initialized */
406
407 static const short errortooutcome[ELAST+1] = {
408 NOACTION,
409 DUMP, /* EPERM 1 Operation not permitted */
410 DUMP, /* ENOENT 2 No such file or directory */
411 DUMPANDLOG, /* ESRCH 3 No such process */
412 RETRY, /* EINTR 4 Interrupted system call */
413 DUMP, /* EIO 5 Input/output error */
414 DUMP, /* ENXIO 6 Device not configured */
415 DUMPANDLOG, /* E2BIG 7 Argument list too long */
416 DUMPANDLOG, /* ENOEXEC 8 Exec format error */
417 DUMPANDLOG, /* EBADF 9 Bad file descriptor */
418 DUMPANDLOG, /* ECHILD 10 No child processes */
419 DUMPANDLOG, /* EDEADLK 11 Resource deadlock avoided - was EAGAIN */
420 RETRY, /* ENOMEM 12 Cannot allocate memory */
421 DUMP, /* EACCES 13 Permission denied */
422 DUMPANDLOG, /* EFAULT 14 Bad address */
423 DUMPANDLOG, /* ENOTBLK 15 POSIX - Block device required */
424 RETRY, /* EBUSY 16 Device busy */
425 DUMP, /* EEXIST 17 File exists */
426 DUMP, /* EXDEV 18 Cross-device link */
427 DUMP, /* ENODEV 19 Operation not supported by device */
428 DUMP, /* ENOTDIR 20 Not a directory */
429 DUMP, /* EISDIR 21 Is a directory */
430 DUMP, /* EINVAL 22 Invalid argument */
431 DUMPANDLOG, /* ENFILE 23 Too many open files in system */
432 DUMPANDLOG, /* EMFILE 24 Too many open files */
433 DUMPANDLOG, /* ENOTTY 25 Inappropriate ioctl for device */
434 DUMPANDLOG, /* ETXTBSY 26 Text file busy - POSIX */
435 DUMP, /* EFBIG 27 File too large */
436 DUMP, /* ENOSPC 28 No space left on device */
437 DUMPANDLOG, /* ESPIPE 29 Illegal seek */
438 DUMP, /* EROFS 30 Read-only file system */
439 DUMP, /* EMLINK 31 Too many links */
440 RETRY, /* EPIPE 32 Broken pipe */
441 /* math software */
442 DUMPANDLOG, /* EDOM 33 Numerical argument out of domain */
443 DUMPANDLOG, /* ERANGE 34 Result too large */
444 RETRY, /* EAGAIN/EWOULDBLOCK 35 Resource temporarily unavailable */
445 DUMPANDLOG, /* EINPROGRESS 36 Operation now in progress */
446 DUMPANDLOG, /* EALREADY 37 Operation already in progress */
447 /* ipc/network software -- argument errors */
448 DUMPANDLOG, /* ENOTSOC 38 Socket operation on non-socket */
449 DUMPANDLOG, /* EDESTADDRREQ 39 Destination address required */
450 DUMPANDLOG, /* EMSGSIZE 40 Message too long */
451 DUMPANDLOG, /* EPROTOTYPE 41 Protocol wrong type for socket */
452 DUMPANDLOG, /* ENOPROTOOPT 42 Protocol not available */
453 DUMPANDLOG, /* EPROTONOSUPPORT 43 Protocol not supported */
454 DUMPANDLOG, /* ESOCKTNOSUPPORT 44 Socket type not supported */
455 DUMPANDLOG, /* ENOTSUP 45 Operation not supported */
456 DUMPANDLOG, /* EPFNOSUPPORT 46 Protocol family not supported */
457 DUMPANDLOG, /* EAFNOSUPPORT 47 Address family not supported by protocol family */
458 DUMPANDLOG, /* EADDRINUSE 48 Address already in use */
459 DUMPANDLOG, /* EADDRNOTAVAIL 49 Can't assign requested address */
460 /* ipc/network software -- operational errors */
461 RETRY, /* ENETDOWN 50 Network is down */
462 RETRY, /* ENETUNREACH 51 Network is unreachable */
463 RETRY, /* ENETRESET 52 Network dropped connection on reset */
464 RETRY, /* ECONNABORTED 53 Software caused connection abort */
465 RETRY, /* ECONNRESET 54 Connection reset by peer */
466 RETRY, /* ENOBUFS 55 No buffer space available */
467 RETRY, /* EISCONN 56 Socket is already connected */
468 RETRY, /* ENOTCONN 57 Socket is not connected */
469 RETRY, /* ESHUTDOWN 58 Can't send after socket shutdown */
470 RETRY, /* ETOOMANYREFS 59 Too many references: can't splice */
471 RETRY, /* ETIMEDOUT 60 Operation timed out */
472 RETRY, /* ECONNREFUSED 61 Connection refused */
473
474 DUMPANDLOG, /* ELOOP 62 Too many levels of symbolic links */
475 DUMP, /* ENAMETOOLONG 63 File name too long */
476 RETRY, /* EHOSTDOWN 64 Host is down */
477 RETRY, /* EHOSTUNREACH 65 No route to host */
478 DUMP, /* ENOTEMPTY 66 Directory not empty */
479 /* quotas & mush */
480 DUMPANDLOG, /* PROCLIM 67 Too many processes */
481 DUMPANDLOG, /* EUSERS 68 Too many users */
482 DUMPANDLOG, /* EDQUOT 69 Disc quota exceeded */
483 /* Network File System */
484 DUMP, /* ESTALE 70 Stale NFS file handle */
485 DUMP, /* EREMOTE 71 Too many levels of remote in path */
486 DUMPANDLOG, /* EBADRPC 72 RPC struct is bad */
487 DUMPANDLOG, /* ERPCMISMATCH 73 RPC version wrong */
488 DUMPANDLOG, /* EPROGUNAVAIL 74 RPC prog. not avail */
489 DUMPANDLOG, /* EPROGMISMATCH 75 Program version wrong */
490 DUMPANDLOG, /* EPROCUNAVAIL 76 Bad procedure for program */
491
492 DUMPANDLOG, /* ENOLCK 77 No locks available */
493 DUMPANDLOG, /* ENOSYS 78 Function not implemented */
494 DUMPANDLOG, /* EFTYPE 79 Inappropriate file type or format */
495 DUMPANDLOG, /* EAUTH 80 Authentication error */
496 DUMPANDLOG, /* ENEEDAUTH 81 Need authenticator */
497 /* Intelligent device errors */
498 DUMPANDLOG, /* EPWROFF 82 Device power is off */
499 DUMPANDLOG, /* EDEVERR 83 Device error, e.g. paper out */
500 DUMPANDLOG, /* EOVERFLOW 84 Value too large to be stored in data type */
501 /* Program loading errors */
502 DUMPANDLOG, /* EBADEXEC 85 Bad executable */
503 DUMPANDLOG, /* EBADARCH 86 Bad CPU type in executable */
504 DUMPANDLOG, /* ESHLIBVERS 87 Shared library version mismatch */
505 DUMPANDLOG, /* EBADMACHO 88 Malformed Macho file */
506 };
507
508
509 static short
510 nfs_pageouterrorhandler(error)
511 int error;
512 {
513 if (error > ELAST)
514 return(DUMP);
515 else
516 return(errortooutcome[error]);
517 }
518
519 static int
520 nfs3_access_otw(struct vnode *vp,
521 int wmode,
522 struct proc *p,
523 struct ucred *cred)
524 {
525 const int v3 = 1;
526 u_int32_t *tl;
527 int error = 0, attrflag;
528
529 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
530 caddr_t bpos, dpos, cp2;
531 register int32_t t1, t2;
532 register caddr_t cp;
533 u_int32_t rmode;
534 struct nfsnode *np = VTONFS(vp);
535 u_int64_t xid;
536
537 nfsstats.rpccnt[NFSPROC_ACCESS]++;
538 nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
539 nfsm_fhtom(vp, v3);
540 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
541 *tl = txdr_unsigned(wmode);
542 nfsm_request(vp, NFSPROC_ACCESS, p, cred, &xid);
543 nfsm_postop_attr(vp, attrflag, &xid);
544 if (!error) {
545 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
546 rmode = fxdr_unsigned(u_int32_t, *tl);
547 np->n_mode = rmode;
548 np->n_modeuid = cred->cr_uid;
549 np->n_modestamp = time_second;
550 }
551 nfsm_reqdone;
552 return error;
553 }
554
555 /*
556 * nfs access vnode op.
557 * For nfs version 2, just return ok. File accesses may fail later.
558 * For nfs version 3, use the access rpc to check accessibility. If file modes
559 * are changed on the server, accesses might still fail later.
560 */
561 static int
562 nfs_access(ap)
563 struct vop_access_args /* {
564 struct vnode *a_vp;
565 int a_mode;
566 struct ucred *a_cred;
567 struct proc *a_p;
568 } */ *ap;
569 {
570 register struct vnode *vp = ap->a_vp;
571 int error = 0;
572 u_long mode, wmode;
573 int v3 = NFS_ISV3(vp);
574 struct nfsnode *np = VTONFS(vp);
575
576 /*
577 * For nfs v3, do an access rpc, otherwise you are stuck emulating
578 * ufs_access() locally using the vattr. This may not be correct,
579 * since the server may apply other access criteria such as
580 * client uid-->server uid mapping that we do not know about, but
581 * this is better than just returning anything that is lying about
582 * in the cache.
583 */
584 if (v3) {
585 if (ap->a_mode & VREAD)
586 mode = NFSV3ACCESS_READ;
587 else
588 mode = 0;
589 if (vp->v_type == VDIR) {
590 if (ap->a_mode & VWRITE)
591 mode |= NFSV3ACCESS_MODIFY |
592 NFSV3ACCESS_EXTEND | NFSV3ACCESS_DELETE;
593 if (ap->a_mode & VEXEC)
594 mode |= NFSV3ACCESS_LOOKUP;
595 } else {
596 if (ap->a_mode & VWRITE)
597 mode |= NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND;
598 if (ap->a_mode & VEXEC)
599 mode |= NFSV3ACCESS_EXECUTE;
600 }
601 /* XXX safety belt, only make blanket request if caching */
602 if (nfsaccess_cache_timeout > 0) {
603 wmode = NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY |
604 NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE |
605 NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP;
606 } else
607 wmode = mode;
608
609 /*
610 * Does our cached result allow us to give a definite yes to
611 * this request?
612 */
613 if (time_second < np->n_modestamp + nfsaccess_cache_timeout &&
614 ap->a_cred->cr_uid == np->n_modeuid &&
615 (np->n_mode & mode) == mode) {
616 /* nfsstats.accesscache_hits++; */
617 } else {
618 /*
619 * Either a no, or a don't know. Go to the wire.
620 */
621 /* nfsstats.accesscache_misses++; */
622 error = nfs3_access_otw(vp, wmode, ap->a_p,ap->a_cred);
623 if (!error) {
624 if ((np->n_mode & mode) != mode)
625 error = EACCES;
626 }
627 }
628 } else
629 return (nfsspec_access(ap)); /* NFSv2 case checks for EROFS here */
630 /*
631 * Disallow write attempts on filesystems mounted read-only;
632 * unless the file is a socket, fifo, or a block or character
633 * device resident on the filesystem.
634 * CSM - moved EROFS check down per NetBSD rev 1.71. So you
635 * get the correct error value with layered filesystems.
636 * EKN - moved the return(error) below this so it does get called.
637 */
638 if (!error && (ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
639 switch (vp->v_type) {
640 case VREG: case VDIR: case VLNK:
641 error = EROFS;
642 default:
643 break;
644 }
645 }
646 return (error);
647 }
648
649 /*
650 * nfs open vnode op
651 * Check to see if the type is ok
652 * and that deletion is not in progress.
653 * For paged in text files, you will need to flush the page cache
654 * if consistency is lost.
655 */
656 /* ARGSUSED */
657
658 static int
659 nfs_open(ap)
660 struct vop_open_args /* {
661 struct vnode *a_vp;
662 int a_mode;
663 struct ucred *a_cred;
664 struct proc *a_p;
665 } */ *ap;
666 {
667 register struct vnode *vp = ap->a_vp;
668 struct nfsnode *np = VTONFS(vp);
669 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
670 struct vattr vattr;
671 int error;
672
673 if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) {
674 return (EACCES);
675 }
676 /*
677 * Get a valid lease. If cached data is stale, flush it.
678 */
679 if (nmp->nm_flag & NFSMNT_NQNFS) {
680 if (NQNFS_CKINVALID(vp, np, ND_READ)) {
681 do {
682 error = nqnfs_getlease(vp, ND_READ, ap->a_cred,
683 ap->a_p);
684 } while (error == NQNFS_EXPIRED);
685 if (error)
686 return (error);
687 if (np->n_lrev != np->n_brev ||
688 (np->n_flag & NQNFSNONCACHE)) {
689 if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
690 ap->a_p, 1)) == EINTR)
691 return (error);
692 np->n_brev = np->n_lrev;
693 }
694 }
695 } else {
696 if (np->n_flag & NMODIFIED) {
697 if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
698 ap->a_p, 1)) == EINTR)
699 return (error);
700 np->n_attrstamp = 0;
701 if (vp->v_type == VDIR)
702 np->n_direofoffset = 0;
703 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
704 if (error)
705 return (error);
706 np->n_mtime = vattr.va_mtime.tv_sec;
707 } else {
708 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
709 if (error)
710 return (error);
711 if (np->n_mtime != vattr.va_mtime.tv_sec) {
712 if (vp->v_type == VDIR)
713 np->n_direofoffset = 0;
714 if ((error = nfs_vinvalbuf(vp, V_SAVE,
715 ap->a_cred, ap->a_p, 1)) == EINTR)
716 return (error);
717 np->n_mtime = vattr.va_mtime.tv_sec;
718 }
719 }
720 }
721 if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
722 np->n_attrstamp = 0; /* For Open/Close consistency */
723 return (0);
724 }
725
726 /*
727 * nfs close vnode op
728 * What an NFS client should do upon close after writing is a debatable issue.
729 * Most NFS clients push delayed writes to the server upon close, basically for
730 * two reasons:
731 * 1 - So that any write errors may be reported back to the client process
732 * doing the close system call. By far the two most likely errors are
733 * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure.
734 * 2 - To put a worst case upper bound on cache inconsistency between
735 * multiple clients for the file.
736 * There is also a consistency problem for Version 2 of the protocol w.r.t.
737 * not being able to tell if other clients are writing a file concurrently,
738 * since there is no way of knowing if the changed modify time in the reply
739 * is only due to the write for this client.
740 * (NFS Version 3 provides weak cache consistency data in the reply that
741 * should be sufficient to detect and handle this case.)
742 *
743 * The current code does the following:
744 * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
745 * for NFS Version 3 - flush dirty buffers to the server but don't invalidate
746 * or commit them (this satisfies 1 and 2 except for the
747 * case where the server crashes after this close but
748 * before the commit RPC, which is felt to be "good
749 * enough". Changing the last argument to nfs_flush() to
750 * a 1 would force a commit operation, if it is felt a
751 * commit is necessary now.
752 * for NQNFS - do nothing now, since 2 is dealt with via leases and
753 * 1 should be dealt with via an fsync() system call for
754 * cases where write errors are important.
755 */
756 /* ARGSUSED */
757 static int
758 nfs_close(ap)
759 struct vop_close_args /* {
760 struct vnodeop_desc *a_desc;
761 struct vnode *a_vp;
762 int a_fflag;
763 struct ucred *a_cred;
764 struct proc *a_p;
765 } */ *ap;
766 {
767 register struct vnode *vp = ap->a_vp;
768 register struct nfsnode *np = VTONFS(vp);
769 int error = 0;
770
771 if (vp->v_type == VREG) {
772 #if DIAGNOSTIC
773 register struct sillyrename *sp = np->n_sillyrename;
774 if (sp)
775 kprintf("nfs_close: %s, dvp=%x, vp=%x, ap=%x, np=%x, sp=%x\n",
776 &sp->s_name[0], (unsigned)(sp->s_dvp), (unsigned)vp,
777 (unsigned)ap, (unsigned)np, (unsigned)sp);
778 #endif
779 if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
780 (np->n_flag & NMODIFIED)) {
781 if (NFS_ISV3(vp)) {
782 error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 1);
783 /*
784 * We cannot clear the NMODIFIED bit in np->n_flag due to
785 * potential races with other processes (and because
786 * the commit arg is 0 in the nfs_flush call above.)
787 * NMODIFIED is a hint
788 */
789 /* np->n_flag &= ~NMODIFIED; */
790 } else
791 error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
792 np->n_attrstamp = 0;
793 }
794 if (np->n_flag & NWRITEERR) {
795 np->n_flag &= ~NWRITEERR;
796 error = np->n_error;
797 }
798 }
799 return (error);
800 }
801
802 /*
803 * nfs getattr call from vfs.
804 */
805 static int
806 nfs_getattr(ap)
807 struct vop_getattr_args /* {
808 struct vnode *a_vp;
809 struct vattr *a_vap;
810 struct ucred *a_cred;
811 struct proc *a_p;
812 } */ *ap;
813 {
814 register struct vnode *vp = ap->a_vp;
815 register struct nfsnode *np = VTONFS(vp);
816 register caddr_t cp;
817 register u_long *tl;
818 register int t1, t2;
819 caddr_t bpos, dpos;
820 int error = 0;
821 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
822 int v3 = NFS_ISV3(vp);
823 u_int64_t xid;
824 int avoidfloods;
825
826 FSDBG_TOP(513, np->n_size, np, np->n_vattr.va_size, np->n_flag);
827 /*
828 * Update local times for special files.
829 */
830 if (np->n_flag & (NACC | NUPD))
831 np->n_flag |= NCHG;
832 /*
833 * First look in the cache.
834 */
835 if ((error = nfs_getattrcache(vp, ap->a_vap)) == 0) {
836 FSDBG_BOT(513, np->n_size, 0, np->n_vattr.va_size, np->n_flag);
837 return (0);
838 }
839 if (error != ENOENT) {
840 FSDBG_BOT(513, np->n_size, error, np->n_vattr.va_size,
841 np->n_flag);
842 return (error);
843 }
844 error = 0;
845
846 if (v3 && nfsaccess_cache_timeout > 0) {
847 /* nfsstats.accesscache_misses++; */
848 if (error = nfs3_access_otw(vp, NFSV3ACCESS_ALL, ap->a_p,
849 ap->a_cred))
850 return (error);
851 if ((error = nfs_getattrcache(vp, ap->a_vap)) == 0)
852 return (0);
853 if (error != ENOENT)
854 return (error);
855 error = 0;
856 }
857 avoidfloods = 0;
858 tryagain:
859 nfsstats.rpccnt[NFSPROC_GETATTR]++;
860 nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3));
861 nfsm_fhtom(vp, v3);
862 nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred, &xid);
863 if (!error) {
864 nfsm_loadattr(vp, ap->a_vap, &xid);
865 if (!xid) { /* out-of-order rpc - attributes were dropped */
866 m_freem(mrep);
867 FSDBG(513, -1, np, np->n_xid << 32, np->n_xid);
868 if (avoidfloods++ < 100)
869 goto tryagain;
870 /*
871 * avoidfloods>1 is bizarre. at 100 pull the plug
872 */
873 panic("nfs_getattr: getattr flood\n");
874 }
875 if (np->n_mtime != ap->a_vap->va_mtime.tv_sec) {
876 FSDBG(513, -1, np, -1, vp);
877 if (vp->v_type == VDIR)
878 nfs_invaldir(vp);
879 error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
880 ap->a_p, 1);
881 FSDBG(513, -1, np, -2, error);
882 if (!error)
883 np->n_mtime = ap->a_vap->va_mtime.tv_sec;
884 }
885 }
886 nfsm_reqdone;
887
888 FSDBG_BOT(513, np->n_size, -1, np->n_vattr.va_size, error);
889 return (error);
890 }
891
892 /*
893 * nfs setattr call.
894 */
895 static int
896 nfs_setattr(ap)
897 struct vop_setattr_args /* {
898 struct vnodeop_desc *a_desc;
899 struct vnode *a_vp;
900 struct vattr *a_vap;
901 struct ucred *a_cred;
902 struct proc *a_p;
903 } */ *ap;
904 {
905 register struct vnode *vp = ap->a_vp;
906 register struct nfsnode *np = VTONFS(vp);
907 register struct vattr *vap = ap->a_vap;
908 int error = 0;
909 u_quad_t tsize;
910
911 #ifndef nolint
912 tsize = (u_quad_t)0;
913 #endif
914
915 #ifdef XXX /* enable this code soon! (but test it first) */
916 /*
917 * Setting of flags is not supported.
918 */
919 if (vap->va_flags != VNOVAL)
920 return (EOPNOTSUPP);
921 #endif
922
923 /*
924 * Disallow write attempts if the filesystem is mounted read-only.
925 */
926 if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
927 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
928 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
929 (vp->v_mount->mnt_flag & MNT_RDONLY))
930 return (EROFS);
931 if (vap->va_size != VNOVAL) {
932 switch (vp->v_type) {
933 case VDIR:
934 return (EISDIR);
935 case VCHR:
936 case VBLK:
937 case VSOCK:
938 case VFIFO:
939 if (vap->va_mtime.tv_sec == VNOVAL &&
940 vap->va_atime.tv_sec == VNOVAL &&
941 vap->va_mode == (u_short)VNOVAL &&
942 vap->va_uid == (uid_t)VNOVAL &&
943 vap->va_gid == (gid_t)VNOVAL)
944 return (0);
945 vap->va_size = VNOVAL;
946 break;
947 default:
948 /*
949 * Disallow write attempts if the filesystem is
950 * mounted read-only.
951 */
952 if (vp->v_mount->mnt_flag & MNT_RDONLY)
953 return (EROFS);
954 FSDBG_TOP(512, np->n_size, vap->va_size,
955 np->n_vattr.va_size, np->n_flag);
956 if (np->n_flag & NMODIFIED) {
957 if (vap->va_size == 0)
958 error = nfs_vinvalbuf(vp, 0,
959 ap->a_cred, ap->a_p, 1);
960 else
961 error = nfs_vinvalbuf(vp, V_SAVE,
962 ap->a_cred, ap->a_p, 1);
963 if (error) {
964 printf("nfs_setattr: nfs_vinvalbuf %d\n", error);
965 FSDBG_BOT(512, np->n_size, vap->va_size,
966 np->n_vattr.va_size, -1);
967 return (error);
968 }
969 } else if (np->n_size > vap->va_size) { /* shrinking? */
970 daddr_t obn, bn;
971 int biosize;
972 struct buf *bp;
973
974 biosize = min(vp->v_mount->mnt_stat.f_iosize,
975 PAGE_SIZE);
976 obn = (np->n_size - 1) / biosize;
977 bn = vap->va_size / biosize;
978 for ( ; obn >= bn; obn--)
979 if (incore(vp, obn)) {
980 bp = getblk(vp, obn, biosize, 0,
981 0, BLK_READ);
982 FSDBG(512, bp, bp->b_flags,
983 0, obn);
984 SET(bp->b_flags, B_INVAL);
985 brelse(bp);
986 }
987 }
988 tsize = np->n_size;
989 np->n_size = np->n_vattr.va_size = vap->va_size;
990 ubc_setsize(vp, (off_t)vap->va_size); /* XXX */
991 };
992 } else if ((vap->va_mtime.tv_sec != VNOVAL ||
993 vap->va_atime.tv_sec != VNOVAL) &&
994 (np->n_flag & NMODIFIED) && vp->v_type == VREG &&
995 (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
996 ap->a_p, 1)) == EINTR)
997 return (error);
998 error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
999 FSDBG_BOT(512, np->n_size, vap->va_size, np->n_vattr.va_size, error);
1000 if (error && vap->va_size != VNOVAL) {
1001 /* make every effort to resync file size w/ server... */
1002 int err = 0; /* preserve "error" for return */
1003
1004 printf("nfs_setattr: nfs_setattrrpc %d\n", error);
1005 np->n_size = np->n_vattr.va_size = tsize;
1006 ubc_setsize(vp, (off_t)np->n_size); /* XXX check error */
1007 vap->va_size = tsize;
1008 err = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
1009 if (err)
1010 printf("nfs_setattr1: nfs_setattrrpc %d\n", err);
1011 }
1012 return (error);
1013 }
1014
1015 /*
1016 * Do an nfs setattr rpc.
1017 */
1018 static int
1019 nfs_setattrrpc(vp, vap, cred, procp)
1020 register struct vnode *vp;
1021 register struct vattr *vap;
1022 struct ucred *cred;
1023 struct proc *procp;
1024 {
1025 register struct nfsv2_sattr *sp;
1026 register caddr_t cp;
1027 register long t1, t2;
1028 caddr_t bpos, dpos, cp2;
1029 u_long *tl;
1030 int error = 0, wccflag = NFSV3_WCCRATTR;
1031 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1032 int v3 = NFS_ISV3(vp);
1033 u_int64_t xid;
1034
1035 nfsstats.rpccnt[NFSPROC_SETATTR]++;
1036 nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3));
1037 nfsm_fhtom(vp, v3);
1038 if (v3) {
1039 if (vap->va_mode != (u_short)VNOVAL) {
1040 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1041 *tl++ = nfs_true;
1042 *tl = txdr_unsigned(vap->va_mode);
1043 } else {
1044 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1045 *tl = nfs_false;
1046 }
1047 if (vap->va_uid != (uid_t)VNOVAL) {
1048 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1049 *tl++ = nfs_true;
1050 *tl = txdr_unsigned(vap->va_uid);
1051 } else {
1052 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1053 *tl = nfs_false;
1054 }
1055 if (vap->va_gid != (gid_t)VNOVAL) {
1056 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1057 *tl++ = nfs_true;
1058 *tl = txdr_unsigned(vap->va_gid);
1059 } else {
1060 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1061 *tl = nfs_false;
1062 }
1063 if (vap->va_size != VNOVAL) {
1064 nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
1065 *tl++ = nfs_true;
1066 txdr_hyper(&vap->va_size, tl);
1067 } else {
1068 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1069 *tl = nfs_false;
1070 }
1071 if (vap->va_atime.tv_sec != VNOVAL) {
1072 if (vap->va_atime.tv_sec != time.tv_sec) {
1073 nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
1074 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
1075 txdr_nfsv3time(&vap->va_atime, tl);
1076 } else {
1077 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1078 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
1079 }
1080 } else {
1081 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1082 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
1083 }
1084 if (vap->va_mtime.tv_sec != VNOVAL) {
1085 if (vap->va_mtime.tv_sec != time.tv_sec) {
1086 nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
1087 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
1088 txdr_nfsv3time(&vap->va_mtime, tl);
1089 } else {
1090 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1091 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
1092 }
1093 } else {
1094 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1095 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
1096 }
1097 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1098 *tl = nfs_false;
1099 } else {
1100 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1101 if (vap->va_mode == (u_short)VNOVAL)
1102 sp->sa_mode = VNOVAL;
1103 else
1104 sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode);
1105 if (vap->va_uid == (uid_t)VNOVAL)
1106 sp->sa_uid = VNOVAL;
1107 else
1108 sp->sa_uid = txdr_unsigned(vap->va_uid);
1109 if (vap->va_gid == (gid_t)VNOVAL)
1110 sp->sa_gid = VNOVAL;
1111 else
1112 sp->sa_gid = txdr_unsigned(vap->va_gid);
1113 sp->sa_size = txdr_unsigned(vap->va_size);
1114 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1115 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1116 }
1117 nfsm_request(vp, NFSPROC_SETATTR, procp, cred, &xid);
1118 if (v3) {
1119 nfsm_wcc_data(vp, wccflag, &xid);
1120 if (!wccflag && vp->v_type != VBAD) /* EINVAL on VBAD node */
1121 VTONFS(vp)->n_attrstamp = 0;
1122 } else
1123 nfsm_loadattr(vp, (struct vattr *)0, &xid);
1124 nfsm_reqdone;
1125 return (error);
1126 }
1127
1128 /*
1129 * nfs lookup call, one step at a time...
1130 * First look in cache
1131 * If not found, unlock the directory nfsnode and do the rpc
1132 */
1133 static int
1134 nfs_lookup(ap)
1135 struct vop_lookup_args /* {
1136 struct vnodeop_desc *a_desc;
1137 struct vnode *a_dvp;
1138 struct vnode **a_vpp;
1139 struct componentname *a_cnp;
1140 } */ *ap;
1141 {
1142 register struct componentname *cnp = ap->a_cnp;
1143 register struct vnode *dvp = ap->a_dvp;
1144 register struct vnode **vpp = ap->a_vpp;
1145 register int flags = cnp->cn_flags;
1146 register struct vnode *newvp;
1147 register u_long *tl;
1148 register caddr_t cp;
1149 register long t1, t2;
1150 struct nfsmount *nmp;
1151 caddr_t bpos, dpos, cp2;
1152 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1153 long len;
1154 nfsfh_t *fhp;
1155 struct nfsnode *np;
1156 int lockparent, wantparent, error = 0, attrflag, fhsize;
1157 int v3 = NFS_ISV3(dvp);
1158 struct proc *p = cnp->cn_proc;
1159 int worldbuildworkaround = 1;
1160 u_int64_t xid;
1161
1162 if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
1163 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
1164 return (EROFS);
1165 *vpp = NULLVP;
1166 if (dvp->v_type != VDIR)
1167 return (ENOTDIR);
1168 lockparent = flags & LOCKPARENT;
1169 wantparent = flags & (LOCKPARENT|WANTPARENT);
1170 nmp = VFSTONFS(dvp->v_mount);
1171 np = VTONFS(dvp);
1172
1173 if (worldbuildworkaround) {
1174 /*
1175 * Temporary workaround for world builds to not have dvp go
1176 * VBAD on during server calls in this routine. When
1177 * the real ref counting problem is found take this out.
1178 * Note if this was later and before the nfsm_request
1179 * set up, the workaround did not work (NOTE other difference
1180 * was I only put one VREF in that time. Thus it needs
1181 * to be above the cache_lookup branch or with 2 VREFS. Not
1182 * sure which. Can't play with world builds right now to see
1183 * which. VOP_ACCESS could also make it go to server. - EKN
1184 */
1185 VREF(dvp); /* hang on to this dvp - EKN */
1186 VREF(dvp); /* hang on tight - EKN */
1187 }
1188
1189 if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
1190 struct vattr vattr;
1191 int vpid;
1192
1193 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p))) {
1194 *vpp = NULLVP;
1195 goto error_return;
1196 }
1197
1198 /* got to check to make sure the vnode didn't go away if access went to server */
1199 if ((*vpp)->v_type == VBAD) {
1200 error = EINVAL;
1201 goto error_return;
1202 }
1203
1204 newvp = *vpp;
1205 vpid = newvp->v_id;
1206 /*
1207 * See the comment starting `Step through' in ufs/ufs_lookup.c
1208 * for an explanation of the locking protocol
1209 */
1210 if (dvp == newvp) {
1211 VREF(newvp);
1212 error = 0;
1213 } else if (flags & ISDOTDOT) {
1214 VOP_UNLOCK(dvp, 0, p);
1215 error = vget(newvp, LK_EXCLUSIVE, p);
1216 if (!error && lockparent && (flags & ISLASTCN))
1217 error = vn_lock(dvp, LK_EXCLUSIVE, p);
1218 } else {
1219 error = vget(newvp, LK_EXCLUSIVE, p);
1220 if (!lockparent || error || !(flags & ISLASTCN))
1221 VOP_UNLOCK(dvp, 0, p);
1222 }
1223 if (!error) {
1224 if (vpid == newvp->v_id) {
1225 if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, p)
1226 && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
1227 nfsstats.lookupcache_hits++;
1228 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
1229 cnp->cn_flags |= SAVENAME;
1230 error = 0; /* ignore any from VOP_GETATTR */
1231 goto error_return;
1232 }
1233 cache_purge(newvp);
1234 }
1235 vput(newvp);
1236 if (lockparent && dvp != newvp && (flags & ISLASTCN))
1237 VOP_UNLOCK(dvp, 0, p);
1238 }
1239 error = vn_lock(dvp, LK_EXCLUSIVE, p);
1240 *vpp = NULLVP;
1241 if (error)
1242 goto error_return;
1243 }
1244
1245 /*
1246 * Got to check to make sure the vnode didn't go away if VOP_GETATTR went to server
1247 * or callers prior to this blocked and had it go VBAD.
1248 */
1249 if (dvp->v_type == VBAD) {
1250 error = EINVAL;
1251 goto error_return;
1252 }
1253
1254 error = 0;
1255 newvp = NULLVP;
1256 nfsstats.lookupcache_misses++;
1257 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
1258 len = cnp->cn_namelen;
1259 nfsm_reqhead(dvp, NFSPROC_LOOKUP,
1260 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
1261 nfsm_fhtom(dvp, v3);
1262 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
1263 /* nfsm_request for NFSv2 causes you to goto to nfsmout upon errors */
1264 nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred, &xid);
1265
1266 if (error) {
1267 nfsm_postop_attr(dvp, attrflag, &xid);
1268 m_freem(mrep);
1269 goto nfsmout;
1270 }
1271 nfsm_getfh(fhp, fhsize, v3);
1272
1273 /*
1274 * Handle RENAME case...
1275 */
1276 if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
1277 if (NFS_CMPFH(np, fhp, fhsize)) {
1278 m_freem(mrep);
1279 error = EISDIR;
1280 goto error_return;
1281 }
1282 if ((error = nfs_nget(dvp->v_mount, fhp, fhsize, &np))) {
1283 m_freem(mrep);
1284 goto error_return;
1285 }
1286 newvp = NFSTOV(np);
1287 if (v3) {
1288 u_int64_t dxid = xid;
1289
1290 nfsm_postop_attr(newvp, attrflag, &xid);
1291 nfsm_postop_attr(dvp, attrflag, &dxid);
1292 } else
1293 nfsm_loadattr(newvp, (struct vattr *)0, &xid);
1294 *vpp = newvp;
1295 m_freem(mrep);
1296 cnp->cn_flags |= SAVENAME;
1297 if (!lockparent)
1298 VOP_UNLOCK(dvp, 0, p);
1299 error = 0;
1300 goto error_return;
1301 }
1302
1303 if (flags & ISDOTDOT) {
1304 VOP_UNLOCK(dvp, 0, p);
1305 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
1306 if (error) {
1307 vn_lock(dvp, LK_EXCLUSIVE + LK_RETRY, p);
1308 goto error_return;
1309 }
1310 newvp = NFSTOV(np);
1311 if (lockparent && (flags & ISLASTCN) &&
1312 (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
1313 vput(newvp);
1314 goto error_return;
1315 }
1316 } else if (NFS_CMPFH(np, fhp, fhsize)) {
1317 VREF(dvp);
1318 newvp = dvp;
1319 } else {
1320 if ((error = nfs_nget(dvp->v_mount, fhp, fhsize, &np))) {
1321 m_freem(mrep);
1322 goto error_return;
1323 }
1324 if (!lockparent || !(flags & ISLASTCN))
1325 VOP_UNLOCK(dvp, 0, p);
1326 newvp = NFSTOV(np);
1327 }
1328 if (v3) {
1329 u_int64_t dxid = xid;
1330
1331 nfsm_postop_attr(newvp, attrflag, &xid);
1332 nfsm_postop_attr(dvp, attrflag, &dxid);
1333 } else
1334 nfsm_loadattr(newvp, (struct vattr *)0, &xid);
1335 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
1336 cnp->cn_flags |= SAVENAME;
1337 if ((cnp->cn_flags & MAKEENTRY) &&
1338 (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
1339 np->n_ctime = np->n_vattr.va_ctime.tv_sec;
1340 cache_enter(dvp, newvp, cnp);
1341 }
1342 *vpp = newvp;
1343 nfsm_reqdone;
1344 if (error) {
1345 if (newvp != NULLVP) {
1346 vrele(newvp);
1347 *vpp = NULLVP;
1348 }
1349 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
1350 (flags & ISLASTCN) && error == ENOENT) {
1351 if (!lockparent)
1352 VOP_UNLOCK(dvp, 0, p);
1353 if (dvp->v_mount->mnt_flag & MNT_RDONLY)
1354 error = EROFS;
1355 else
1356 error = EJUSTRETURN;
1357 }
1358 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
1359 cnp->cn_flags |= SAVENAME;
1360 }
1361 error_return:
1362 /*
1363 * These "vreles" set dvp refcounts back to where they were
1364 * before we took extra 2 VREFS to avoid VBAD vnode on dvp
1365 * during server calls for world builds. Remove when real
1366 * fix is found. - EKN
1367 */
1368 if (worldbuildworkaround) {
1369 vrele(dvp); /* end of hanging on tight to dvp - EKN */
1370 vrele(dvp); /* end of hanging on tight to dvp - EKN */
1371 }
1372
1373 return (error);
1374 }
1375
1376 /*
1377 * nfs read call.
1378 * Just call nfs_bioread() to do the work.
1379 */
1380 static int
1381 nfs_read(ap)
1382 struct vop_read_args /* {
1383 struct vnode *a_vp;
1384 struct uio *a_uio;
1385 int a_ioflag;
1386 struct ucred *a_cred;
1387 } */ *ap;
1388 {
1389 register struct vnode *vp = ap->a_vp;
1390
1391 if (vp->v_type != VREG)
1392 return (EPERM);
1393 return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred, 0));
1394 }
1395
1396
1397 /*
1398 * nfs readlink call
1399 */
1400 static int
1401 nfs_readlink(ap)
1402 struct vop_readlink_args /* {
1403 struct vnode *a_vp;
1404 struct uio *a_uio;
1405 struct ucred *a_cred;
1406 } */ *ap;
1407 {
1408 register struct vnode *vp = ap->a_vp;
1409
1410 if (vp->v_type != VLNK)
1411 return (EPERM);
1412 return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred, 0));
1413 }
1414
1415 /*
1416 * Do a readlink rpc.
1417 * Called by nfs_doio() from below the buffer cache.
1418 */
1419 int
1420 nfs_readlinkrpc(vp, uiop, cred)
1421 register struct vnode *vp;
1422 struct uio *uiop;
1423 struct ucred *cred;
1424 {
1425 register u_long *tl;
1426 register caddr_t cp;
1427 register long t1, t2;
1428 caddr_t bpos, dpos, cp2;
1429 int error = 0, len, attrflag;
1430 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1431 int v3 = NFS_ISV3(vp);
1432 u_int64_t xid;
1433
1434 nfsstats.rpccnt[NFSPROC_READLINK]++;
1435 nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
1436 nfsm_fhtom(vp, v3);
1437 nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred, &xid);
1438 if (v3)
1439 nfsm_postop_attr(vp, attrflag, &xid);
1440 if (!error) {
1441 nfsm_strsiz(len, NFS_MAXPATHLEN);
1442 if (len == NFS_MAXPATHLEN) {
1443 struct nfsnode *np = VTONFS(vp);
1444 #if DIAGNOSTIC
1445 if (!np)
1446 panic("nfs_readlinkrpc: null np");
1447 #endif
1448 if (np->n_size && np->n_size < NFS_MAXPATHLEN)
1449 len = np->n_size;
1450 }
1451 nfsm_mtouio(uiop, len);
1452 }
1453 nfsm_reqdone;
1454 return (error);
1455 }
1456
1457 /*
1458 * nfs read rpc call
1459 * Ditto above
1460 */
1461 int
1462 nfs_readrpc(vp, uiop, cred)
1463 register struct vnode *vp;
1464 struct uio *uiop;
1465 struct ucred *cred;
1466 {
1467 register u_long *tl;
1468 register caddr_t cp;
1469 register long t1, t2;
1470 caddr_t bpos, dpos, cp2;
1471 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1472 struct nfsmount *nmp;
1473 int error = 0, len, retlen, tsiz, eof, attrflag;
1474 int v3 = NFS_ISV3(vp);
1475 u_int64_t xid;
1476
1477 #ifndef nolint
1478 eof = 0;
1479 #endif
1480 nmp = VFSTONFS(vp->v_mount);
1481 tsiz = uiop->uio_resid;
1482 if (((u_int64_t)uiop->uio_offset + (unsigned int)tsiz > 0xffffffff) &&
1483 !v3)
1484 return (EFBIG);
1485 while (tsiz > 0) {
1486 nfsstats.rpccnt[NFSPROC_READ]++;
1487 len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
1488 nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3);
1489 nfsm_fhtom(vp, v3);
1490 nfsm_build(tl, u_long *, NFSX_UNSIGNED * 3);
1491 if (v3) {
1492 txdr_hyper(&uiop->uio_offset, tl);
1493 *(tl + 2) = txdr_unsigned(len);
1494 } else {
1495 *tl++ = txdr_unsigned(uiop->uio_offset);
1496 *tl++ = txdr_unsigned(len);
1497 *tl = 0;
1498 }
1499 nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred, &xid);
1500 if (v3) {
1501 nfsm_postop_attr(vp, attrflag, &xid);
1502 if (error) {
1503 m_freem(mrep);
1504 goto nfsmout;
1505 }
1506 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1507 eof = fxdr_unsigned(int, *(tl + 1));
1508 } else
1509 nfsm_loadattr(vp, (struct vattr *)0, &xid);
1510 nfsm_strsiz(retlen, nmp->nm_rsize);
1511 nfsm_mtouio(uiop, retlen);
1512 m_freem(mrep);
1513 tsiz -= retlen;
1514 if (v3) {
1515 if (eof || retlen == 0)
1516 tsiz = 0;
1517 } else if (retlen < len)
1518 tsiz = 0;
1519 }
1520 nfsmout:
1521 return (error);
1522 }
1523
1524 /*
1525 * nfs write call
1526 */
1527 int
1528 nfs_writerpc(vp, uiop, cred, iomode, must_commit)
1529 register struct vnode *vp;
1530 register struct uio *uiop;
1531 struct ucred *cred;
1532 int *iomode, *must_commit;
1533 {
1534 register u_long *tl;
1535 register caddr_t cp;
1536 register int t1, t2, backup;
1537 caddr_t bpos, dpos, cp2;
1538 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1539 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1540 int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit;
1541 int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC;
1542 u_int64_t xid;
1543
1544 #if DIAGNOSTIC
1545 if (uiop->uio_iovcnt != 1)
1546 panic("nfs_writerpc: iovcnt > 1");
1547 #endif
1548 *must_commit = 0;
1549 tsiz = uiop->uio_resid;
1550 if (((u_int64_t)uiop->uio_offset + (unsigned int)tsiz > 0xffffffff) && !v3)
1551 return (EFBIG);
1552 while (tsiz > 0) {
1553 nfsstats.rpccnt[NFSPROC_WRITE]++;
1554 len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
1555 nfsm_reqhead(vp, NFSPROC_WRITE,
1556 NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len));
1557 nfsm_fhtom(vp, v3);
1558 if (v3) {
1559 nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
1560 txdr_hyper(&uiop->uio_offset, tl);
1561 tl += 2;
1562 *tl++ = txdr_unsigned(len);
1563 *tl++ = txdr_unsigned(*iomode);
1564 } else {
1565 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1566 *++tl = txdr_unsigned(uiop->uio_offset);
1567 tl += 2;
1568 }
1569 *tl = txdr_unsigned(len);
1570 nfsm_uiotom(uiop, len);
1571 nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred, &xid);
1572 if (v3) {
1573 wccflag = NFSV3_WCCCHK;
1574 nfsm_wcc_data(vp, wccflag, &xid);
1575 if (!error) {
1576 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED +
1577 NFSX_V3WRITEVERF);
1578 rlen = fxdr_unsigned(int, *tl++);
1579 if (rlen <= 0) {
1580 error = NFSERR_IO;
1581 break;
1582 } else if (rlen < len) {
1583 backup = len - rlen;
1584 uiop->uio_iov->iov_base -= backup;
1585 uiop->uio_iov->iov_len += backup;
1586 uiop->uio_offset -= backup;
1587 uiop->uio_resid += backup;
1588 len = rlen;
1589 }
1590 commit = fxdr_unsigned(int, *tl++);
1591
1592 /*
1593 * Return the lowest committment level
1594 * obtained by any of the RPCs.
1595 */
1596 if (committed == NFSV3WRITE_FILESYNC)
1597 committed = commit;
1598 else if (committed == NFSV3WRITE_DATASYNC &&
1599 commit == NFSV3WRITE_UNSTABLE)
1600 committed = commit;
1601 if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0) {
1602 bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
1603 NFSX_V3WRITEVERF);
1604 nmp->nm_flag |= NFSMNT_HASWRITEVERF;
1605 } else if (bcmp((caddr_t)tl,
1606 (caddr_t)nmp->nm_verf, NFSX_V3WRITEVERF)) {
1607 *must_commit = 1;
1608 bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
1609 NFSX_V3WRITEVERF);
1610 }
1611 }
1612 } else
1613 nfsm_loadattr(vp, (struct vattr *)0, &xid);
1614
1615 if (wccflag && vp->v_type != VBAD) /* EINVAL set on VBAD node */
1616 VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
1617 m_freem(mrep);
1618 /*
1619 * we seem to have a case where we end up looping on shutdown
1620 * and taking down nfs servers. For V3, error cases, there is
1621 * no way to terminate loop, if the len was 0, meaning,
1622 * nmp->nm_wsize was trashed. FreeBSD has this fix in it.
1623 * Let's try it.
1624 */
1625 if (error)
1626 break;
1627 tsiz -= len;
1628 }
1629 nfsmout:
1630 /* EKN
1631 * does it make sense to even say it was committed if we had an error?
1632 * okay well just don't on bad vnodes then. EINVAL will be
1633 * returned on bad vnodes
1634 */
1635 if (vp->v_type != VBAD && (vp->v_mount->mnt_flag & MNT_ASYNC))
1636 committed = NFSV3WRITE_FILESYNC;
1637 *iomode = committed;
1638 if (error)
1639 uiop->uio_resid = tsiz;
1640 return (error);
1641 }
1642
1643 /*
1644 * nfs mknod rpc
1645 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1646 * mode set to specify the file type and the size field for rdev.
1647 */
1648 static int
1649 nfs_mknodrpc(dvp, vpp, cnp, vap)
1650 register struct vnode *dvp;
1651 register struct vnode **vpp;
1652 register struct componentname *cnp;
1653 register struct vattr *vap;
1654 {
1655 register struct nfsv2_sattr *sp;
1656 register struct nfsv3_sattr *sp3;
1657 register u_long *tl;
1658 register caddr_t cp;
1659 register long t1, t2;
1660 struct vnode *newvp = (struct vnode *)0;
1661 struct nfsnode *np = (struct nfsnode *)0;
1662 struct vattr vattr;
1663 char *cp2;
1664 caddr_t bpos, dpos;
1665 int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
1666 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1667 u_long rdev;
1668 u_int64_t xid;
1669 int v3 = NFS_ISV3(dvp);
1670
1671 if (vap->va_type == VCHR || vap->va_type == VBLK)
1672 rdev = txdr_unsigned(vap->va_rdev);
1673 else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
1674 rdev = 0xffffffff;
1675 else {
1676 VOP_ABORTOP(dvp, cnp);
1677 vput(dvp);
1678 return (EOPNOTSUPP);
1679 }
1680 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
1681 VOP_ABORTOP(dvp, cnp);
1682 vput(dvp);
1683 return (error);
1684 }
1685 nfsstats.rpccnt[NFSPROC_MKNOD]++;
1686 nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
1687 + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
1688 nfsm_fhtom(dvp, v3);
1689 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1690 if (v3) {
1691 nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3SRVSATTR);
1692 *tl++ = vtonfsv3_type(vap->va_type);
1693 sp3 = (struct nfsv3_sattr *)tl;
1694 nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
1695 if (vap->va_type == VCHR || vap->va_type == VBLK) {
1696 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1697 *tl++ = txdr_unsigned(major(vap->va_rdev));
1698 *tl = txdr_unsigned(minor(vap->va_rdev));
1699 }
1700 } else {
1701 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1702 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1703 sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1704 sp->sa_gid = txdr_unsigned(vattr.va_gid);
1705 sp->sa_size = rdev;
1706 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1707 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1708 }
1709 nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred, &xid);
1710 if (!error) {
1711 nfsm_mtofh(dvp, newvp, v3, gotvp, &xid);
1712 if (!gotvp) {
1713 if (newvp) {
1714 vput(newvp);
1715 newvp = (struct vnode *)0;
1716 }
1717 error = nfs_lookitup(dvp, cnp->cn_nameptr,
1718 cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
1719 if (!error)
1720 newvp = NFSTOV(np);
1721 }
1722 }
1723 if (v3)
1724 nfsm_wcc_data(dvp, wccflag, &xid);
1725 nfsm_reqdone;
1726 if (error) {
1727 if (newvp)
1728 vput(newvp);
1729 } else {
1730 if (cnp->cn_flags & MAKEENTRY)
1731 cache_enter(dvp, newvp, cnp);
1732 *vpp = newvp;
1733 }
1734 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1735 if (dvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
1736 VTONFS(dvp)->n_flag |= NMODIFIED;
1737 if (!wccflag)
1738 VTONFS(dvp)->n_attrstamp = 0;
1739 }
1740 vput(dvp);
1741 return (error);
1742 }
1743
1744 /*
1745 * nfs mknod vop
1746 * just call nfs_mknodrpc() to do the work.
1747 */
1748 /* ARGSUSED */
1749 static int
1750 nfs_mknod(ap)
1751 struct vop_mknod_args /* {
1752 struct vnode *a_dvp;
1753 struct vnode **a_vpp;
1754 struct componentname *a_cnp;
1755 struct vattr *a_vap;
1756 } */ *ap;
1757 {
1758 struct vnode *newvp;
1759 int error;
1760
1761 error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap);
1762 if (!error && newvp)
1763 vput(newvp);
1764 *ap->a_vpp = 0;
1765 return (error);
1766 }
1767
1768 static u_long create_verf;
1769 /*
1770 * nfs file create call
1771 */
1772 static int
1773 nfs_create(ap)
1774 struct vop_create_args /* {
1775 struct vnode *a_dvp;
1776 struct vnode **a_vpp;
1777 struct componentname *a_cnp;
1778 struct vattr *a_vap;
1779 } */ *ap;
1780 {
1781 register struct vnode *dvp = ap->a_dvp;
1782 register struct vattr *vap = ap->a_vap;
1783 register struct componentname *cnp = ap->a_cnp;
1784 register struct nfsv2_sattr *sp;
1785 register struct nfsv3_sattr *sp3;
1786 register u_long *tl;
1787 register caddr_t cp;
1788 register long t1, t2;
1789 struct nfsnode *np = (struct nfsnode *)0;
1790 struct vnode *newvp = (struct vnode *)0;
1791 caddr_t bpos, dpos, cp2;
1792 int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0;
1793 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1794 struct vattr vattr;
1795 int v3 = NFS_ISV3(dvp);
1796 u_int64_t xid;
1797
1798 /*
1799 * Oops, not for me..
1800 */
1801 if (vap->va_type == VSOCK)
1802 return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
1803
1804 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
1805 VOP_ABORTOP(dvp, cnp);
1806 vput(dvp);
1807 return (error);
1808 }
1809 if (vap->va_vaflags & VA_EXCLUSIVE)
1810 fmode |= O_EXCL;
1811 again:
1812 nfsstats.rpccnt[NFSPROC_CREATE]++;
1813 nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
1814 nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
1815 nfsm_fhtom(dvp, v3);
1816 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1817 if (v3) {
1818 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1819 if (fmode & O_EXCL) {
1820 *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE);
1821 nfsm_build(tl, u_long *, NFSX_V3CREATEVERF);
1822 if (!TAILQ_EMPTY(&in_ifaddrhead))
1823 *tl++ = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr.s_addr;
1824 else
1825 *tl++ = create_verf;
1826 *tl = ++create_verf;
1827 } else {
1828 *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED);
1829 nfsm_build(tl, u_long *, NFSX_V3SRVSATTR);
1830 sp3 = (struct nfsv3_sattr *)tl;
1831 nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
1832 }
1833 } else {
1834 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1835 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1836 sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1837 sp->sa_gid = txdr_unsigned(vattr.va_gid);
1838 sp->sa_size = 0;
1839 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1840 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1841 }
1842 nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred, &xid);
1843 if (!error) {
1844 nfsm_mtofh(dvp, newvp, v3, gotvp, &xid);
1845 if (!gotvp) {
1846 if (newvp) {
1847 vput(newvp);
1848 newvp = (struct vnode *)0;
1849 }
1850 error = nfs_lookitup(dvp, cnp->cn_nameptr,
1851 cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
1852 if (!error)
1853 newvp = NFSTOV(np);
1854 }
1855 }
1856 if (v3)
1857 nfsm_wcc_data(dvp, wccflag, &xid);
1858 nfsm_reqdone;
1859 if (error) {
1860 if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) {
1861 fmode &= ~O_EXCL;
1862 goto again;
1863 }
1864 if (newvp)
1865 vput(newvp);
1866 } else if (v3 && (fmode & O_EXCL))
1867 error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
1868 if (!error) {
1869 if (cnp->cn_flags & MAKEENTRY)
1870 cache_enter(dvp, newvp, cnp);
1871 *ap->a_vpp = newvp;
1872 }
1873 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1874 if (dvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
1875 VTONFS(dvp)->n_flag |= NMODIFIED;
1876 if (!wccflag)
1877 VTONFS(dvp)->n_attrstamp = 0;
1878 }
1879 vput(dvp);
1880 return (error);
1881 }
1882
1883 /*
1884 * nfs file remove call
1885 * To try and make nfs semantics closer to ufs semantics, a file that has
1886 * other processes using the vnode is renamed instead of removed and then
1887 * removed later on the last close.
1888 * - If v_usecount > 1
1889 * If a rename is not already in the works
1890 * call nfs_sillyrename() to set it up
1891 * else
1892 * do the remove rpc
1893 */
1894 static int
1895 nfs_remove(ap)
1896 struct vop_remove_args /* {
1897 struct vnodeop_desc *a_desc;
1898 struct vnode * a_dvp;
1899 struct vnode * a_vp;
1900 struct componentname * a_cnp;
1901 } */ *ap;
1902 {
1903 register struct vnode *vp = ap->a_vp;
1904 register struct vnode *dvp = ap->a_dvp;
1905 register struct componentname *cnp = ap->a_cnp;
1906 register struct nfsnode *np = VTONFS(vp);
1907 int error = 0;
1908 struct vattr vattr;
1909 int file_deleted = 0;
1910
1911 #if DIAGNOSTIC
1912 if ((cnp->cn_flags & HASBUF) == 0)
1913 panic("nfs_remove: no name");
1914 if (vp->v_usecount < 1)
1915 panic("nfs_remove: bad v_usecount");
1916 #endif
1917 if (vp->v_usecount == 1 ||
1918 (UBCISVALID(vp)&&(vp->v_usecount==2)) ||
1919 (np->n_sillyrename &&
1920 VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 &&
1921 vattr.va_nlink > 1)) {
1922 /*
1923 * Purge the name cache so that the chance of a lookup for
1924 * the name succeeding while the remove is in progress is
1925 * minimized. Without node locking it can still happen, such
1926 * that an I/O op returns ESTALE, but since you get this if
1927 * another host removes the file..
1928 */
1929 cache_purge(vp);
1930 /*
1931 * throw away biocache buffers, mainly to avoid
1932 * unnecessary delayed writes later.
1933 */
1934 error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
1935 np->n_size = 0;
1936 ubc_setsize(vp, (off_t)0); /* XXX check error */
1937 /* Do the rpc */
1938 if (error != EINTR)
1939 error = nfs_removerpc(dvp, cnp->cn_nameptr,
1940 cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc);
1941 /*
1942 * Kludge City: If the first reply to the remove rpc is lost..
1943 * the reply to the retransmitted request will be ENOENT
1944 * since the file was in fact removed
1945 * Therefore, we cheat and return success.
1946 */
1947 if (error == ENOENT)
1948 error = 0;
1949 file_deleted = 1;
1950 } else if (!np->n_sillyrename) {
1951 error = nfs_sillyrename(dvp, vp, cnp);
1952 }
1953
1954 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1955 np->n_attrstamp = 0;
1956 vput(dvp);
1957
1958 VOP_UNLOCK(vp, 0, cnp->cn_proc);
1959
1960 if (file_deleted)
1961 ubc_uncache(vp);
1962
1963 vrele(vp);
1964
1965 return (error);
1966 }
1967
1968 /*
1969 * nfs file remove rpc called from nfs_inactive
1970 */
1971 int
1972 nfs_removeit(sp)
1973 register struct sillyrename *sp;
1974 {
1975
1976 return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
1977 (struct proc *)0));
1978 }
1979
1980 /*
1981 * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
1982 */
1983 static int
1984 nfs_removerpc(dvp, name, namelen, cred, proc)
1985 register struct vnode *dvp;
1986 char *name;
1987 int namelen;
1988 struct ucred *cred;
1989 struct proc *proc;
1990 {
1991 register u_long *tl;
1992 register caddr_t cp;
1993 register long t1, t2;
1994 caddr_t bpos, dpos, cp2;
1995 int error = 0, wccflag = NFSV3_WCCRATTR;
1996 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1997 int v3 = NFS_ISV3(dvp);
1998 u_int64_t xid;
1999
2000 nfsstats.rpccnt[NFSPROC_REMOVE]++;
2001 nfsm_reqhead(dvp, NFSPROC_REMOVE,
2002 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
2003 nfsm_fhtom(dvp, v3);
2004 nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
2005 nfsm_request(dvp, NFSPROC_REMOVE, proc, cred, &xid);
2006 if (v3)
2007 nfsm_wcc_data(dvp, wccflag, &xid);
2008 nfsm_reqdone;
2009 if (dvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
2010 VTONFS(dvp)->n_flag |= NMODIFIED;
2011 if (!wccflag)
2012 VTONFS(dvp)->n_attrstamp = 0;
2013 }
2014 return (error);
2015 }
2016
2017 /*
2018 * nfs file rename call
2019 */
2020 static int
2021 nfs_rename(ap)
2022 struct vop_rename_args /* {
2023 struct vnode *a_fdvp;
2024 struct vnode *a_fvp;
2025 struct componentname *a_fcnp;
2026 struct vnode *a_tdvp;
2027 struct vnode *a_tvp;
2028 struct componentname *a_tcnp;
2029 } */ *ap;
2030 {
2031 register struct vnode *fvp = ap->a_fvp;
2032 register struct vnode *tvp = ap->a_tvp;
2033 register struct vnode *fdvp = ap->a_fdvp;
2034 register struct vnode *tdvp = ap->a_tdvp;
2035 register struct componentname *tcnp = ap->a_tcnp;
2036 register struct componentname *fcnp = ap->a_fcnp;
2037 int error;
2038
2039 #if DIAGNOSTIC
2040 if ((tcnp->cn_flags & HASBUF) == 0 ||
2041 (fcnp->cn_flags & HASBUF) == 0)
2042 panic("nfs_rename: no name");
2043 #endif
2044 /* Check for cross-device rename */
2045 if ((fvp->v_mount != tdvp->v_mount) ||
2046 (tvp && (fvp->v_mount != tvp->v_mount))) {
2047 error = EXDEV;
2048 goto out;
2049 }
2050
2051 /*
2052 * If the tvp exists and is in use, sillyrename it before doing the
2053 * rename of the new file over it.
2054 * XXX Can't sillyrename a directory.
2055 */
2056 if (tvp && (tvp->v_usecount>(UBCISVALID(tvp) ? 2 : 1)) &&
2057 !VTONFS(tvp)->n_sillyrename &&
2058 tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) {
2059 vput(tvp);
2060 tvp = NULL;
2061 }
2062
2063 error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
2064 tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
2065 tcnp->cn_proc);
2066
2067 if (fvp->v_type == VDIR) {
2068 if (tvp != NULL && tvp->v_type == VDIR)
2069 cache_purge(tdvp);
2070 cache_purge(fdvp);
2071 }
2072 out:
2073 if (tdvp == tvp)
2074 vrele(tdvp);
2075 else
2076 vput(tdvp);
2077 if (tvp)
2078 vput(tvp);
2079 vrele(fdvp);
2080 vrele(fvp);
2081 /*
2082 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
2083 */
2084 if (error == ENOENT)
2085 error = 0;
2086 return (error);
2087 }
2088
2089 /*
2090 * nfs file rename rpc called from nfs_remove() above
2091 */
2092 static int
2093 nfs_renameit(sdvp, scnp, sp)
2094 struct vnode *sdvp;
2095 struct componentname *scnp;
2096 register struct sillyrename *sp;
2097 {
2098 return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen,
2099 sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_proc));
2100 }
2101
2102 /*
2103 * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
2104 */
2105 static int
2106 nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc)
2107 register struct vnode *fdvp;
2108 char *fnameptr;
2109 int fnamelen;
2110 register struct vnode *tdvp;
2111 char *tnameptr;
2112 int tnamelen;
2113 struct ucred *cred;
2114 struct proc *proc;
2115 {
2116 register u_long *tl;
2117 register caddr_t cp;
2118 register long t1, t2;
2119 caddr_t bpos, dpos, cp2;
2120 int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
2121 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2122 int v3 = NFS_ISV3(fdvp);
2123 u_int64_t xid;
2124
2125 nfsstats.rpccnt[NFSPROC_RENAME]++;
2126 nfsm_reqhead(fdvp, NFSPROC_RENAME,
2127 (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
2128 nfsm_rndup(tnamelen));
2129 nfsm_fhtom(fdvp, v3);
2130 nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
2131 nfsm_fhtom(tdvp, v3);
2132 nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
2133 nfsm_request(fdvp, NFSPROC_RENAME, proc, cred, &xid);
2134 if (v3) {
2135 u_int64_t txid = xid;
2136
2137 nfsm_wcc_data(fdvp, fwccflag, &xid);
2138 nfsm_wcc_data(tdvp, twccflag, &txid);
2139 }
2140 nfsm_reqdone;
2141 if (fdvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
2142 VTONFS(fdvp)->n_flag |= NMODIFIED;
2143 if (!fwccflag)
2144 VTONFS(fdvp)->n_attrstamp = 0;
2145 }
2146 if (tdvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
2147 VTONFS(tdvp)->n_flag |= NMODIFIED;
2148 if (!twccflag)
2149 VTONFS(tdvp)->n_attrstamp = 0;
2150 }
2151 return (error);
2152 }
2153
2154 /*
2155 * nfs hard link create call
2156 */
2157 static int
2158 nfs_link(ap)
2159 struct vop_link_args /* {
2160 struct vnode *a_vp;
2161 struct vnode *a_tdvp;
2162 struct componentname *a_cnp;
2163 } */ *ap;
2164 {
2165 register struct vnode *vp = ap->a_vp;
2166 register struct vnode *tdvp = ap->a_tdvp;
2167 register struct componentname *cnp = ap->a_cnp;
2168 register u_long *tl;
2169 register caddr_t cp;
2170 register long t1, t2;
2171 caddr_t bpos, dpos, cp2;
2172 int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
2173 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2174 int v3 = NFS_ISV3(vp);
2175 u_int64_t xid;
2176
2177 if (vp->v_mount != tdvp->v_mount) {
2178 VOP_ABORTOP(vp, cnp);
2179 if (tdvp == vp)
2180 vrele(tdvp);
2181 else
2182 vput(tdvp);
2183 return (EXDEV);
2184 }
2185
2186 /*
2187 * Push all writes to the server, so that the attribute cache
2188 * doesn't get "out of sync" with the server.
2189 * XXX There should be a better way!
2190 */
2191 VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc);
2192
2193 nfsstats.rpccnt[NFSPROC_LINK]++;
2194 nfsm_reqhead(vp, NFSPROC_LINK,
2195 NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
2196 nfsm_fhtom(vp, v3);
2197 nfsm_fhtom(tdvp, v3);
2198 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
2199 nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred, &xid);
2200 if (v3) {
2201 u_int64_t txid = xid;
2202
2203 nfsm_postop_attr(vp, attrflag, &xid);
2204 nfsm_wcc_data(tdvp, wccflag, &txid);
2205 }
2206 nfsm_reqdone;
2207 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
2208
2209 VTONFS(tdvp)->n_flag |= NMODIFIED;
2210 if (!attrflag && vp->v_type != VBAD) /* EINVAL set on VBAD vnode */
2211 VTONFS(vp)->n_attrstamp = 0;
2212 if (!wccflag && tdvp->v_type != VBAD) /* EINVAL set on VBAD vnode */
2213 VTONFS(tdvp)->n_attrstamp = 0;
2214 vput(tdvp);
2215 /*
2216 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2217 */
2218 if (error == EEXIST)
2219 error = 0;
2220 return (error);
2221 }
2222
2223 /*
2224 * nfs symbolic link create call
2225 */
2226 static int
2227 nfs_symlink(ap)
2228 struct vop_symlink_args /* {
2229 struct vnode *a_dvp;
2230 struct vnode **a_vpp;
2231 struct componentname *a_cnp;
2232 struct vattr *a_vap;
2233 char *a_target;
2234 } */ *ap;
2235 {
2236 register struct vnode *dvp = ap->a_dvp;
2237 register struct vattr *vap = ap->a_vap;
2238 register struct componentname *cnp = ap->a_cnp;
2239 register struct nfsv2_sattr *sp;
2240 register struct nfsv3_sattr *sp3;
2241 register u_long *tl;
2242 register caddr_t cp;
2243 register long t1, t2;
2244 caddr_t bpos, dpos, cp2;
2245 int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
2246 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2247 struct vnode *newvp = (struct vnode *)0;
2248 int v3 = NFS_ISV3(dvp);
2249 u_int64_t xid;
2250
2251 nfsstats.rpccnt[NFSPROC_SYMLINK]++;
2252 slen = strlen(ap->a_target);
2253 nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED +
2254 nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
2255 nfsm_fhtom(dvp, v3);
2256 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
2257 if (v3) {
2258 nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
2259 nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid,
2260 cnp->cn_cred->cr_gid);
2261 }
2262 nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
2263 if (!v3) {
2264 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2265 sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode);
2266 sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
2267 sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
2268 sp->sa_size = -1;
2269 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
2270 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
2271 }
2272 nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred, &xid);
2273 if (v3) {
2274 u_int64_t dxid = xid;
2275
2276 if (!error)
2277 nfsm_mtofh(dvp, newvp, v3, gotvp, &xid);
2278 nfsm_wcc_data(dvp, wccflag, &dxid);
2279 }
2280 nfsm_reqdone;
2281 if (newvp)
2282 vput(newvp);
2283 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
2284 if (dvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
2285 VTONFS(dvp)->n_flag |= NMODIFIED;
2286 if (!wccflag)
2287 VTONFS(dvp)->n_attrstamp = 0;
2288 }
2289 vput(dvp);
2290 /*
2291 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2292 */
2293 if (error == EEXIST)
2294 error = 0;
2295 return (error);
2296 }
2297
2298 /*
2299 * nfs make dir call
2300 */
2301 static int
2302 nfs_mkdir(ap)
2303 struct vop_mkdir_args /* {
2304 struct vnode *a_dvp;
2305 struct vnode **a_vpp;
2306 struct componentname *a_cnp;
2307 struct vattr *a_vap;
2308 } */ *ap;
2309 {
2310 register struct vnode *dvp = ap->a_dvp;
2311 register struct vattr *vap = ap->a_vap;
2312 register struct componentname *cnp = ap->a_cnp;
2313 register struct nfsv2_sattr *sp;
2314 register struct nfsv3_sattr *sp3;
2315 register u_long *tl;
2316 register caddr_t cp;
2317 register long t1, t2;
2318 register int len;
2319 struct nfsnode *np = (struct nfsnode *)0;
2320 struct vnode *newvp = (struct vnode *)0;
2321 caddr_t bpos, dpos, cp2;
2322 int error = 0, wccflag = NFSV3_WCCRATTR;
2323 int gotvp = 0;
2324 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2325 struct vattr vattr;
2326 int v3 = NFS_ISV3(dvp);
2327 u_int64_t xid, dxid;
2328
2329 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
2330 VOP_ABORTOP(dvp, cnp);
2331 vput(dvp);
2332 return (error);
2333 }
2334 len = cnp->cn_namelen;
2335 nfsstats.rpccnt[NFSPROC_MKDIR]++;
2336 nfsm_reqhead(dvp, NFSPROC_MKDIR,
2337 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
2338 nfsm_fhtom(dvp, v3);
2339 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
2340 if (v3) {
2341 nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
2342 nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
2343 } else {
2344 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2345 sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode);
2346 sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
2347 sp->sa_gid = txdr_unsigned(vattr.va_gid);
2348 sp->sa_size = -1;
2349 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
2350 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
2351 }
2352 nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred, &xid);
2353 dxid = xid;
2354 if (!error)
2355 nfsm_mtofh(dvp, newvp, v3, gotvp, &xid);
2356 if (v3)
2357 nfsm_wcc_data(dvp, wccflag, &dxid);
2358 nfsm_reqdone;
2359 if (dvp->v_type != VBAD) { /* EINVAL set on this case */
2360 VTONFS(dvp)->n_flag |= NMODIFIED;
2361 if (!wccflag)
2362 VTONFS(dvp)->n_attrstamp = 0;
2363 }
2364 /*
2365 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
2366 * if we can succeed in looking up the directory.
2367 */
2368 if (error == EEXIST || (!error && !gotvp)) {
2369 if (newvp) {
2370 vrele(newvp);
2371 newvp = (struct vnode *)0;
2372 }
2373 error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
2374 cnp->cn_proc, &np);
2375 if (!error) {
2376 newvp = NFSTOV(np);
2377 if (newvp->v_type != VDIR)
2378 error = EEXIST;
2379 }
2380 }
2381 if (error) {
2382 if (newvp)
2383 vrele(newvp);
2384 } else
2385 *ap->a_vpp = newvp;
2386 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
2387 vput(dvp);
2388 return (error);
2389 }
2390
2391 /*
2392 * nfs remove directory call
2393 */
2394 static int
2395 nfs_rmdir(ap)
2396 struct vop_rmdir_args /* {
2397 struct vnode *a_dvp;
2398 struct vnode *a_vp;
2399 struct componentname *a_cnp;
2400 } */ *ap;
2401 {
2402 register struct vnode *vp = ap->a_vp;
2403 register struct vnode *dvp = ap->a_dvp;
2404 register struct componentname *cnp = ap->a_cnp;
2405 register u_long *tl;
2406 register caddr_t cp;
2407 register long t1, t2;
2408 caddr_t bpos, dpos, cp2;
2409 int error = 0, wccflag = NFSV3_WCCRATTR;
2410 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2411 int v3 = NFS_ISV3(dvp);
2412 u_int64_t xid;
2413
2414 nfsstats.rpccnt[NFSPROC_RMDIR]++;
2415 nfsm_reqhead(dvp, NFSPROC_RMDIR,
2416 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
2417 nfsm_fhtom(dvp, v3);
2418 nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
2419 nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred, &xid);
2420 if (v3)
2421 nfsm_wcc_data(dvp, wccflag, &xid);
2422 nfsm_reqdone;
2423 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
2424 if (dvp->v_type != VBAD) { /* EINVAL set on this case */
2425 VTONFS(dvp)->n_flag |= NMODIFIED;
2426 if (!wccflag)
2427 VTONFS(dvp)->n_attrstamp = 0;
2428 }
2429 cache_purge(dvp);
2430 cache_purge(vp);
2431 vput(vp);
2432 vput(dvp);
2433 /*
2434 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2435 */
2436 if (error == ENOENT)
2437 error = 0;
2438 return (error);
2439 }
2440
2441 /*
2442 * nfs readdir call
2443 */
2444 static int
2445 nfs_readdir(ap)
2446 struct vop_readdir_args /* {
2447 struct vnode *a_vp;
2448 struct uio *a_uio;
2449 struct ucred *a_cred;
2450 } */ *ap;
2451 {
2452 register struct vnode *vp = ap->a_vp;
2453 register struct nfsnode *np = VTONFS(vp);
2454 register struct uio *uio = ap->a_uio;
2455 int tresid, error;
2456 struct vattr vattr;
2457
2458 if (vp->v_type != VDIR)
2459 return (EPERM);
2460 /*
2461 * First, check for hit on the EOF offset cache
2462 */
2463 if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset &&
2464 (np->n_flag & NMODIFIED) == 0) {
2465 if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
2466 if (NQNFS_CKCACHABLE(vp, ND_READ)) {
2467 nfsstats.direofcache_hits++;
2468 return (0);
2469 }
2470 } else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
2471 np->n_mtime == vattr.va_mtime.tv_sec) {
2472 nfsstats.direofcache_hits++;
2473 return (0);
2474 }
2475 }
2476
2477 /*
2478 * Call nfs_bioread() to do the real work.
2479 */
2480 tresid = uio->uio_resid;
2481 error = nfs_bioread(vp, uio, 0, ap->a_cred, 0);
2482
2483 if (!error && uio->uio_resid == tresid)
2484 nfsstats.direofcache_misses++;
2485 return (error);
2486 }
2487
2488 /*
2489 * Readdir rpc call.
2490 * Called from below the buffer cache by nfs_doio().
2491 */
2492 int
2493 nfs_readdirrpc(vp, uiop, cred)
2494 struct vnode *vp;
2495 register struct uio *uiop;
2496 struct ucred *cred;
2497
2498 {
2499 register int len, left;
2500 register struct dirent *dp;
2501 register u_long *tl;
2502 register caddr_t cp;
2503 register long t1, t2;
2504 register nfsuint64 *cookiep;
2505 caddr_t bpos, dpos, cp2;
2506 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2507 nfsuint64 cookie;
2508 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2509 struct nfsnode *dnp = VTONFS(vp);
2510 u_quad_t fileno;
2511 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
2512 int attrflag;
2513 int v3 = NFS_ISV3(vp);
2514 u_int64_t xid;
2515
2516 #ifndef nolint
2517 dp = (struct dirent *)0;
2518 #endif
2519 #if DIAGNOSTIC
2520 if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (NFS_DIRBLKSIZ - 1)) ||
2521 (uiop->uio_resid & (NFS_DIRBLKSIZ - 1)))
2522 panic("nfs_readdirrpc: bad uio");
2523 #endif
2524
2525 /*
2526 * If there is no cookie, assume directory was stale.
2527 */
2528 cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
2529 if (cookiep)
2530 cookie = *cookiep;
2531 else
2532 return (NFSERR_BAD_COOKIE);
2533 /*
2534 * Loop around doing readdir rpc's of size nm_readdirsize
2535 * truncated to a multiple of DIRBLKSIZ.
2536 * The stopping criteria is EOF or buffer full.
2537 */
2538 while (more_dirs && bigenough) {
2539 nfsstats.rpccnt[NFSPROC_READDIR]++;
2540 nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) +
2541 NFSX_READDIR(v3));
2542 nfsm_fhtom(vp, v3);
2543 if (v3) {
2544 nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
2545 *tl++ = cookie.nfsuquad[0];
2546 *tl++ = cookie.nfsuquad[1];
2547 *tl++ = dnp->n_cookieverf.nfsuquad[0];
2548 *tl++ = dnp->n_cookieverf.nfsuquad[1];
2549 } else {
2550 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2551 *tl++ = cookie.nfsuquad[0];
2552 }
2553 *tl = txdr_unsigned(nmp->nm_readdirsize);
2554 nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred, &xid);
2555 if (v3) {
2556 nfsm_postop_attr(vp, attrflag, &xid);
2557 if (!error) {
2558 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2559 dnp->n_cookieverf.nfsuquad[0] = *tl++;
2560 dnp->n_cookieverf.nfsuquad[1] = *tl;
2561 } else {
2562 m_freem(mrep);
2563 goto nfsmout;
2564 }
2565 }
2566 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2567 more_dirs = fxdr_unsigned(int, *tl);
2568
2569 /* loop thru the dir entries, doctoring them to 4bsd form */
2570 while (more_dirs && bigenough) {
2571 if (v3) {
2572 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2573 fxdr_hyper(tl, &fileno);
2574 len = fxdr_unsigned(int, *(tl + 2));
2575 } else {
2576 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2577 fileno = fxdr_unsigned(u_quad_t, *tl++);
2578 len = fxdr_unsigned(int, *tl);
2579 }
2580 if (len <= 0 || len > NFS_MAXNAMLEN) {
2581 error = EBADRPC;
2582 m_freem(mrep);
2583 goto nfsmout;
2584 }
2585 tlen = nfsm_rndup(len);
2586 if (tlen == len)
2587 tlen += 4; /* To ensure null termination */
2588 left = DIRBLKSIZ - blksiz;
2589 if ((tlen + DIRHDSIZ) > left) {
2590 dp->d_reclen += left;
2591 uiop->uio_iov->iov_base += left;
2592 uiop->uio_iov->iov_len -= left;
2593 uiop->uio_offset += left;
2594 uiop->uio_resid -= left;
2595 blksiz = 0;
2596 }
2597 if ((tlen + DIRHDSIZ) > uiop->uio_resid)
2598 bigenough = 0;
2599 if (bigenough) {
2600 dp = (struct dirent *)uiop->uio_iov->iov_base;
2601 dp->d_fileno = (int)fileno;
2602 dp->d_namlen = len;
2603 dp->d_reclen = tlen + DIRHDSIZ;
2604 dp->d_type = DT_UNKNOWN;
2605 blksiz += dp->d_reclen;
2606 if (blksiz == DIRBLKSIZ)
2607 blksiz = 0;
2608 uiop->uio_offset += DIRHDSIZ;
2609 uiop->uio_resid -= DIRHDSIZ;
2610 uiop->uio_iov->iov_base += DIRHDSIZ;
2611 uiop->uio_iov->iov_len -= DIRHDSIZ;
2612 nfsm_mtouio(uiop, len);
2613 cp = uiop->uio_iov->iov_base;
2614 tlen -= len;
2615 *cp = '\0'; /* null terminate */
2616 uiop->uio_iov->iov_base += tlen;
2617 uiop->uio_iov->iov_len -= tlen;
2618 uiop->uio_offset += tlen;
2619 uiop->uio_resid -= tlen;
2620 } else
2621 nfsm_adv(nfsm_rndup(len));
2622 if (v3) {
2623 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2624 } else {
2625 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2626 }
2627 if (bigenough) {
2628 cookie.nfsuquad[0] = *tl++;
2629 if (v3)
2630 cookie.nfsuquad[1] = *tl++;
2631 } else if (v3)
2632 tl += 2;
2633 else
2634 tl++;
2635 more_dirs = fxdr_unsigned(int, *tl);
2636 }
2637 /*
2638 * If at end of rpc data, get the eof boolean
2639 */
2640 if (!more_dirs) {
2641 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2642 more_dirs = (fxdr_unsigned(int, *tl) == 0);
2643 }
2644 m_freem(mrep);
2645 }
2646 /*
2647 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
2648 * by increasing d_reclen for the last record.
2649 */
2650 if (blksiz > 0) {
2651 left = DIRBLKSIZ - blksiz;
2652 dp->d_reclen += left;
2653 uiop->uio_iov->iov_base += left;
2654 uiop->uio_iov->iov_len -= left;
2655 uiop->uio_offset += left;
2656 uiop->uio_resid -= left;
2657 }
2658
2659 /*
2660 * We are now either at the end of the directory or have filled the
2661 * block.
2662 */
2663 if (bigenough)
2664 dnp->n_direofoffset = uiop->uio_offset;
2665 else {
2666 if (uiop->uio_resid > 0)
2667 printf("EEK! readdirrpc resid > 0\n");
2668 cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
2669 *cookiep = cookie;
2670 }
2671 nfsmout:
2672 return (error);
2673 }
2674
2675 /*
2676 * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
2677 */
2678 int
2679 nfs_readdirplusrpc(vp, uiop, cred)
2680 struct vnode *vp;
2681 register struct uio *uiop;
2682 struct ucred *cred;
2683 {
2684 register int len, left;
2685 register struct dirent *dp;
2686 register u_long *tl;
2687 register caddr_t cp;
2688 register long t1, t2;
2689 register struct vnode *newvp;
2690 register nfsuint64 *cookiep;
2691 caddr_t bpos, dpos, cp2, dpossav1, dpossav2;
2692 struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2;
2693 struct nameidata nami, *ndp = &nami;
2694 struct componentname *cnp = &ndp->ni_cnd;
2695 nfsuint64 cookie;
2696 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2697 struct nfsnode *dnp = VTONFS(vp), *np;
2698 nfsfh_t *fhp;
2699 u_quad_t fileno;
2700 int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
2701 int attrflag, fhsize;
2702 u_int64_t xid, savexid;
2703
2704 #ifndef nolint
2705 dp = (struct dirent *)0;
2706 #endif
2707 #if DIAGNOSTIC
2708 if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) ||
2709 (uiop->uio_resid & (DIRBLKSIZ - 1)))
2710 panic("nfs_readdirplusrpc: bad uio");
2711 #endif
2712 ndp->ni_dvp = vp;
2713 newvp = NULLVP;
2714
2715 /*
2716 * If there is no cookie, assume directory was stale.
2717 */
2718 cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
2719 if (cookiep)
2720 cookie = *cookiep;
2721 else
2722 return (NFSERR_BAD_COOKIE);
2723 /*
2724 * Loop around doing readdir rpc's of size nm_readdirsize
2725 * truncated to a multiple of DIRBLKSIZ.
2726 * The stopping criteria is EOF or buffer full.
2727 */
2728 while (more_dirs && bigenough) {
2729 nfsstats.rpccnt[NFSPROC_READDIRPLUS]++;
2730 nfsm_reqhead(vp, NFSPROC_READDIRPLUS,
2731 NFSX_FH(1) + 6 * NFSX_UNSIGNED);
2732 nfsm_fhtom(vp, 1);
2733 nfsm_build(tl, u_long *, 6 * NFSX_UNSIGNED);
2734 *tl++ = cookie.nfsuquad[0];
2735 *tl++ = cookie.nfsuquad[1];
2736 *tl++ = dnp->n_cookieverf.nfsuquad[0];
2737 *tl++ = dnp->n_cookieverf.nfsuquad[1];
2738 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
2739 *tl = txdr_unsigned(nmp->nm_rsize);
2740 nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred,
2741 &xid);
2742 savexid = xid;
2743 nfsm_postop_attr(vp, attrflag, &xid);
2744 if (error) {
2745 m_freem(mrep);
2746 goto nfsmout;
2747 }
2748 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2749 dnp->n_cookieverf.nfsuquad[0] = *tl++;
2750 dnp->n_cookieverf.nfsuquad[1] = *tl++;
2751 more_dirs = fxdr_unsigned(int, *tl);
2752
2753 /* loop thru the dir entries, doctoring them to 4bsd form */
2754 while (more_dirs && bigenough) {
2755 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2756 fxdr_hyper(tl, &fileno);
2757 len = fxdr_unsigned(int, *(tl + 2));
2758 if (len <= 0 || len > NFS_MAXNAMLEN) {
2759 error = EBADRPC;
2760 m_freem(mrep);
2761 goto nfsmout;
2762 }
2763 tlen = nfsm_rndup(len);
2764 if (tlen == len)
2765 tlen += 4; /* To ensure null termination*/
2766 left = DIRBLKSIZ - blksiz;
2767 if ((tlen + DIRHDSIZ) > left) {
2768 dp->d_reclen += left;
2769 uiop->uio_iov->iov_base += left;
2770 uiop->uio_iov->iov_len -= left;
2771 uiop->uio_offset += left;
2772 uiop->uio_resid -= left;
2773 blksiz = 0;
2774 }
2775 if ((tlen + DIRHDSIZ) > uiop->uio_resid)
2776 bigenough = 0;
2777 if (bigenough) {
2778 dp = (struct dirent *)uiop->uio_iov->iov_base;
2779 dp->d_fileno = (int)fileno;
2780 dp->d_namlen = len;
2781 dp->d_reclen = tlen + DIRHDSIZ;
2782 dp->d_type = DT_UNKNOWN;
2783 blksiz += dp->d_reclen;
2784 if (blksiz == DIRBLKSIZ)
2785 blksiz = 0;
2786 uiop->uio_offset += DIRHDSIZ;
2787 uiop->uio_resid -= DIRHDSIZ;
2788 uiop->uio_iov->iov_base += DIRHDSIZ;
2789 uiop->uio_iov->iov_len -= DIRHDSIZ;
2790 cnp->cn_nameptr = uiop->uio_iov->iov_base;
2791 cnp->cn_namelen = len;
2792 nfsm_mtouio(uiop, len);
2793 cp = uiop->uio_iov->iov_base;
2794 tlen -= len;
2795 *cp = '\0';
2796 uiop->uio_iov->iov_base += tlen;
2797 uiop->uio_iov->iov_len -= tlen;
2798 uiop->uio_offset += tlen;
2799 uiop->uio_resid -= tlen;
2800 } else
2801 nfsm_adv(nfsm_rndup(len));
2802 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2803 if (bigenough) {
2804 cookie.nfsuquad[0] = *tl++;
2805 cookie.nfsuquad[1] = *tl++;
2806 } else
2807 tl += 2;
2808
2809 /*
2810 * Since the attributes are before the file handle
2811 * (sigh), we must skip over the attributes and then
2812 * come back and get them.
2813 */
2814 attrflag = fxdr_unsigned(int, *tl);
2815 if (attrflag) {
2816 dpossav1 = dpos;
2817 mdsav1 = md;
2818 nfsm_adv(NFSX_V3FATTR);
2819 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2820 doit = fxdr_unsigned(int, *tl);
2821 if (doit) {
2822 nfsm_getfh(fhp, fhsize, 1);
2823 if (NFS_CMPFH(dnp, fhp, fhsize)) {
2824 VREF(vp);
2825 newvp = vp;
2826 np = dnp;
2827 } else {
2828 if ((error = nfs_nget(vp->v_mount, fhp,
2829 fhsize, &np)))
2830 doit = 0;
2831 else
2832 newvp = NFSTOV(np);
2833 }
2834 }
2835 if (doit) {
2836 dpossav2 = dpos;
2837 dpos = dpossav1;
2838 mdsav2 = md;
2839 md = mdsav1;
2840 xid = savexid;
2841 nfsm_loadattr(newvp, (struct vattr *)0, &xid);
2842 dpos = dpossav2;
2843 md = mdsav2;
2844 dp->d_type =
2845 IFTODT(VTTOIF(np->n_vattr.va_type));
2846 ndp->ni_vp = newvp;
2847 cnp->cn_hash = 0;
2848 for (cp = cnp->cn_nameptr, i = 1; i <= len;
2849 i++, cp++)
2850 cnp->cn_hash += (unsigned char)*cp * i;
2851 if (cnp->cn_namelen <= NCHNAMLEN)
2852 cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
2853 }
2854 } else {
2855 /* Just skip over the file handle */
2856 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2857 i = fxdr_unsigned(int, *tl);
2858 nfsm_adv(nfsm_rndup(i));
2859 }
2860 if (newvp != NULLVP) {
2861 vrele(newvp);
2862 newvp = NULLVP;
2863 }
2864 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2865 more_dirs = fxdr_unsigned(int, *tl);
2866 }
2867 /*
2868 * If at end of rpc data, get the eof boolean
2869 */
2870 if (!more_dirs) {
2871 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2872 more_dirs = (fxdr_unsigned(int, *tl) == 0);
2873 }
2874 m_freem(mrep);
2875 }
2876 /*
2877 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
2878 * by increasing d_reclen for the last record.
2879 */
2880 if (blksiz > 0) {
2881 left = DIRBLKSIZ - blksiz;
2882 dp->d_reclen += left;
2883 uiop->uio_iov->iov_base += left;
2884 uiop->uio_iov->iov_len -= left;
2885 uiop->uio_offset += left;
2886 uiop->uio_resid -= left;
2887 }
2888
2889 /*
2890 * We are now either at the end of the directory or have filled the
2891 * block.
2892 */
2893 if (bigenough)
2894 dnp->n_direofoffset = uiop->uio_offset;
2895 else {
2896 if (uiop->uio_resid > 0)
2897 printf("EEK! readdirplusrpc resid > 0\n");
2898 cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
2899 *cookiep = cookie;
2900 }
2901 nfsmout:
2902 if (newvp != NULLVP) {
2903 if (newvp == vp)
2904 vrele(newvp);
2905 else
2906 vput(newvp);
2907 newvp = NULLVP;
2908 }
2909 return (error);
2910 }
2911
2912 /*
2913 * Silly rename. To make the NFS filesystem that is stateless look a little
2914 * more like the "ufs" a remove of an active vnode is translated to a rename
2915 * to a funny looking filename that is removed by nfs_inactive on the
2916 * nfsnode. There is the potential for another process on a different client
2917 * to create the same funny name between the nfs_lookitup() fails and the
2918 * nfs_rename() completes, but...
2919 */
2920 static int
2921 nfs_sillyrename(dvp, vp, cnp)
2922 struct vnode *dvp, *vp;
2923 struct componentname *cnp;
2924 {
2925 register struct sillyrename *sp;
2926 struct nfsnode *np;
2927 int error;
2928 short pid;
2929 struct ucred *cred;
2930
2931 cache_purge(dvp);
2932 np = VTONFS(vp);
2933 #if DIAGNOSTIC
2934 if (vp->v_type == VDIR)
2935 panic("nfs_sillyrename: dir");
2936 #endif
2937 MALLOC_ZONE(sp, struct sillyrename *,
2938 sizeof (struct sillyrename), M_NFSREQ, M_WAITOK);
2939 sp->s_cred = crdup(cnp->cn_cred);
2940 sp->s_dvp = dvp;
2941 VREF(dvp);
2942
2943 /* Fudge together a funny name */
2944 pid = cnp->cn_proc->p_pid;
2945 sp->s_namlen = sprintf(sp->s_name, ".nfsA%04x4.4", pid);
2946
2947 /* Try lookitups until we get one that isn't there */
2948 while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
2949 cnp->cn_proc, (struct nfsnode **)0) == 0) {
2950 sp->s_name[4]++;
2951 if (sp->s_name[4] > 'z') {
2952 error = EINVAL;
2953 goto bad;
2954 }
2955 }
2956 if ((error = nfs_renameit(dvp, cnp, sp)))
2957 goto bad;
2958 error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
2959 cnp->cn_proc, &np);
2960 #if DIAGNOSTIC
2961 kprintf("sillyrename: %s, vp=%x, np=%x, dvp=%x\n",
2962 &sp->s_name[0], (unsigned)vp, (unsigned)np, (unsigned)dvp);
2963 #endif
2964 np->n_sillyrename = sp;
2965 return (0);
2966 bad:
2967 vrele(sp->s_dvp);
2968 cred = sp->s_cred;
2969 sp->s_cred = NOCRED;
2970 crfree(cred);
2971 _FREE_ZONE((caddr_t)sp, sizeof (struct sillyrename), M_NFSREQ);
2972 return (error);
2973 }
2974
2975 /*
2976 * Look up a file name and optionally either update the file handle or
2977 * allocate an nfsnode, depending on the value of npp.
2978 * npp == NULL --> just do the lookup
2979 * *npp == NULL --> allocate a new nfsnode and make sure attributes are
2980 * handled too
2981 * *npp != NULL --> update the file handle in the vnode
2982 */
2983 static int
2984 nfs_lookitup(dvp, name, len, cred, procp, npp)
2985 register struct vnode *dvp;
2986 char *name;
2987 int len;
2988 struct ucred *cred;
2989 struct proc *procp;
2990 struct nfsnode **npp;
2991 {
2992 register u_long *tl;
2993 register caddr_t cp;
2994 register long t1, t2;
2995 struct vnode *newvp = (struct vnode *)0;
2996 struct nfsnode *np, *dnp = VTONFS(dvp);
2997 caddr_t bpos, dpos, cp2;
2998 int error = 0, fhlen, attrflag;
2999 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
3000 nfsfh_t *nfhp;
3001 int v3 = NFS_ISV3(dvp);
3002 u_int64_t xid;
3003
3004 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
3005 nfsm_reqhead(dvp, NFSPROC_LOOKUP,
3006 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
3007 nfsm_fhtom(dvp, v3);
3008 nfsm_strtom(name, len, NFS_MAXNAMLEN);
3009 nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred, &xid);
3010 if (npp && !error) {
3011 nfsm_getfh(nfhp, fhlen, v3);
3012 if (*npp) {
3013 np = *npp;
3014 if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
3015 _FREE_ZONE((caddr_t)np->n_fhp,
3016 np->n_fhsize, M_NFSBIGFH);
3017 np->n_fhp = &np->n_fh;
3018 } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH)
3019 MALLOC_ZONE(np->n_fhp, nfsfh_t *,
3020 fhlen, M_NFSBIGFH, M_WAITOK);
3021 bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen);
3022 np->n_fhsize = fhlen;
3023 newvp = NFSTOV(np);
3024 } else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
3025 VREF(dvp);
3026 newvp = dvp;
3027 } else {
3028 error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
3029 if (error) {
3030 m_freem(mrep);
3031 return (error);
3032 }
3033 newvp = NFSTOV(np);
3034 }
3035 if (v3) {
3036 nfsm_postop_attr(newvp, attrflag, &xid);
3037 if (!attrflag && *npp == NULL) {
3038 m_freem(mrep);
3039 if (newvp == dvp)
3040 vrele(newvp);
3041 else
3042 vput(newvp);
3043 return (ENOENT);
3044 }
3045 } else
3046 nfsm_loadattr(newvp, (struct vattr *)0, &xid);
3047 }
3048 nfsm_reqdone;
3049 if (npp && *npp == NULL) {
3050 if (error) {
3051 if (newvp)
3052 if (newvp == dvp)
3053 vrele(newvp);
3054 else
3055 vput(newvp);
3056 } else
3057 *npp = np;
3058 }
3059 return (error);
3060 }
3061
3062 /*
3063 * Nfs Version 3 commit rpc
3064 */
3065 static int
3066 nfs_commit(vp, offset, cnt, cred, procp)
3067 register struct vnode *vp;
3068 u_quad_t offset;
3069 int cnt;
3070 struct ucred *cred;
3071 struct proc *procp;
3072 {
3073 register caddr_t cp;
3074 register u_long *tl;
3075 register int t1, t2;
3076 register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
3077 caddr_t bpos, dpos, cp2;
3078 int error = 0, wccflag = NFSV3_WCCRATTR;
3079 struct mbuf *mreq, *mrep, *md, *mb, *mb2;
3080 u_int64_t xid;
3081
3082 FSDBG(521, vp, offset, cnt, nmp->nm_flag);
3083 if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0)
3084 return (0);
3085 nfsstats.rpccnt[NFSPROC_COMMIT]++;
3086 nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1));
3087 nfsm_fhtom(vp, 1);
3088 nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
3089 txdr_hyper(&offset, tl);
3090 tl += 2;
3091 *tl = txdr_unsigned(cnt);
3092 nfsm_request(vp, NFSPROC_COMMIT, procp, cred, &xid);
3093 nfsm_wcc_data(vp, wccflag, &xid);
3094 if (!error) {
3095 nfsm_dissect(tl, u_long *, NFSX_V3WRITEVERF);
3096 if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl,
3097 NFSX_V3WRITEVERF)) {
3098 bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
3099 NFSX_V3WRITEVERF);
3100 error = NFSERR_STALEWRITEVERF;
3101 }
3102 }
3103 nfsm_reqdone;
3104 return (error);
3105 }
3106
3107 /*
3108 * Kludge City..
3109 * - make nfs_bmap() essentially a no-op that does no translation
3110 * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc
3111 * (Maybe I could use the process's page mapping, but I was concerned that
3112 * Kernel Write might not be enabled and also figured copyout() would do
3113 * a lot more work than bcopy() and also it currently happens in the
3114 * context of the swapper process (2).
3115 */
3116 static int
3117 nfs_bmap(ap)
3118 struct vop_bmap_args /* {
3119 struct vnode *a_vp;
3120 daddr_t a_bn;
3121 struct vnode **a_vpp;
3122 daddr_t *a_bnp;
3123 int *a_runp;
3124 int *a_runb;
3125 } */ *ap;
3126 {
3127 register struct vnode *vp = ap->a_vp;
3128 int devBlockSize = DEV_BSIZE;
3129
3130 if (ap->a_vpp != NULL)
3131 *ap->a_vpp = vp;
3132 if (ap->a_bnp != NULL)
3133 *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize,
3134 devBlockSize);
3135 if (ap->a_runp != NULL)
3136 *ap->a_runp = 0;
3137 #ifdef notyet
3138 if (ap->a_runb != NULL)
3139 *ap->a_runb = 0;
3140 #endif
3141 return (0);
3142 }
3143
3144 /*
3145 * Strategy routine.
3146 * For async requests when nfsiod(s) are running, queue the request by
3147 * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
3148 * request.
3149 */
3150 static int
3151 nfs_strategy(ap)
3152 struct vop_strategy_args *ap;
3153 {
3154 register struct buf *bp = ap->a_bp;
3155 struct ucred *cr;
3156 struct proc *p;
3157 int error = 0;
3158
3159 if (ISSET(bp->b_flags, B_PHYS))
3160 panic("nfs_strategy: physio");
3161 if (ISSET(bp->b_flags, B_ASYNC))
3162 p = (struct proc *)0;
3163 else
3164 p = current_proc(); /* XXX */
3165 if (ISSET(bp->b_flags, B_READ))
3166 cr = bp->b_rcred;
3167 else
3168 cr = bp->b_wcred;
3169 /*
3170 * If the op is asynchronous and an i/o daemon is waiting
3171 * queue the request, wake it up and wait for completion
3172 * otherwise just do it ourselves.
3173 */
3174 if (!ISSET(bp->b_flags, B_ASYNC) || nfs_asyncio(bp, NOCRED))
3175 error = nfs_doio(bp, cr, p);
3176 return (error);
3177 }
3178
3179 /*
3180 * Mmap a file
3181 *
3182 * NB Currently unsupported.
3183 */
3184 /* ARGSUSED */
3185 static int
3186 nfs_mmap(ap)
3187 struct vop_mmap_args /* {
3188 struct vnode *a_vp;
3189 int a_fflags;
3190 struct ucred *a_cred;
3191 struct proc *a_p;
3192 } */ *ap;
3193 {
3194
3195 return (EINVAL);
3196 }
3197
3198 /*
3199 * fsync vnode op. Just call nfs_flush() with commit == 1.
3200 */
3201 /* ARGSUSED */
3202 static int
3203 nfs_fsync(ap)
3204 struct vop_fsync_args /* {
3205 struct vnodeop_desc *a_desc;
3206 struct vnode * a_vp;
3207 struct ucred * a_cred;
3208 int a_waitfor;
3209 struct proc * a_p;
3210 } */ *ap;
3211 {
3212 return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));
3213 }
3214
3215 /*
3216 * Flush all the blocks associated with a vnode.
3217 * Walk through the buffer pool and push any dirty pages
3218 * associated with the vnode.
3219 */
3220 static int
3221 nfs_flush(vp, cred, waitfor, p, commit)
3222 register struct vnode *vp;
3223 struct ucred *cred;
3224 int waitfor;
3225 struct proc *p;
3226 int commit;
3227 {
3228 register struct nfsnode *np = VTONFS(vp);
3229 register struct buf *bp;
3230 register int i;
3231 struct buf *nbp;
3232 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
3233 int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos, err;
3234 int passone = 1;
3235 u_quad_t off, endoff, toff;
3236 struct ucred* wcred = NULL;
3237 struct buf **bvec = NULL;
3238 #ifndef NFS_COMMITBVECSIZ
3239 #define NFS_COMMITBVECSIZ 20
3240 #endif
3241 struct buf *bvec_on_stack[NFS_COMMITBVECSIZ];
3242 int bvecsize = 0, bveccount;
3243 kern_return_t kret;
3244 upl_t upl;
3245
3246 FSDBG_TOP(517, vp, np, waitfor, commit);
3247
3248 if (nmp->nm_flag & NFSMNT_INT)
3249 slpflag = PCATCH;
3250 if (!commit)
3251 passone = 0;
3252
3253 /*
3254 * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the
3255 * server, but nas not been committed to stable storage on the server
3256 * yet. On the first pass, the byte range is worked out and the commit
3257 * rpc is done. On the second pass, nfs_writebp() is called to do the
3258 * job.
3259 */
3260 again:
3261 FSDBG(518, vp->v_dirtyblkhd.lh_first, np->n_flag, 0, 0);
3262 if (vp->v_dirtyblkhd.lh_first)
3263 np->n_flag |= NMODIFIED;
3264 off = (u_quad_t)-1;
3265 endoff = 0;
3266 bvecpos = 0;
3267 if (NFS_ISV3(vp) && commit) {
3268 s = splbio();
3269 /*
3270 * Count up how many buffers waiting for a commit.
3271 * This is an upper bound - any with dirty pages must be
3272 * written not commited.
3273 */
3274 bveccount = 0;
3275 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
3276 nbp = bp->b_vnbufs.le_next;
3277 if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
3278 == (B_DELWRI | B_NEEDCOMMIT))
3279 bveccount++;
3280 FSDBG(519, bp, bp->b_flags, bveccount, 0);
3281 }
3282 /*
3283 * Allocate space to remember the list of bufs to commit. It is
3284 * important to use M_NOWAIT here to avoid a race with nfs_write
3285 * If we can't get memory (for whatever reason), we will end up
3286 * committing the buffers one-by-one in the loop below.
3287 */
3288 if (bvec != NULL && bvec != bvec_on_stack)
3289 _FREE(bvec, M_TEMP);
3290 if (bveccount > NFS_COMMITBVECSIZ) {
3291 MALLOC(bvec, struct buf **,
3292 bveccount * sizeof(struct buf *), M_TEMP,
3293 M_NOWAIT);
3294 if (bvec == NULL) {
3295 bvec = bvec_on_stack;
3296 bvecsize = NFS_COMMITBVECSIZ;
3297 } else
3298 bvecsize = bveccount;
3299 } else {
3300 bvec = bvec_on_stack;
3301 bvecsize = NFS_COMMITBVECSIZ;
3302 }
3303 FSDBG(519, 0, bvecsize, bveccount, 0);
3304
3305 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
3306 nbp = bp->b_vnbufs.le_next;
3307 /* XXX nbp aok if we sleep in this loop? */
3308 FSDBG(520, bp, bp->b_flags, bvecpos, bp->b_bufsize);
3309 FSDBG(520, bp->b_validoff, bp->b_validend,
3310 bp->b_dirtyoff, bp->b_dirtyend);
3311 if (bvecpos >= bvecsize)
3312 break;
3313 if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
3314 != (B_DELWRI | B_NEEDCOMMIT))
3315 continue;
3316 SET(bp->b_flags, B_BUSY);
3317 /*
3318 * we need a upl to see if the page has been
3319 * dirtied (think mmap) since the unstable write, and
3320 * so to prevent vm from paging during our commit rpc
3321 */
3322 if (ISSET(bp->b_flags, B_PAGELIST)) {
3323 upl = bp->b_pagelist;
3324 } else {
3325 kret = ubc_create_upl(vp, ubc_blktooff(vp, bp->b_lblkno),
3326 bp->b_bufsize, &upl,
3327 NULL, UPL_PRECIOUS);
3328 if (kret != KERN_SUCCESS)
3329 panic("nfs_flush: create upl %d", kret);
3330 #ifdef UBC_DEBUG
3331 upl_ubc_alias_set(upl, current_act(), 1);
3332 #endif /* UBC_DEBUG */
3333 }
3334 if (upl_dirty_page(ubc_upl_pageinfo(upl), 0)) {
3335 if (!ISSET(bp->b_flags, B_PAGELIST)) {
3336 err = ubc_upl_abort(upl, NULL);
3337 if (err)
3338 printf("nfs_flush: upl abort %d\n", err);
3339 }
3340 /*
3341 * Any/all of it may be modified...
3342 */
3343 bp->b_dirtyoff = bp->b_validoff;
3344 bp->b_dirtyend = bp->b_validend;
3345 CLR(bp->b_flags, B_BUSY | B_NEEDCOMMIT);
3346 continue;
3347 }
3348 if (!ISSET(bp->b_flags, B_PAGELIST)) {
3349 bp->b_pagelist = upl;
3350 SET(bp->b_flags, B_PAGELIST);
3351 ubc_upl_map(upl, (vm_address_t *)&bp->b_data);
3352 }
3353 bremfree(bp);
3354 /*
3355 * Work out if all buffers are using the same cred
3356 * so we can deal with them all with one commit.
3357 */
3358 if (wcred == NULL)
3359 wcred = bp->b_wcred;
3360 else if (wcred != bp->b_wcred)
3361 wcred = NOCRED;
3362 SET(bp->b_flags, B_WRITEINPROG);
3363
3364 /*
3365 * A list of these buffers is kept so that the
3366 * second loop knows which buffers have actually
3367 * been committed. This is necessary, since there
3368 * may be a race between the commit rpc and new
3369 * uncommitted writes on the file.
3370 */
3371 bvec[bvecpos++] = bp;
3372 toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
3373 bp->b_dirtyoff;
3374 if (toff < off)
3375 off = toff;
3376 toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff);
3377 if (toff > endoff)
3378 endoff = toff;
3379 }
3380 splx(s);
3381 }
3382 if (bvecpos > 0) {
3383 /*
3384 * Commit data on the server, as required.
3385 * If all bufs are using the same wcred, then use that with
3386 * one call for all of them, otherwise commit each one
3387 * separately.
3388 */
3389 if (wcred != NOCRED)
3390 retv = nfs_commit(vp, off, (int)(endoff - off),
3391 wcred, p);
3392 else {
3393 retv = 0;
3394 for (i = 0; i < bvecpos; i++) {
3395 off_t off, size;
3396 bp = bvec[i];
3397 FSDBG(522, bp, bp->b_blkno * DEV_BSIZE,
3398 bp->b_dirtyoff, bp->b_dirtyend);
3399 off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
3400 bp->b_dirtyoff;
3401 size = (u_quad_t)(bp->b_dirtyend
3402 - bp->b_dirtyoff);
3403 retv = nfs_commit(vp, off, (int)size,
3404 bp->b_wcred, p);
3405 if (retv) break;
3406 }
3407 }
3408
3409 if (retv == NFSERR_STALEWRITEVERF)
3410 nfs_clearcommit(vp->v_mount);
3411
3412 /*
3413 * Now, either mark the blocks I/O done or mark the
3414 * blocks dirty, depending on whether the commit
3415 * succeeded.
3416 */
3417 for (i = 0; i < bvecpos; i++) {
3418 bp = bvec[i];
3419 FSDBG(523, bp, retv, bp->b_flags, 0);
3420 CLR(bp->b_flags, (B_NEEDCOMMIT | B_WRITEINPROG));
3421 if (retv) {
3422 brelse(bp);
3423 } else {
3424 s = splbio();
3425 vp->v_numoutput++;
3426 SET(bp->b_flags, B_ASYNC);
3427 CLR(bp->b_flags,
3428 (B_READ|B_DONE|B_ERROR|B_DELWRI));
3429 bp->b_dirtyoff = bp->b_dirtyend = 0;
3430 reassignbuf(bp, vp);
3431 splx(s);
3432 biodone(bp);
3433 }
3434 }
3435
3436 }
3437 /*
3438 * Start/do any write(s) that are required. There is a window here
3439 * where B_BUSY protects the buffer. The vm pages have been freed up,
3440 * yet B_BUSY is set. Don't think you will hit any busy/incore problems
3441 * while we sleep, but not absolutely sure. Keep an eye on it. Otherwise
3442 * we will have to hold vm page across this locked. - EKN
3443 */
3444 loop:
3445 if (current_thread_aborted()) {
3446 error = EINTR;
3447 goto done;
3448 }
3449 s = splbio();
3450 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
3451 nbp = bp->b_vnbufs.le_next;
3452 if (ISSET(bp->b_flags, B_BUSY)) {
3453 FSDBG(524, bp, waitfor, passone, bp->b_flags);
3454 if (waitfor != MNT_WAIT || passone)
3455 continue;
3456 SET(bp->b_flags, B_WANTED);
3457 error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
3458 "nfsfsync", slptimeo);
3459 splx(s);
3460 if (error) {
3461 if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) {
3462 error = EINTR;
3463 goto done;
3464 }
3465 if (slpflag == PCATCH) {
3466 slpflag = 0;
3467 slptimeo = 2 * hz;
3468 }
3469 }
3470 goto loop;
3471 }
3472 if (!ISSET(bp->b_flags, B_DELWRI))
3473 panic("nfs_fsync: not dirty");
3474 FSDBG(525, bp, passone, commit, bp->b_flags);
3475 if ((passone || !commit) && ISSET(bp->b_flags, B_NEEDCOMMIT))
3476 continue;
3477 bremfree(bp);
3478 if (passone || !commit)
3479 SET(bp->b_flags, B_BUSY|B_ASYNC);
3480 else
3481 SET(bp->b_flags,
3482 B_BUSY|B_ASYNC|B_WRITEINPROG|B_NEEDCOMMIT);
3483 splx(s);
3484 VOP_BWRITE(bp);
3485 goto loop;
3486 }
3487 splx(s);
3488 if (passone) {
3489 passone = 0;
3490 goto again;
3491 }
3492 if (waitfor == MNT_WAIT) {
3493 while (vp->v_numoutput) {
3494 vp->v_flag |= VBWAIT;
3495 error = tsleep((caddr_t)&vp->v_numoutput,
3496 slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
3497 if (error) {
3498 if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) {
3499 error = EINTR;
3500 goto done;
3501 }
3502 if (slpflag == PCATCH) {
3503 slpflag = 0;
3504 slptimeo = 2 * hz;
3505 }
3506 }
3507 }
3508 if (vp->v_dirtyblkhd.lh_first && commit) {
3509 goto loop;
3510 }
3511 }
3512 FSDBG(526, np->n_flag, np->n_error, 0, 0);
3513 if (np->n_flag & NWRITEERR) {
3514 error = np->n_error;
3515 np->n_flag &= ~NWRITEERR;
3516 }
3517 done:
3518 FSDBG_BOT(517, vp, np, error, 0);
3519 if (bvec != NULL && bvec != bvec_on_stack)
3520 _FREE(bvec, M_TEMP);
3521 return (error);
3522 }
3523
3524 /*
3525 * Return POSIX pathconf information applicable to nfs.
3526 *
3527 * The NFS V2 protocol doesn't support this, so just return EINVAL
3528 * for V2.
3529 */
3530 /* ARGSUSED */
3531 static int
3532 nfs_pathconf(ap)
3533 struct vop_pathconf_args /* {
3534 struct vnode *a_vp;
3535 int a_name;
3536 int *a_retval;
3537 } */ *ap;
3538 {
3539
3540 return (EINVAL);
3541 }
3542
3543 /*
3544 * NFS advisory byte-level locks.
3545 * Currently unsupported.
3546 */
3547 static int
3548 nfs_advlock(ap)
3549 struct vop_advlock_args /* {
3550 struct vnode *a_vp;
3551 caddr_t a_id;
3552 int a_op;
3553 struct flock *a_fl;
3554 int a_flags;
3555 } */ *ap;
3556 {
3557 #ifdef __FreeBSD__
3558 register struct nfsnode *np = VTONFS(ap->a_vp);
3559
3560 /*
3561 * The following kludge is to allow diskless support to work
3562 * until a real NFS lockd is implemented. Basically, just pretend
3563 * that this is a local lock.
3564 */
3565 return (lf_advlock(ap, &(np->n_lockf), np->n_size));
3566 #else
3567 #if DIAGNOSTIC
3568 printf("nfs_advlock: pid %d comm %s\n", current_proc()->p_pid, current_proc()->p_comm);
3569 #endif
3570 return (EOPNOTSUPP);
3571 #endif
3572 }
3573
3574 /*
3575 * Print out the contents of an nfsnode.
3576 */
3577 static int
3578 nfs_print(ap)
3579 struct vop_print_args /* {
3580 struct vnode *a_vp;
3581 } */ *ap;
3582 {
3583 register struct vnode *vp = ap->a_vp;
3584 register struct nfsnode *np = VTONFS(vp);
3585
3586 printf("tag VT_NFS, fileid %ld fsid 0x%lx",
3587 np->n_vattr.va_fileid, np->n_vattr.va_fsid);
3588 if (vp->v_type == VFIFO)
3589 fifo_printinfo(vp);
3590 printf("\n");
3591 return (0);
3592 }
3593
3594 /*
3595 * NFS directory offset lookup.
3596 * Currently unsupported.
3597 */
3598 static int
3599 nfs_blkatoff(ap)
3600 struct vop_blkatoff_args /* {
3601 struct vnode *a_vp;
3602 off_t a_offset;
3603 char **a_res;
3604 struct buf **a_bpp;
3605 } */ *ap;
3606 {
3607
3608 #if DIAGNOSTIC
3609 printf("nfs_blkatoff: unimplemented!!");
3610 #endif
3611 return (EOPNOTSUPP);
3612 }
3613
3614 /*
3615 * NFS flat namespace allocation.
3616 * Currently unsupported.
3617 */
3618 static int
3619 nfs_valloc(ap)
3620 struct vop_valloc_args /* {
3621 struct vnode *a_pvp;
3622 int a_mode;
3623 struct ucred *a_cred;
3624 struct vnode **a_vpp;
3625 } */ *ap;
3626 {
3627
3628 return (EOPNOTSUPP);
3629 }
3630
3631 /*
3632 * NFS flat namespace free.
3633 * Currently unsupported.
3634 */
3635 static int
3636 nfs_vfree(ap)
3637 struct vop_vfree_args /* {
3638 struct vnode *a_pvp;
3639 ino_t a_ino;
3640 int a_mode;
3641 } */ *ap;
3642 {
3643
3644 #if DIAGNOSTIC
3645 printf("nfs_vfree: unimplemented!!");
3646 #endif
3647 return (EOPNOTSUPP);
3648 }
3649
3650 /*
3651 * NFS file truncation.
3652 */
3653 static int
3654 nfs_truncate(ap)
3655 struct vop_truncate_args /* {
3656 struct vnode *a_vp;
3657 off_t a_length;
3658 int a_flags;
3659 struct ucred *a_cred;
3660 struct proc *a_p;
3661 } */ *ap;
3662 {
3663
3664 /* Use nfs_setattr */
3665 #if DIAGNOSTIC
3666 printf("nfs_truncate: unimplemented!!");
3667 #endif
3668 return (EOPNOTSUPP);
3669 }
3670
3671 /*
3672 * NFS update.
3673 */
3674 static int
3675 nfs_update(ap)
3676 struct vop_update_args /* {
3677 struct vnode *a_vp;
3678 struct timeval *a_ta;
3679 struct timeval *a_tm;
3680 int a_waitfor;
3681 } */ *ap;
3682 {
3683
3684 /* Use nfs_setattr */
3685 #if DIAGNOSTIC
3686 printf("nfs_update: unimplemented!!");
3687 #endif
3688 return (EOPNOTSUPP);
3689 }
3690
3691 int nfs_aio_threads = 0; /* 1 per nfd (arbitrary) */
3692 struct slock nfs_aio_slock;
3693 TAILQ_HEAD(bqueues, buf) nfs_aio_bufq;
3694 int nfs_aio_bufq_len = 0; /* diagnostic only */
3695
3696 void
3697 nfs_aio_thread()
3698 { /* see comment below in nfs_bwrite() for some rationale */
3699 struct buf *bp;
3700 boolean_t funnel_state;
3701
3702 funnel_state = thread_funnel_set(kernel_flock, TRUE);
3703 for(;;) {
3704 simple_lock(&nfs_aio_slock);
3705 if ((bp = nfs_aio_bufq.tqh_first)) {
3706 TAILQ_REMOVE(&nfs_aio_bufq, bp, b_freelist);
3707 nfs_aio_bufq_len--;
3708 simple_unlock(&nfs_aio_slock);
3709 nfs_writebp(bp, 1);
3710 } else { /* nothing to do - goodnight */
3711 assert_wait(&nfs_aio_bufq, THREAD_UNINT);
3712 simple_unlock(&nfs_aio_slock);
3713 (void)tsleep((caddr_t)0, PRIBIO+1, "nfs_aio_bufq", 0);
3714 }
3715 }
3716 (void) thread_funnel_set(kernel_flock, FALSE);
3717 }
3718
3719
3720 void
3721 nfs_aio_thread_init()
3722 {
3723 if (nfs_aio_threads++ == 0) {
3724 simple_lock_init(&nfs_aio_slock);
3725 TAILQ_INIT(&nfs_aio_bufq);
3726 }
3727 kernel_thread(kernel_task, nfs_aio_thread);
3728 }
3729
3730
3731 /*
3732 * Just call nfs_writebp() with the force argument set to 1.
3733 */
3734 static int
3735 nfs_bwrite(ap)
3736 struct vop_bwrite_args /* {
3737 struct vnode *a_bp;
3738 } */ *ap;
3739 {
3740 extern void wakeup_one(caddr_t chan);
3741
3742 /*
3743 * nfs_writebp will issue a synchronous rpc to if B_ASYNC then
3744 * to avoid distributed deadlocks we handoff the write to the
3745 * nfs_aio threads. Doing so allows us to complete the
3746 * current request, rather than blocking on a server which may
3747 * be ourself (or blocked on ourself).
3748 *
3749 * Note the loopback deadlocks happened when the thread
3750 * invoking us was nfsd, and also when it was the pagedaemon.
3751 *
3752 * This solution has one known problem. If *ALL* buffers get
3753 * on the nfs_aio queue then no forward progress can be made
3754 * until one of those writes complete. And if the current
3755 * nfs_aio writes-in-progress block due to a non-responsive server we
3756 * are in a deadlock circle. Probably the cure is to limit the
3757 * async write concurrency in getnewbuf as in FreeBSD 3.2.
3758 */
3759 if (nfs_aio_threads && ISSET(ap->a_bp->b_flags, B_ASYNC)) {
3760 simple_lock(&nfs_aio_slock);
3761 nfs_aio_bufq_len++;
3762 TAILQ_INSERT_TAIL(&nfs_aio_bufq, ap->a_bp, b_freelist);
3763 simple_unlock(&nfs_aio_slock);
3764 wakeup_one((caddr_t)&nfs_aio_bufq);
3765 return (0);
3766 }
3767 return (nfs_writebp(ap->a_bp, 1));
3768 }
3769
3770 /*
3771 * This is a clone of vn_bwrite(), except that B_WRITEINPROG isn't set unless
3772 * the force flag is one and it also handles the B_NEEDCOMMIT flag.
3773 */
3774 int
3775 nfs_writebp(bp, force)
3776 register struct buf *bp;
3777 int force;
3778 {
3779 int s;
3780 register int oldflags = bp->b_flags, retv = 1;
3781 off_t off;
3782 upl_t upl;
3783 kern_return_t kret;
3784 struct vnode *vp = bp->b_vp;
3785 upl_page_info_t *pl;
3786
3787 if(!ISSET(bp->b_flags, B_BUSY))
3788 panic("nfs_writebp: buffer is not busy???");
3789
3790 s = splbio();
3791 CLR(bp->b_flags, (B_READ|B_DONE|B_ERROR|B_DELWRI));
3792
3793 if (ISSET(oldflags, (B_ASYNC|B_DELWRI))) {
3794 reassignbuf(bp, vp);
3795 }
3796
3797 vp->v_numoutput++;
3798 current_proc()->p_stats->p_ru.ru_oublock++;
3799 splx(s);
3800
3801 /*
3802 * Since the B_BUSY flag is set, we need to lock the page before doing
3803 * nfs_commit. Otherwise we may block and get a busy incore pages
3804 * during a vm pageout. Move the existing code up before the commit.
3805 */
3806 if (!ISSET(bp->b_flags, B_META) && UBCISVALID(vp) &&
3807 !ISSET(bp->b_flags, B_PAGELIST)) {
3808 kret = ubc_create_upl(vp, ubc_blktooff(vp, bp->b_lblkno),
3809 bp->b_bufsize, &upl, &pl, UPL_PRECIOUS);
3810 if (kret != KERN_SUCCESS)
3811 panic("nfs_writebp: ubc_create_upl %d", kret);
3812 #ifdef UBC_DEBUG
3813 upl_ubc_alias_set(upl, current_act(), 2);
3814 #endif /* UBC_DEBUG */
3815 s = splbio();
3816 bp->b_pagelist = upl;
3817 SET(bp->b_flags, B_PAGELIST);
3818 splx(s);
3819
3820 kret = ubc_upl_map(upl, (vm_address_t *)&(bp->b_data));
3821 if (kret != KERN_SUCCESS)
3822 panic("nfs_writebp: ubc_upl_map %d", kret);
3823 if(bp->b_data == 0)
3824 panic("nfs_writebp: ubc_upl_map mapped 0");
3825 if (!upl_page_present(pl, 0)) /* even more paranoia */
3826 panic("nfs_writebp: nopage");
3827 }
3828
3829 /*
3830 * If B_NEEDCOMMIT is set, a commit rpc may do the trick. If not
3831 * an actual write will have to be scheduled via. VOP_STRATEGY().
3832 * If B_WRITEINPROG is already set, then push it with a write anyhow.
3833 */
3834 if ((oldflags & (B_NEEDCOMMIT | B_WRITEINPROG)) == B_NEEDCOMMIT) {
3835 off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
3836 SET(bp->b_flags, B_WRITEINPROG);
3837 retv = nfs_commit(vp, off, bp->b_dirtyend-bp->b_dirtyoff,
3838 bp->b_wcred, bp->b_proc);
3839 CLR(bp->b_flags, B_WRITEINPROG);
3840 if (!retv) {
3841 bp->b_dirtyoff = bp->b_dirtyend = 0;
3842 CLR(bp->b_flags, B_NEEDCOMMIT);
3843 biodone(bp); /* on B_ASYNC will brelse the buffer */
3844
3845 } else if (retv == NFSERR_STALEWRITEVERF)
3846 nfs_clearcommit(vp->v_mount);
3847 }
3848 if (retv) {
3849 if (force)
3850 SET(bp->b_flags, B_WRITEINPROG);
3851 VOP_STRATEGY(bp);
3852 }
3853
3854 if( (oldflags & B_ASYNC) == 0) {
3855 int rtval = biowait(bp);
3856
3857 if (oldflags & B_DELWRI) {
3858 s = splbio();
3859 reassignbuf(bp, vp);
3860 splx(s);
3861 }
3862 brelse(bp);
3863 return (rtval);
3864 }
3865
3866 return (0);
3867 }
3868
3869 /*
3870 * nfs special file access vnode op.
3871 * Essentially just get vattr and then imitate iaccess() since the device is
3872 * local to the client.
3873 */
3874 static int
3875 nfsspec_access(ap)
3876 struct vop_access_args /* {
3877 struct vnode *a_vp;
3878 int a_mode;
3879 struct ucred *a_cred;
3880 struct proc *a_p;
3881 } */ *ap;
3882 {
3883 register struct vattr *vap;
3884 register gid_t *gp;
3885 register struct ucred *cred = ap->a_cred;
3886 struct vnode *vp = ap->a_vp;
3887 mode_t mode = ap->a_mode;
3888 struct vattr vattr;
3889 register int i;
3890 int error;
3891
3892 /*
3893 * Disallow write attempts on filesystems mounted read-only;
3894 * unless the file is a socket, fifo, or a block or character
3895 * device resident on the filesystem.
3896 */
3897 if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3898 switch (vp->v_type) {
3899 case VREG: case VDIR: case VLNK:
3900 return (EROFS);
3901 }
3902 }
3903 /*
3904 * If you're the super-user,
3905 * you always get access.
3906 */
3907 if (cred->cr_uid == 0)
3908 return (0);
3909 vap = &vattr;
3910 error = VOP_GETATTR(vp, vap, cred, ap->a_p);
3911 if (error)
3912 return (error);
3913 /*
3914 * Access check is based on only one of owner, group, public.
3915 * If not owner, then check group. If not a member of the
3916 * group, then check public access.
3917 */
3918 if (cred->cr_uid != vap->va_uid) {
3919 mode >>= 3;
3920 gp = cred->cr_groups;
3921 for (i = 0; i < cred->cr_ngroups; i++, gp++)
3922 if (vap->va_gid == *gp)
3923 goto found;
3924 mode >>= 3;
3925 found:
3926 ;
3927 }
3928 error = (vap->va_mode & mode) == mode ? 0 : EACCES;
3929 return (error);
3930 }
3931
3932 /*
3933 * Read wrapper for special devices.
3934 */
3935 static int
3936 nfsspec_read(ap)
3937 struct vop_read_args /* {
3938 struct vnode *a_vp;
3939 struct uio *a_uio;
3940 int a_ioflag;
3941 struct ucred *a_cred;
3942 } */ *ap;
3943 {
3944 register struct nfsnode *np = VTONFS(ap->a_vp);
3945
3946 /*
3947 * Set access flag.
3948 */
3949 np->n_flag |= NACC;
3950 np->n_atim.tv_sec = time.tv_sec;
3951 np->n_atim.tv_nsec = time.tv_usec * 1000;
3952 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
3953 }
3954
3955 /*
3956 * Write wrapper for special devices.
3957 */
3958 static int
3959 nfsspec_write(ap)
3960 struct vop_write_args /* {
3961 struct vnode *a_vp;
3962 struct uio *a_uio;
3963 int a_ioflag;
3964 struct ucred *a_cred;
3965 } */ *ap;
3966 {
3967 register struct nfsnode *np = VTONFS(ap->a_vp);
3968
3969 /*
3970 * Set update flag.
3971 */
3972 np->n_flag |= NUPD;
3973 np->n_mtim.tv_sec = time.tv_sec;
3974 np->n_mtim.tv_nsec = time.tv_usec * 1000;
3975 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
3976 }
3977
3978 /*
3979 * Close wrapper for special devices.
3980 *
3981 * Update the times on the nfsnode then do device close.
3982 */
3983 static int
3984 nfsspec_close(ap)
3985 struct vop_close_args /* {
3986 struct vnode *a_vp;
3987 int a_fflag;
3988 struct ucred *a_cred;
3989 struct proc *a_p;
3990 } */ *ap;
3991 {
3992 register struct vnode *vp = ap->a_vp;
3993 register struct nfsnode *np = VTONFS(vp);
3994 struct vattr vattr;
3995
3996 if (np->n_flag & (NACC | NUPD)) {
3997 np->n_flag |= NCHG;
3998 if (vp->v_usecount == 1 &&
3999 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
4000 VATTR_NULL(&vattr);
4001 if (np->n_flag & NACC)
4002 vattr.va_atime = np->n_atim;
4003 if (np->n_flag & NUPD)
4004 vattr.va_mtime = np->n_mtim;
4005 (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
4006 }
4007 }
4008 return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
4009 }
4010
4011 /*
4012 * Read wrapper for fifos.
4013 */
4014 static int
4015 nfsfifo_read(ap)
4016 struct vop_read_args /* {
4017 struct vnode *a_vp;
4018 struct uio *a_uio;
4019 int a_ioflag;
4020 struct ucred *a_cred;
4021 } */ *ap;
4022 {
4023 extern vop_t **fifo_vnodeop_p;
4024 register struct nfsnode *np = VTONFS(ap->a_vp);
4025
4026 /*
4027 * Set access flag.
4028 */
4029 np->n_flag |= NACC;
4030 np->n_atim.tv_sec = time.tv_sec;
4031 np->n_atim.tv_nsec = time.tv_usec * 1000;
4032 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
4033 }
4034
4035 /*
4036 * Write wrapper for fifos.
4037 */
4038 static int
4039 nfsfifo_write(ap)
4040 struct vop_write_args /* {
4041 struct vnode *a_vp;
4042 struct uio *a_uio;
4043 int a_ioflag;
4044 struct ucred *a_cred;
4045 } */ *ap;
4046 {
4047 extern vop_t **fifo_vnodeop_p;
4048 register struct nfsnode *np = VTONFS(ap->a_vp);
4049
4050 /*
4051 * Set update flag.
4052 */
4053 np->n_flag |= NUPD;
4054 np->n_mtim.tv_sec = time.tv_sec;
4055 np->n_mtim.tv_nsec = time.tv_usec * 1000;
4056 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
4057 }
4058
4059 /*
4060 * Close wrapper for fifos.
4061 *
4062 * Update the times on the nfsnode then do fifo close.
4063 */
4064 static int
4065 nfsfifo_close(ap)
4066 struct vop_close_args /* {
4067 struct vnode *a_vp;
4068 int a_fflag;
4069 struct ucred *a_cred;
4070 struct proc *a_p;
4071 } */ *ap;
4072 {
4073 register struct vnode *vp = ap->a_vp;
4074 register struct nfsnode *np = VTONFS(vp);
4075 struct vattr vattr;
4076 extern vop_t **fifo_vnodeop_p;
4077
4078 if (np->n_flag & (NACC | NUPD)) {
4079 if (np->n_flag & NACC) {
4080 np->n_atim.tv_sec = time.tv_sec;
4081 np->n_atim.tv_nsec = time.tv_usec * 1000;
4082 }
4083 if (np->n_flag & NUPD) {
4084 np->n_mtim.tv_sec = time.tv_sec;
4085 np->n_mtim.tv_nsec = time.tv_usec * 1000;
4086 }
4087 np->n_flag |= NCHG;
4088 if (vp->v_usecount == 1 &&
4089 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
4090 VATTR_NULL(&vattr);
4091 if (np->n_flag & NACC)
4092 vattr.va_atime = np->n_atim;
4093 if (np->n_flag & NUPD)
4094 vattr.va_mtime = np->n_mtim;
4095 (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
4096 }
4097 }
4098 return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
4099 }
4100
4101 static int
4102 nfs_ioctl(ap)
4103 struct vop_ioctl_args *ap;
4104 {
4105
4106 /*
4107 * XXX we were once bogusly enoictl() which returned this (ENOTTY).
4108 * Probably we should return ENODEV.
4109 */
4110 return (ENOTTY);
4111 }
4112
4113 static int
4114 nfs_select(ap)
4115 struct vop_select_args *ap;
4116 {
4117
4118 /*
4119 * We were once bogusly seltrue() which returns 1. Is this right?
4120 */
4121 return (1);
4122 }
4123
4124 /* XXX Eliminate use of struct bp here */
4125 /*
4126 * Vnode op for pagein using getblk_pages
4127 * derived from nfs_bioread()
4128 * No read aheads are started from pagein operation
4129 */
4130 static int
4131 nfs_pagein(ap)
4132 struct vop_pagein_args /* {
4133 struct vnode *a_vp,
4134 upl_t a_pl,
4135 vm_offset_t a_pl_offset,
4136 off_t a_f_offset,
4137 size_t a_size,
4138 struct ucred *a_cred,
4139 int a_flags
4140 } */ *ap;
4141 {
4142 register struct vnode *vp = ap->a_vp;
4143 upl_t pl = ap->a_pl;
4144 size_t size= ap->a_size;
4145 off_t f_offset = ap->a_f_offset;
4146 vm_offset_t pl_offset = ap->a_pl_offset;
4147 int flags = ap->a_flags;
4148 struct ucred *cred;
4149 register struct nfsnode *np = VTONFS(vp);
4150 register int biosize;
4151 register int xsize;
4152 struct vattr vattr;
4153 struct proc *p = current_proc();
4154 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
4155 int error = 0;
4156 vm_offset_t ioaddr;
4157 struct uio auio;
4158 struct iovec aiov;
4159 struct uio * uio = &auio;
4160 int nofreeupl = flags & UPL_NOCOMMIT;
4161
4162 FSDBG(322, f_offset, size, pl, pl_offset);
4163 if (pl == (upl_t)NULL)
4164 panic("nfs_pagein: no upl");
4165
4166 if (UBCINVALID(vp)) {
4167 printf("nfs_pagein: invalid vnode 0x%x", (int)vp);
4168 if (!nofreeupl)
4169 (void) ubc_upl_abort(pl, NULL);
4170 return (EPERM);
4171 }
4172 UBCINFOCHECK("nfs_pagein", vp);
4173
4174 if (size <= 0) {
4175 printf("nfs_pagein: invalid size %d", size);
4176 if (!nofreeupl)
4177 (void) ubc_upl_abort(pl, NULL);
4178 return (EINVAL);
4179 }
4180 if (f_offset < 0 || f_offset >= np->n_size ||
4181 (f_offset & PAGE_MASK_64)) {
4182 if (!nofreeupl)
4183 ubc_upl_abort_range(pl, pl_offset, size,
4184 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
4185 return (EINVAL);
4186 }
4187 cred = ubc_getcred(vp);
4188 if (cred == NOCRED)
4189 cred = ap->a_cred;
4190
4191 auio.uio_iov = &aiov;
4192 auio.uio_iovcnt = 1;
4193 auio.uio_offset = f_offset;
4194 auio.uio_segflg = UIO_SYSSPACE;
4195 auio.uio_rw = UIO_READ;
4196 auio.uio_procp = NULL;
4197
4198 if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3)
4199 (void)nfs_fsinfo(nmp, vp, cred, p);
4200 biosize = min(vp->v_mount->mnt_stat.f_iosize, size);
4201
4202 if (biosize & PAGE_MASK)
4203 panic("nfs_pagein(%x): biosize not page aligned", biosize);
4204
4205 ubc_upl_map(pl, &ioaddr);
4206 ioaddr += pl_offset;
4207 xsize = size;
4208
4209 do {
4210 uio->uio_resid = min(biosize, xsize);
4211 aiov.iov_len = uio->uio_resid;
4212 aiov.iov_base = (caddr_t)ioaddr;
4213
4214 FSDBG(322, uio->uio_offset, uio->uio_resid, ioaddr, xsize);
4215 #warning our nfs_pagein does not support NQNFS
4216 /*
4217 * With UBC we get here only when the file data is not in the VM
4218 * page cache, so go ahead and read in.
4219 */
4220 #ifdef UBC_DEBUG
4221 upl_ubc_alias_set(pl, current_act(), 2);
4222 #endif /* UBC_DEBUG */
4223 nfsstats.pageins++;
4224 error = nfs_readrpc(vp, uio, cred);
4225
4226 if (!error) {
4227 if (uio->uio_resid) {
4228 /*
4229 * If uio_resid > 0, there is a hole in the file
4230 * and no writes after the hole have been pushed
4231 * to the server yet... or we're at the EOF
4232 * Just zero fill the rest of the valid area.
4233 */
4234 int zcnt = uio->uio_resid;
4235 int zoff = biosize - zcnt;
4236 bzero((char *)ioaddr + zoff, zcnt);
4237
4238 FSDBG(324, uio->uio_offset, zoff, zcnt, ioaddr);
4239 uio->uio_offset += zcnt;
4240 }
4241 ioaddr += biosize;
4242 xsize -= biosize;
4243 } else
4244 FSDBG(322, uio->uio_offset, uio->uio_resid, error, -1);
4245 if (p && (vp->v_flag & VTEXT) &&
4246 ((nmp->nm_flag & NFSMNT_NQNFS &&
4247 NQNFS_CKINVALID(vp, np, ND_READ) &&
4248 np->n_lrev != np->n_brev) ||
4249 (!(nmp->nm_flag & NFSMNT_NQNFS) &&
4250 np->n_mtime != np->n_vattr.va_mtime.tv_sec))) {
4251 uprintf("Process killed due to text file modification\n");
4252 psignal(p, SIGKILL);
4253 p->p_flag |= P_NOSWAP;
4254 }
4255
4256 } while (error == 0 && xsize > 0);
4257
4258 ubc_upl_unmap(pl);
4259
4260 if (!nofreeupl) {
4261 if (error)
4262 ubc_upl_abort_range(pl, pl_offset, size,
4263 UPL_ABORT_ERROR |
4264 UPL_ABORT_FREE_ON_EMPTY);
4265 else
4266 ubc_upl_commit_range(pl, pl_offset, size,
4267 UPL_COMMIT_CLEAR_DIRTY |
4268 UPL_COMMIT_FREE_ON_EMPTY);
4269 }
4270 return (error);
4271 }
4272
4273
4274 /*
4275 * Vnode op for pageout using UPL
4276 * Derived from nfs_write()
4277 * File size changes are not permitted in pageout.
4278 */
4279 static int
4280 nfs_pageout(ap)
4281 struct vop_pageout_args /* {
4282 struct vnode *a_vp,
4283 upl_t a_pl,
4284 vm_offset_t a_pl_offset,
4285 off_t a_f_offset,
4286 size_t a_size,
4287 struct ucred *a_cred,
4288 int a_flags
4289 } */ *ap;
4290 {
4291 register struct vnode *vp = ap->a_vp;
4292 upl_t pl = ap->a_pl;
4293 size_t size= ap->a_size;
4294 off_t f_offset = ap->a_f_offset;
4295 vm_offset_t pl_offset = ap->a_pl_offset;
4296 int flags = ap->a_flags;
4297 int ioflag = ap->a_flags;
4298 register int biosize;
4299 struct proc *p = current_proc();
4300 struct nfsnode *np = VTONFS(vp);
4301 register struct ucred *cred;
4302 struct buf *bp;
4303 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
4304 daddr_t lbn;
4305 int n = 0, on, error = 0, iomode, must_commit, s;
4306 off_t off;
4307 vm_offset_t ioaddr;
4308 struct uio auio;
4309 struct iovec aiov;
4310 struct uio * uio = &auio;
4311 int nofreeupl = flags & UPL_NOCOMMIT;
4312 int iosize;
4313 int pgsize;
4314
4315 FSDBG(323, f_offset, size, pl, pl_offset);
4316
4317 if (pl == (upl_t)NULL)
4318 panic("nfs_pageout: no upl");
4319
4320 if (UBCINVALID(vp)) {
4321 printf("nfs_pageout: invalid vnode 0x%x", (int)vp);
4322 if (!nofreeupl)
4323 (void) ubc_upl_abort(pl, NULL);
4324 return (EIO);
4325 }
4326 UBCINFOCHECK("nfs_pageout", vp);
4327
4328 if (size <= 0) {
4329 printf("nfs_pageout: invalid size %d", size);
4330 if (!nofreeupl)
4331 (void) ubc_upl_abort(pl, NULL);
4332 return (EINVAL);
4333 }
4334
4335 /*
4336 * I use nm_rsize, not nm_wsize so that all buffer cache blocks
4337 * will be the same size within a filesystem. nfs_writerpc will
4338 * still use nm_wsize when sizing the rpc's.
4339 */
4340 biosize = min(vp->v_mount->mnt_stat.f_iosize, size);
4341
4342 if (biosize & PAGE_MASK)
4343 panic("nfs_pageout(%x): biosize not page aligned", biosize);
4344
4345 /*
4346 * Check to see whether the buffer is incore
4347 * If incore and not busy invalidate it from the cache
4348 * we should not find it BUSY, since we always do a
4349 * vm_fault_list_request in 'getblk' before returning
4350 * which would block on the page busy status
4351 */
4352 lbn = f_offset / PAGE_SIZE; /* to match the size getblk uses */
4353
4354 for (iosize = size; iosize > 0; iosize -= PAGE_SIZE, lbn++) {
4355 s = splbio();
4356 if (bp = incore(vp, lbn)) {
4357 FSDBG(323, lbn*PAGE_SIZE, 1, bp, bp->b_flags);
4358 if (ISSET(bp->b_flags, B_BUSY)) {
4359 /* no panic. just tell vm we are busy */
4360 if (!nofreeupl)
4361 (void) ubc_upl_abort(pl, NULL);
4362 return(EBUSY);
4363 }
4364 bremfree(bp);
4365 SET(bp->b_flags, (B_BUSY | B_INVAL));
4366 brelse(bp);
4367 }
4368 splx(s);
4369 }
4370
4371 cred = ubc_getcred(vp);
4372 if (cred == NOCRED)
4373 cred = ap->a_cred;
4374
4375 if (np->n_flag & NWRITEERR) {
4376 np->n_flag &= ~NWRITEERR;
4377 if (!nofreeupl)
4378 ubc_upl_abort_range(pl, pl_offset, size,
4379 UPL_ABORT_FREE_ON_EMPTY);
4380 return (np->n_error);
4381 }
4382 if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3)
4383 (void)nfs_fsinfo(nmp, vp, cred, p);
4384
4385 if (f_offset < 0 || f_offset >= np->n_size ||
4386 f_offset & PAGE_MASK_64 || size & PAGE_MASK) {
4387 if (!nofreeupl)
4388 ubc_upl_abort_range(pl, pl_offset, size,
4389 UPL_ABORT_FREE_ON_EMPTY);
4390 return (EINVAL);
4391 }
4392
4393 ubc_upl_map(pl, &ioaddr);
4394
4395 if (f_offset + size > np->n_size)
4396 iosize = np->n_size - f_offset;
4397 else
4398 iosize = size;
4399
4400 pgsize = (iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK;
4401
4402 if (size > pgsize) {
4403 if (!nofreeupl)
4404 ubc_upl_abort_range(pl, pl_offset + pgsize,
4405 size - pgsize,
4406 UPL_ABORT_FREE_ON_EMPTY);
4407 }
4408 auio.uio_iov = &aiov;
4409 auio.uio_iovcnt = 1;
4410 auio.uio_offset = f_offset;
4411 auio.uio_segflg = UIO_SYSSPACE;
4412 auio.uio_rw = UIO_READ;
4413 auio.uio_resid = iosize;
4414 auio.uio_procp = NULL;
4415
4416 aiov.iov_len = iosize;
4417 aiov.iov_base = (caddr_t)ioaddr + pl_offset;
4418 /*
4419 * check for partial page and clear the
4420 * contents past end of the file before
4421 * releasing it in the VM page cache
4422 */
4423 if (f_offset < np->n_size && f_offset + size > np->n_size) {
4424 size_t io = np->n_size - f_offset;
4425
4426 bzero((caddr_t)(ioaddr + pl_offset + io), size - io);
4427
4428 FSDBG(321, np->n_size, f_offset, f_offset + io, size - io);
4429 }
4430
4431 do {
4432 #warning our nfs_pageout does not support NQNFS
4433 nfsstats.pageouts++;
4434 lbn = uio->uio_offset / biosize;
4435 on = uio->uio_offset & (biosize-1);
4436 n = min((unsigned)(biosize - on), uio->uio_resid);
4437 again:
4438 #if 0
4439 /* (removed for UBC) */
4440 bufsize = biosize;
4441 if ((lbn + 1) * biosize > np->n_size) {
4442 bufsize = np->n_size - lbn * biosize;
4443 bufsize = (bufsize + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
4444 }
4445 #endif
4446 vp->v_numoutput++;
4447 /* NMODIFIED would be set here if doing unstable writes */
4448 iomode = NFSV3WRITE_FILESYNC;
4449 error = nfs_writerpc(vp, uio, cred, &iomode, &must_commit);
4450 if (must_commit)
4451 nfs_clearcommit(vp->v_mount);
4452 vpwakeup(vp);
4453
4454 if (error)
4455 goto cleanup;
4456
4457 if (n > 0) {
4458 uio->uio_resid -= n;
4459 uio->uio_offset += n;
4460 uio->uio_iov->iov_base += n;
4461 uio->uio_iov->iov_len -= n;
4462 }
4463 } while (uio->uio_resid > 0 && n > 0);
4464
4465 cleanup:
4466 ubc_upl_unmap(pl);
4467 /*
4468 * We've had several different solutions on what to do when the pageout
4469 * gets an error. If we don't handle it, and return an error to the
4470 * caller, vm, it will retry . This can end in endless looping
4471 * between vm and here doing retries of the same page. Doing a dump
4472 * back to vm, will get it out of vm's knowledge and we lose whatever
4473 * data existed. This is risky, but in some cases necessary. For
4474 * example, the initial fix here was to do that for ESTALE. In that case
4475 * the server is telling us that the file is no longer the same. We
4476 * would not want to keep paging out to that. We also saw some 151
4477 * errors from Auspex server and NFSv3 can return errors higher than
4478 * ELAST. Those along with NFS known server errors we will "dump" from
4479 * vm. Errors we don't expect to occur, we dump and log for further
4480 * analysis. Errors that could be transient, networking ones,
4481 * we let vm "retry". Lastly, errors that we retry, but may have potential
4482 * to storm the network, we "retrywithsleep". "sever" will be used in
4483 * in the future to dump all pages of object for cases like ESTALE.
4484 * All this is the basis for the states returned and first guesses on
4485 * error handling. Tweaking expected as more statistics are gathered.
4486 * Note, in the long run we may need another more robust solution to
4487 * have some kind of persistant store when the vm cannot dump nor keep
4488 * retrying as a solution, but this would be a file architectural change
4489 */
4490
4491 if (!nofreeupl) { /* otherwise stacked file system has to handle this */
4492 if (error) {
4493 int abortflags;
4494 short action = nfs_pageouterrorhandler(error);
4495
4496 switch (action) {
4497 case DUMP:
4498 abortflags = UPL_ABORT_DUMP_PAGES|UPL_ABORT_FREE_ON_EMPTY;
4499 break;
4500 case DUMPANDLOG:
4501 abortflags = UPL_ABORT_DUMP_PAGES|UPL_ABORT_FREE_ON_EMPTY;
4502 if (error <= ELAST &&
4503 (errorcount[error] % 100 == 0))
4504 printf("nfs_pageout: unexpected error %d. dumping vm page\n", error);
4505 errorcount[error]++;
4506 break;
4507 case RETRY:
4508 abortflags = UPL_ABORT_FREE_ON_EMPTY;
4509 break;
4510 case RETRYWITHSLEEP:
4511 abortflags = UPL_ABORT_FREE_ON_EMPTY;
4512 /* pri unused. PSOCK for placeholder. */
4513 (void) tsleep(&lbolt, PSOCK,
4514 "nfspageout", 0);
4515 break;
4516 case SEVER: /* not implemented */
4517 default:
4518 printf("nfs_pageout: action %d not expected\n", action);
4519 break;
4520 }
4521
4522 ubc_upl_abort_range(pl, pl_offset, size, abortflags);
4523 /* return error in all cases above */
4524
4525 } else
4526 ubc_upl_commit_range(pl, pl_offset, pgsize,
4527 UPL_COMMIT_CLEAR_DIRTY |
4528 UPL_COMMIT_FREE_ON_EMPTY);
4529 }
4530 return (error);
4531 }
4532
4533 /* Blktooff derives file offset given a logical block number */
4534 static int
4535 nfs_blktooff(ap)
4536 struct vop_blktooff_args /* {
4537 struct vnode *a_vp;
4538 daddr_t a_lblkno;
4539 off_t *a_offset;
4540 } */ *ap;
4541 {
4542 int biosize;
4543 register struct vnode *vp = ap->a_vp;
4544
4545 biosize = min(vp->v_mount->mnt_stat.f_iosize, PAGE_SIZE); /* nfs_bio.c */
4546
4547 *ap->a_offset = (off_t)(ap->a_lblkno * biosize);
4548
4549 return (0);
4550 }
4551
4552 static int
4553 nfs_offtoblk(ap)
4554 struct vop_offtoblk_args /* {
4555 struct vnode *a_vp;
4556 off_t a_offset;
4557 daddr_t *a_lblkno;
4558 } */ *ap;
4559 {
4560 int biosize;
4561 register struct vnode *vp = ap->a_vp;
4562
4563 biosize = min(vp->v_mount->mnt_stat.f_iosize, PAGE_SIZE); /* nfs_bio.c */
4564
4565 *ap->a_lblkno = (daddr_t)(ap->a_offset / biosize);
4566
4567 return (0);
4568 }
4569 static int
4570 nfs_cmap(ap)
4571 struct vop_cmap_args /* {
4572 struct vnode *a_vp;
4573 off_t a_offset;
4574 size_t a_size;
4575 daddr_t *a_bpn;
4576 size_t *a_run;
4577 void *a_poff;
4578 } */ *ap;
4579 {
4580 return (EOPNOTSUPP);
4581 }