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