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