2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
27 * This code is derived from software contributed to Berkeley by
28 * Rick Macklem at The University of Guelph.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
59 * FreeBSD-Id: nfs_vnops.c,v 1.72 1997/11/07 09:20:48 phk Exp $
64 * vnode op calls for Sun NFS version 2 and 3
66 #include <sys/param.h>
67 #include <sys/kernel.h>
68 #include <sys/systm.h>
69 #include <sys/resourcevar.h>
71 #include <sys/mount.h>
72 #include <sys/malloc.h>
75 #include <sys/namei.h>
76 #include <sys/vnode.h>
77 #include <sys/dirent.h>
78 #include <sys/fcntl.h>
79 #include <sys/lockf.h>
82 #include <vfs/vfs_support.h>
85 #include <machine/spl.h>
86 #include <vm/vm_pageout.h>
89 #include <kern/clock.h>
91 #include <miscfs/fifofs/fifo.h>
92 #include <miscfs/specfs/specdev.h>
94 #include <nfs/rpcv2.h>
95 #include <nfs/nfsproto.h>
97 #include <nfs/nfsnode.h>
98 #include <nfs/nfsmount.h>
99 #include <nfs/nfs_lock.h>
100 #include <nfs/xdr_subs.h>
101 #include <nfs/nfsm_subs.h>
102 #include <nfs/nqnfs.h>
105 #include <netinet/in.h>
106 #include <netinet/in_var.h>
107 #include <vm/vm_kern.h>
109 #include <kern/task.h>
110 #include <kern/sched_prim.h>
112 #include <sys/kdebug.h>
114 #define FSDBG(A, B, C, D, E) \
115 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_NONE, \
116 (int)(B), (int)(C), (int)(D), (int)(E), 0)
117 #define FSDBG_TOP(A, B, C, D, E) \
118 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_START, \
119 (int)(B), (int)(C), (int)(D), (int)(E), 0)
120 #define FSDBG_BOT(A, B, C, D, E) \
121 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_END, \
122 (int)(B), (int)(C), (int)(D), (int)(E), 0)
127 #define NFS_FREE_PNBUF(CNP) \
129 char *tmp = (CNP)->cn_pnbuf; \
130 (CNP)->cn_pnbuf = NULL; \
131 (CNP)->cn_flags &= ~HASBUF; \
132 FREE_ZONE(tmp, (CNP)->cn_pnlen, M_NAMEI); \
136 static int nfsspec_read
__P((struct vop_read_args
*));
137 static int nfsspec_write
__P((struct vop_write_args
*));
138 static int nfsfifo_read
__P((struct vop_read_args
*));
139 static int nfsfifo_write
__P((struct vop_write_args
*));
140 static int nfsspec_close
__P((struct vop_close_args
*));
141 static int nfsfifo_close
__P((struct vop_close_args
*));
142 #define nfs_poll vop_nopoll
143 static int nfs_ioctl
__P((struct vop_ioctl_args
*));
144 static int nfs_select
__P((struct vop_select_args
*));
145 static int nfs_flush
__P((struct vnode
*,struct ucred
*,int,struct proc
*));
146 static int nfs_setattrrpc
__P((struct vnode
*,struct vattr
*,struct ucred
*,struct proc
*));
147 static int nfs_lookup
__P((struct vop_lookup_args
*));
148 static int nfs_create
__P((struct vop_create_args
*));
149 static int nfs_mknod
__P((struct vop_mknod_args
*));
150 static int nfs_open
__P((struct vop_open_args
*));
151 static int nfs_close
__P((struct vop_close_args
*));
152 static int nfs_access
__P((struct vop_access_args
*));
153 static int nfs_getattr
__P((struct vop_getattr_args
*));
154 static int nfs_setattr
__P((struct vop_setattr_args
*));
155 static int nfs_read
__P((struct vop_read_args
*));
156 static int nfs_mmap
__P((struct vop_mmap_args
*));
157 static int nfs_fsync
__P((struct vop_fsync_args
*));
158 static int nfs_remove
__P((struct vop_remove_args
*));
159 static int nfs_link
__P((struct vop_link_args
*));
160 static int nfs_rename
__P((struct vop_rename_args
*));
161 static int nfs_mkdir
__P((struct vop_mkdir_args
*));
162 static int nfs_rmdir
__P((struct vop_rmdir_args
*));
163 static int nfs_symlink
__P((struct vop_symlink_args
*));
164 static int nfs_readdir
__P((struct vop_readdir_args
*));
165 static int nfs_bmap
__P((struct vop_bmap_args
*));
166 static int nfs_lookitup
__P((struct vnode
*,char *,int,struct ucred
*,struct proc
*,struct nfsnode
**));
167 static int nfs_sillyrename
__P((struct vnode
*,struct vnode
*,struct componentname
*));
168 static int nfsspec_access
__P((struct vop_access_args
*));
169 static int nfs_readlink
__P((struct vop_readlink_args
*));
170 static int nfs_print
__P((struct vop_print_args
*));
171 static int nfs_pathconf
__P((struct vop_pathconf_args
*));
172 static int nfs_advlock
__P((struct vop_advlock_args
*));
173 static int nfs_blkatoff
__P((struct vop_blkatoff_args
*));
174 static int nfs_valloc
__P((struct vop_valloc_args
*));
175 static int nfs_vfree
__P((struct vop_vfree_args
*));
176 static int nfs_truncate
__P((struct vop_truncate_args
*));
177 static int nfs_update
__P((struct vop_update_args
*));
178 static int nfs_pagein
__P((struct vop_pagein_args
*));
179 static int nfs_pageout
__P((struct vop_pageout_args
*));
180 static int nfs_blktooff
__P((struct vop_blktooff_args
*));
181 static int nfs_offtoblk
__P((struct vop_offtoblk_args
*));
182 static int nfs_cmap
__P((struct vop_cmap_args
*));
185 * Global vfs data structures for nfs
187 vop_t
**nfsv2_vnodeop_p
;
188 static struct vnodeopv_entry_desc nfsv2_vnodeop_entries
[] = {
189 { &vop_default_desc
, (vop_t
*)vn_default_error
},
190 { &vop_lookup_desc
, (vop_t
*)nfs_lookup
}, /* lookup */
191 { &vop_create_desc
, (vop_t
*)nfs_create
}, /* create */
192 { &vop_mknod_desc
, (vop_t
*)nfs_mknod
}, /* mknod */
193 { &vop_open_desc
, (vop_t
*)nfs_open
}, /* open */
194 { &vop_close_desc
, (vop_t
*)nfs_close
}, /* close */
195 { &vop_access_desc
, (vop_t
*)nfs_access
}, /* access */
196 { &vop_getattr_desc
, (vop_t
*)nfs_getattr
}, /* getattr */
197 { &vop_setattr_desc
, (vop_t
*)nfs_setattr
}, /* setattr */
198 { &vop_read_desc
, (vop_t
*)nfs_read
}, /* read */
199 { &vop_write_desc
, (vop_t
*)nfs_write
}, /* write */
200 { &vop_lease_desc
, (vop_t
*)nfs_lease_check
}, /* lease */
201 { &vop_ioctl_desc
, (vop_t
*)nfs_ioctl
}, /* ioctl */
202 { &vop_select_desc
, (vop_t
*)nfs_select
}, /* select */
203 { &vop_revoke_desc
, (vop_t
*)nfs_revoke
}, /* revoke */
204 { &vop_mmap_desc
, (vop_t
*)nfs_mmap
}, /* mmap */
205 { &vop_fsync_desc
, (vop_t
*)nfs_fsync
}, /* fsync */
206 { &vop_seek_desc
, (vop_t
*)nfs_seek
}, /* seek */
207 { &vop_remove_desc
, (vop_t
*)nfs_remove
}, /* remove */
208 { &vop_link_desc
, (vop_t
*)nfs_link
}, /* link */
209 { &vop_rename_desc
, (vop_t
*)nfs_rename
}, /* rename */
210 { &vop_mkdir_desc
, (vop_t
*)nfs_mkdir
}, /* mkdir */
211 { &vop_rmdir_desc
, (vop_t
*)nfs_rmdir
}, /* rmdir */
212 { &vop_symlink_desc
, (vop_t
*)nfs_symlink
}, /* symlink */
213 { &vop_readdir_desc
, (vop_t
*)nfs_readdir
}, /* readdir */
214 { &vop_readlink_desc
, (vop_t
*)nfs_readlink
}, /* readlink */
215 { &vop_abortop_desc
, (vop_t
*)nop_abortop
}, /* abortop */
216 { &vop_inactive_desc
, (vop_t
*)nfs_inactive
}, /* inactive */
217 { &vop_reclaim_desc
, (vop_t
*)nfs_reclaim
}, /* reclaim */
218 { &vop_lock_desc
, (vop_t
*)nfs_lock
}, /* lock */
219 { &vop_unlock_desc
, (vop_t
*)nfs_unlock
}, /* unlock */
220 { &vop_bmap_desc
, (vop_t
*)nfs_bmap
}, /* bmap */
221 { &vop_strategy_desc
, (vop_t
*)err_strategy
}, /* strategy */
222 { &vop_print_desc
, (vop_t
*)nfs_print
}, /* print */
223 { &vop_islocked_desc
, (vop_t
*)nfs_islocked
}, /* islocked */
224 { &vop_pathconf_desc
, (vop_t
*)nfs_pathconf
}, /* pathconf */
225 { &vop_advlock_desc
, (vop_t
*)nfs_advlock
}, /* advlock */
226 { &vop_blkatoff_desc
, (vop_t
*)nfs_blkatoff
}, /* blkatoff */
227 { &vop_valloc_desc
, (vop_t
*)nfs_valloc
}, /* valloc */
228 { &vop_reallocblks_desc
, (vop_t
*)nfs_reallocblks
}, /* reallocblks */
229 { &vop_vfree_desc
, (vop_t
*)nfs_vfree
}, /* vfree */
230 { &vop_truncate_desc
, (vop_t
*)nfs_truncate
}, /* truncate */
231 { &vop_update_desc
, (vop_t
*)nfs_update
}, /* update */
232 { &vop_bwrite_desc
, (vop_t
*)err_bwrite
}, /* bwrite */
233 { &vop_pagein_desc
, (vop_t
*)nfs_pagein
}, /* Pagein */
234 { &vop_pageout_desc
, (vop_t
*)nfs_pageout
}, /* Pageout */
235 { &vop_copyfile_desc
, (vop_t
*)err_copyfile
}, /* Copyfile */
236 { &vop_blktooff_desc
, (vop_t
*)nfs_blktooff
}, /* blktooff */
237 { &vop_offtoblk_desc
, (vop_t
*)nfs_offtoblk
}, /* offtoblk */
238 { &vop_cmap_desc
, (vop_t
*)nfs_cmap
}, /* cmap */
241 struct vnodeopv_desc nfsv2_vnodeop_opv_desc
=
242 { &nfsv2_vnodeop_p
, nfsv2_vnodeop_entries
};
244 VNODEOP_SET(nfsv2_vnodeop_opv_desc
);
248 * Special device vnode ops
250 vop_t
**spec_nfsv2nodeop_p
;
251 static struct vnodeopv_entry_desc spec_nfsv2nodeop_entries
[] = {
252 { &vop_default_desc
, (vop_t
*)vn_default_error
},
253 { &vop_lookup_desc
, (vop_t
*)spec_lookup
}, /* lookup */
254 { &vop_create_desc
, (vop_t
*)spec_create
}, /* create */
255 { &vop_mknod_desc
, (vop_t
*)spec_mknod
}, /* mknod */
256 { &vop_open_desc
, (vop_t
*)spec_open
}, /* open */
257 { &vop_close_desc
, (vop_t
*)nfsspec_close
}, /* close */
258 { &vop_access_desc
, (vop_t
*)nfsspec_access
}, /* access */
259 { &vop_getattr_desc
, (vop_t
*)nfs_getattr
}, /* getattr */
260 { &vop_setattr_desc
, (vop_t
*)nfs_setattr
}, /* setattr */
261 { &vop_read_desc
, (vop_t
*)nfsspec_read
}, /* read */
262 { &vop_write_desc
, (vop_t
*)nfsspec_write
}, /* write */
263 { &vop_lease_desc
, (vop_t
*)spec_lease_check
}, /* lease */
264 { &vop_ioctl_desc
, (vop_t
*)spec_ioctl
}, /* ioctl */
265 { &vop_select_desc
, (vop_t
*)spec_select
}, /* select */
266 { &vop_revoke_desc
, (vop_t
*)spec_revoke
}, /* revoke */
267 { &vop_mmap_desc
, (vop_t
*)spec_mmap
}, /* mmap */
268 { &vop_fsync_desc
, (vop_t
*)nfs_fsync
}, /* fsync */
269 { &vop_seek_desc
, (vop_t
*)spec_seek
}, /* seek */
270 { &vop_remove_desc
, (vop_t
*)spec_remove
}, /* remove */
271 { &vop_link_desc
, (vop_t
*)spec_link
}, /* link */
272 { &vop_rename_desc
, (vop_t
*)spec_rename
}, /* rename */
273 { &vop_mkdir_desc
, (vop_t
*)spec_mkdir
}, /* mkdir */
274 { &vop_rmdir_desc
, (vop_t
*)spec_rmdir
}, /* rmdir */
275 { &vop_symlink_desc
, (vop_t
*)spec_symlink
}, /* symlink */
276 { &vop_readdir_desc
, (vop_t
*)spec_readdir
}, /* readdir */
277 { &vop_readlink_desc
, (vop_t
*)spec_readlink
}, /* readlink */
278 { &vop_abortop_desc
, (vop_t
*)spec_abortop
}, /* abortop */
279 { &vop_inactive_desc
, (vop_t
*)nfs_inactive
}, /* inactive */
280 { &vop_reclaim_desc
, (vop_t
*)nfs_reclaim
}, /* reclaim */
281 { &vop_lock_desc
, (vop_t
*)nfs_lock
}, /* lock */
282 { &vop_unlock_desc
, (vop_t
*)nfs_unlock
}, /* unlock */
283 { &vop_bmap_desc
, (vop_t
*)spec_bmap
}, /* bmap */
284 { &vop_strategy_desc
, (vop_t
*)spec_strategy
}, /* strategy */
285 { &vop_print_desc
, (vop_t
*)nfs_print
}, /* print */
286 { &vop_islocked_desc
, (vop_t
*)nfs_islocked
}, /* islocked */
287 { &vop_pathconf_desc
, (vop_t
*)spec_pathconf
}, /* pathconf */
288 { &vop_advlock_desc
, (vop_t
*)spec_advlock
}, /* advlock */
289 { &vop_blkatoff_desc
, (vop_t
*)spec_blkatoff
}, /* blkatoff */
290 { &vop_valloc_desc
, (vop_t
*)spec_valloc
}, /* valloc */
291 { &vop_reallocblks_desc
, (vop_t
*)spec_reallocblks
}, /* reallocblks */
292 { &vop_vfree_desc
, (vop_t
*)spec_vfree
}, /* vfree */
293 { &vop_truncate_desc
, (vop_t
*)spec_truncate
}, /* truncate */
294 { &vop_update_desc
, (vop_t
*)nfs_update
}, /* update */
295 { &vop_bwrite_desc
, (vop_t
*)vn_bwrite
}, /* bwrite */
296 { &vop_devblocksize_desc
, (vop_t
*)spec_devblocksize
}, /* devblocksize */
297 { &vop_pagein_desc
, (vop_t
*)nfs_pagein
}, /* Pagein */
298 { &vop_pageout_desc
, (vop_t
*)nfs_pageout
}, /* Pageout */
299 { &vop_blktooff_desc
, (vop_t
*)nfs_blktooff
}, /* blktooff */
300 { &vop_offtoblk_desc
, (vop_t
*)nfs_offtoblk
}, /* offtoblk */
301 { &vop_cmap_desc
, (vop_t
*)nfs_cmap
}, /* cmap */
304 struct vnodeopv_desc spec_nfsv2nodeop_opv_desc
=
305 { &spec_nfsv2nodeop_p
, spec_nfsv2nodeop_entries
};
307 VNODEOP_SET(spec_nfsv2nodeop_opv_desc
);
310 vop_t
**fifo_nfsv2nodeop_p
;
311 static struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries
[] = {
312 { &vop_default_desc
, (vop_t
*)vn_default_error
},
313 { &vop_lookup_desc
, (vop_t
*)fifo_lookup
}, /* lookup */
314 { &vop_create_desc
, (vop_t
*)fifo_create
}, /* create */
315 { &vop_mknod_desc
, (vop_t
*)fifo_mknod
}, /* mknod */
316 { &vop_open_desc
, (vop_t
*)fifo_open
}, /* open */
317 { &vop_close_desc
, (vop_t
*)nfsfifo_close
}, /* close */
318 { &vop_access_desc
, (vop_t
*)nfsspec_access
}, /* access */
319 { &vop_getattr_desc
, (vop_t
*)nfs_getattr
}, /* getattr */
320 { &vop_setattr_desc
, (vop_t
*)nfs_setattr
}, /* setattr */
321 { &vop_read_desc
, (vop_t
*)nfsfifo_read
}, /* read */
322 { &vop_write_desc
, (vop_t
*)nfsfifo_write
}, /* write */
323 { &vop_lease_desc
, (vop_t
*)fifo_lease_check
}, /* lease */
324 { &vop_ioctl_desc
, (vop_t
*)fifo_ioctl
}, /* ioctl */
325 { &vop_select_desc
, (vop_t
*)fifo_select
}, /* select */
326 { &vop_revoke_desc
, (vop_t
*)fifo_revoke
}, /* revoke */
327 { &vop_mmap_desc
, (vop_t
*)fifo_mmap
}, /* mmap */
328 { &vop_fsync_desc
, (vop_t
*)nfs_fsync
}, /* fsync */
329 { &vop_seek_desc
, (vop_t
*)fifo_seek
}, /* seek */
330 { &vop_remove_desc
, (vop_t
*)fifo_remove
}, /* remove */
331 { &vop_link_desc
, (vop_t
*)fifo_link
}, /* link */
332 { &vop_rename_desc
, (vop_t
*)fifo_rename
}, /* rename */
333 { &vop_mkdir_desc
, (vop_t
*)fifo_mkdir
}, /* mkdir */
334 { &vop_rmdir_desc
, (vop_t
*)fifo_rmdir
}, /* rmdir */
335 { &vop_symlink_desc
, (vop_t
*)fifo_symlink
}, /* symlink */
336 { &vop_readdir_desc
, (vop_t
*)fifo_readdir
}, /* readdir */
337 { &vop_readlink_desc
, (vop_t
*)fifo_readlink
}, /* readlink */
338 { &vop_abortop_desc
, (vop_t
*)fifo_abortop
}, /* abortop */
339 { &vop_inactive_desc
, (vop_t
*)nfs_inactive
}, /* inactive */
340 { &vop_reclaim_desc
, (vop_t
*)nfs_reclaim
}, /* reclaim */
341 { &vop_lock_desc
, (vop_t
*)nfs_lock
}, /* lock */
342 { &vop_unlock_desc
, (vop_t
*)nfs_unlock
}, /* unlock */
343 { &vop_bmap_desc
, (vop_t
*)fifo_bmap
}, /* bmap */
344 { &vop_strategy_desc
, (vop_t
*)fifo_strategy
}, /* strategy */
345 { &vop_print_desc
, (vop_t
*)nfs_print
}, /* print */
346 { &vop_islocked_desc
, (vop_t
*)nfs_islocked
}, /* islocked */
347 { &vop_pathconf_desc
, (vop_t
*)fifo_pathconf
}, /* pathconf */
348 { &vop_advlock_desc
, (vop_t
*)fifo_advlock
}, /* advlock */
349 { &vop_blkatoff_desc
, (vop_t
*)fifo_blkatoff
}, /* blkatoff */
350 { &vop_valloc_desc
, (vop_t
*)fifo_valloc
}, /* valloc */
351 { &vop_reallocblks_desc
, (vop_t
*)fifo_reallocblks
}, /* reallocblks */
352 { &vop_vfree_desc
, (vop_t
*)fifo_vfree
}, /* vfree */
353 { &vop_truncate_desc
, (vop_t
*)fifo_truncate
}, /* truncate */
354 { &vop_update_desc
, (vop_t
*)nfs_update
}, /* update */
355 { &vop_bwrite_desc
, (vop_t
*)vn_bwrite
}, /* bwrite */
356 { &vop_pagein_desc
, (vop_t
*)nfs_pagein
}, /* Pagein */
357 { &vop_pageout_desc
, (vop_t
*)nfs_pageout
}, /* Pageout */
358 { &vop_blktooff_desc
, (vop_t
*)nfs_blktooff
}, /* blktooff */
359 { &vop_offtoblk_desc
, (vop_t
*)nfs_offtoblk
}, /* offtoblk */
360 { &vop_cmap_desc
, (vop_t
*)nfs_cmap
}, /* cmap */
363 struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc
=
364 { &fifo_nfsv2nodeop_p
, fifo_nfsv2nodeop_entries
};
366 VNODEOP_SET(fifo_nfsv2nodeop_opv_desc
);
369 static int nfs_mknodrpc
__P((struct vnode
*dvp
, struct vnode
**vpp
,
370 struct componentname
*cnp
,
372 static int nfs_removerpc
__P((struct vnode
*dvp
, char *name
, int namelen
,
373 struct ucred
*cred
, struct proc
*proc
));
374 static int nfs_renamerpc
__P((struct vnode
*fdvp
, char *fnameptr
,
375 int fnamelen
, struct vnode
*tdvp
,
376 char *tnameptr
, int tnamelen
,
377 struct ucred
*cred
, struct proc
*proc
));
378 static int nfs_renameit
__P((struct vnode
*sdvp
,
379 struct componentname
*scnp
,
380 struct sillyrename
*sp
));
385 extern u_long nfs_true
, nfs_false
;
386 extern struct nfsstats nfsstats
;
387 extern nfstype nfsv3_type
[9];
388 struct proc
*nfs_iodwant
[NFS_MAXASYNCDAEMON
];
389 struct nfsmount
*nfs_iodmount
[NFS_MAXASYNCDAEMON
];
390 int nfs_numasync
= 0;
391 int nfs_ioddelwri
= 0;
392 #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
394 static int nfsaccess_cache_timeout
= NFS_MAXATTRTIMO
;
395 /* SYSCTL_INT(_vfs_nfs, OID_AUTO, access_cache_timeout, CTLFLAG_RW,
396 &nfsaccess_cache_timeout, 0, "NFS ACCESS cache timeout");
398 #define NFSV3ACCESS_ALL (NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY \
399 | NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE \
400 | NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP)
404 * the following are needed only by nfs_pageout to know how to handle errors
405 * see nfs_pageout comments on explanation of actions.
406 * the errors here are copied from errno.h and errors returned by servers
407 * are expected to match the same numbers here. If not, our actions maybe
410 enum actiontype
{NOACTION
, DUMP
, DUMPANDLOG
, RETRY
, RETRYWITHSLEEP
, SEVER
};
412 static int errorcount
[ELAST
+1]; /* better be zeros when initialized */
414 static const short errortooutcome
[ELAST
+1] = {
416 DUMP
, /* EPERM 1 Operation not permitted */
417 DUMP
, /* ENOENT 2 No such file or directory */
418 DUMPANDLOG
, /* ESRCH 3 No such process */
419 RETRY
, /* EINTR 4 Interrupted system call */
420 DUMP
, /* EIO 5 Input/output error */
421 DUMP
, /* ENXIO 6 Device not configured */
422 DUMPANDLOG
, /* E2BIG 7 Argument list too long */
423 DUMPANDLOG
, /* ENOEXEC 8 Exec format error */
424 DUMPANDLOG
, /* EBADF 9 Bad file descriptor */
425 DUMPANDLOG
, /* ECHILD 10 No child processes */
426 DUMPANDLOG
, /* EDEADLK 11 Resource deadlock avoided - was EAGAIN */
427 RETRY
, /* ENOMEM 12 Cannot allocate memory */
428 DUMP
, /* EACCES 13 Permission denied */
429 DUMPANDLOG
, /* EFAULT 14 Bad address */
430 DUMPANDLOG
, /* ENOTBLK 15 POSIX - Block device required */
431 RETRY
, /* EBUSY 16 Device busy */
432 DUMP
, /* EEXIST 17 File exists */
433 DUMP
, /* EXDEV 18 Cross-device link */
434 DUMP
, /* ENODEV 19 Operation not supported by device */
435 DUMP
, /* ENOTDIR 20 Not a directory */
436 DUMP
, /* EISDIR 21 Is a directory */
437 DUMP
, /* EINVAL 22 Invalid argument */
438 DUMPANDLOG
, /* ENFILE 23 Too many open files in system */
439 DUMPANDLOG
, /* EMFILE 24 Too many open files */
440 DUMPANDLOG
, /* ENOTTY 25 Inappropriate ioctl for device */
441 DUMPANDLOG
, /* ETXTBSY 26 Text file busy - POSIX */
442 DUMP
, /* EFBIG 27 File too large */
443 DUMP
, /* ENOSPC 28 No space left on device */
444 DUMPANDLOG
, /* ESPIPE 29 Illegal seek */
445 DUMP
, /* EROFS 30 Read-only file system */
446 DUMP
, /* EMLINK 31 Too many links */
447 RETRY
, /* EPIPE 32 Broken pipe */
449 DUMPANDLOG
, /* EDOM 33 Numerical argument out of domain */
450 DUMPANDLOG
, /* ERANGE 34 Result too large */
451 RETRY
, /* EAGAIN/EWOULDBLOCK 35 Resource temporarily unavailable */
452 DUMPANDLOG
, /* EINPROGRESS 36 Operation now in progress */
453 DUMPANDLOG
, /* EALREADY 37 Operation already in progress */
454 /* ipc/network software -- argument errors */
455 DUMPANDLOG
, /* ENOTSOC 38 Socket operation on non-socket */
456 DUMPANDLOG
, /* EDESTADDRREQ 39 Destination address required */
457 DUMPANDLOG
, /* EMSGSIZE 40 Message too long */
458 DUMPANDLOG
, /* EPROTOTYPE 41 Protocol wrong type for socket */
459 DUMPANDLOG
, /* ENOPROTOOPT 42 Protocol not available */
460 DUMPANDLOG
, /* EPROTONOSUPPORT 43 Protocol not supported */
461 DUMPANDLOG
, /* ESOCKTNOSUPPORT 44 Socket type not supported */
462 DUMPANDLOG
, /* ENOTSUP 45 Operation not supported */
463 DUMPANDLOG
, /* EPFNOSUPPORT 46 Protocol family not supported */
464 DUMPANDLOG
, /* EAFNOSUPPORT 47 Address family not supported by protocol family */
465 DUMPANDLOG
, /* EADDRINUSE 48 Address already in use */
466 DUMPANDLOG
, /* EADDRNOTAVAIL 49 Can't assign requested address */
467 /* ipc/network software -- operational errors */
468 RETRY
, /* ENETDOWN 50 Network is down */
469 RETRY
, /* ENETUNREACH 51 Network is unreachable */
470 RETRY
, /* ENETRESET 52 Network dropped connection on reset */
471 RETRY
, /* ECONNABORTED 53 Software caused connection abort */
472 RETRY
, /* ECONNRESET 54 Connection reset by peer */
473 RETRY
, /* ENOBUFS 55 No buffer space available */
474 RETRY
, /* EISCONN 56 Socket is already connected */
475 RETRY
, /* ENOTCONN 57 Socket is not connected */
476 RETRY
, /* ESHUTDOWN 58 Can't send after socket shutdown */
477 RETRY
, /* ETOOMANYREFS 59 Too many references: can't splice */
478 RETRY
, /* ETIMEDOUT 60 Operation timed out */
479 RETRY
, /* ECONNREFUSED 61 Connection refused */
481 DUMPANDLOG
, /* ELOOP 62 Too many levels of symbolic links */
482 DUMP
, /* ENAMETOOLONG 63 File name too long */
483 RETRY
, /* EHOSTDOWN 64 Host is down */
484 RETRY
, /* EHOSTUNREACH 65 No route to host */
485 DUMP
, /* ENOTEMPTY 66 Directory not empty */
487 DUMPANDLOG
, /* PROCLIM 67 Too many processes */
488 DUMPANDLOG
, /* EUSERS 68 Too many users */
489 DUMPANDLOG
, /* EDQUOT 69 Disc quota exceeded */
490 /* Network File System */
491 DUMP
, /* ESTALE 70 Stale NFS file handle */
492 DUMP
, /* EREMOTE 71 Too many levels of remote in path */
493 DUMPANDLOG
, /* EBADRPC 72 RPC struct is bad */
494 DUMPANDLOG
, /* ERPCMISMATCH 73 RPC version wrong */
495 DUMPANDLOG
, /* EPROGUNAVAIL 74 RPC prog. not avail */
496 DUMPANDLOG
, /* EPROGMISMATCH 75 Program version wrong */
497 DUMPANDLOG
, /* EPROCUNAVAIL 76 Bad procedure for program */
499 DUMPANDLOG
, /* ENOLCK 77 No locks available */
500 DUMPANDLOG
, /* ENOSYS 78 Function not implemented */
501 DUMPANDLOG
, /* EFTYPE 79 Inappropriate file type or format */
502 DUMPANDLOG
, /* EAUTH 80 Authentication error */
503 DUMPANDLOG
, /* ENEEDAUTH 81 Need authenticator */
504 /* Intelligent device errors */
505 DUMPANDLOG
, /* EPWROFF 82 Device power is off */
506 DUMPANDLOG
, /* EDEVERR 83 Device error, e.g. paper out */
507 DUMPANDLOG
, /* EOVERFLOW 84 Value too large to be stored in data type */
508 /* Program loading errors */
509 DUMPANDLOG
, /* EBADEXEC 85 Bad executable */
510 DUMPANDLOG
, /* EBADARCH 86 Bad CPU type in executable */
511 DUMPANDLOG
, /* ESHLIBVERS 87 Shared library version mismatch */
512 DUMPANDLOG
, /* EBADMACHO 88 Malformed Macho file */
517 nfs_pageouterrorhandler(error
)
523 return(errortooutcome
[error
]);
527 nfs3_access_otw(struct vnode
*vp
,
534 int error
= 0, attrflag
;
536 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
537 caddr_t bpos
, dpos
, cp2
;
538 register long t1
, t2
;
541 struct nfsnode
*np
= VTONFS(vp
);
545 nfsstats
.rpccnt
[NFSPROC_ACCESS
]++;
546 nfsm_reqhead(vp
, NFSPROC_ACCESS
, NFSX_FH(v3
) + NFSX_UNSIGNED
);
548 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
549 *tl
= txdr_unsigned(wmode
);
550 nfsm_request(vp
, NFSPROC_ACCESS
, p
, cred
, &xid
);
552 nfsm_postop_attr(vp
, attrflag
, &xid
);
555 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
556 rmode
= fxdr_unsigned(u_int32_t
, *tl
);
558 np
->n_modeuid
= cred
->cr_uid
;
560 np
->n_modestamp
= now
.tv_sec
;
567 * nfs access vnode op.
568 * For nfs version 2, just return ok. File accesses may fail later.
569 * For nfs version 3, use the access rpc to check accessibility. If file modes
570 * are changed on the server, accesses might still fail later.
574 struct vop_access_args
/* {
577 struct ucred *a_cred;
581 register struct vnode
*vp
= ap
->a_vp
;
584 int v3
= NFS_ISV3(vp
);
585 struct nfsnode
*np
= VTONFS(vp
);
589 * For nfs v3, do an access rpc, otherwise you are stuck emulating
590 * ufs_access() locally using the vattr. This may not be correct,
591 * since the server may apply other access criteria such as
592 * client uid-->server uid mapping that we do not know about, but
593 * this is better than just returning anything that is lying about
597 if (ap
->a_mode
& VREAD
)
598 mode
= NFSV3ACCESS_READ
;
601 if (vp
->v_type
== VDIR
) {
602 if (ap
->a_mode
& VWRITE
)
603 mode
|= NFSV3ACCESS_MODIFY
|
604 NFSV3ACCESS_EXTEND
| NFSV3ACCESS_DELETE
;
605 if (ap
->a_mode
& VEXEC
)
606 mode
|= NFSV3ACCESS_LOOKUP
;
608 if (ap
->a_mode
& VWRITE
)
609 mode
|= NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
;
610 if (ap
->a_mode
& VEXEC
)
611 mode
|= NFSV3ACCESS_EXECUTE
;
613 /* XXX safety belt, only make blanket request if caching */
614 if (nfsaccess_cache_timeout
> 0) {
615 wmode
= NFSV3ACCESS_READ
| NFSV3ACCESS_MODIFY
|
616 NFSV3ACCESS_EXTEND
| NFSV3ACCESS_EXECUTE
|
617 NFSV3ACCESS_DELETE
| NFSV3ACCESS_LOOKUP
;
622 * Does our cached result allow us to give a definite yes to
626 if (now
.tv_sec
< np
->n_modestamp
+ nfsaccess_cache_timeout
&&
627 ap
->a_cred
->cr_uid
== np
->n_modeuid
&&
628 (np
->n_mode
& mode
) == mode
) {
629 /* nfsstats.accesscache_hits++; */
632 * Either a no, or a don't know. Go to the wire.
634 /* nfsstats.accesscache_misses++; */
635 error
= nfs3_access_otw(vp
, wmode
, ap
->a_p
,ap
->a_cred
);
637 if ((np
->n_mode
& mode
) != mode
)
642 return (nfsspec_access(ap
)); /* NFSv2 case checks for EROFS here */
644 * Disallow write attempts on filesystems mounted read-only;
645 * unless the file is a socket, fifo, or a block or character
646 * device resident on the filesystem.
647 * CSM - moved EROFS check down per NetBSD rev 1.71. So you
648 * get the correct error value with layered filesystems.
649 * EKN - moved the return(error) below this so it does get called.
651 if (!error
&& (ap
->a_mode
& VWRITE
) && (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
652 switch (vp
->v_type
) {
653 case VREG
: case VDIR
: case VLNK
:
664 * Check to see if the type is ok
665 * and that deletion is not in progress.
666 * For paged in text files, you will need to flush the page cache
667 * if consistency is lost.
673 struct vop_open_args
/* {
676 struct ucred *a_cred;
680 register struct vnode
*vp
= ap
->a_vp
;
681 struct nfsnode
*np
= VTONFS(vp
);
682 struct nfsmount
*nmp
= VFSTONFS(vp
->v_mount
);
686 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VDIR
&& vp
->v_type
!= VLNK
) {
690 * Get a valid lease. If cached data is stale, flush it.
692 if (nmp
->nm_flag
& NFSMNT_NQNFS
) {
693 if (NQNFS_CKINVALID(vp
, np
, ND_READ
)) {
695 error
= nqnfs_getlease(vp
, ND_READ
, ap
->a_cred
,
697 } while (error
== NQNFS_EXPIRED
);
700 if (np
->n_lrev
!= np
->n_brev
||
701 (np
->n_flag
& NQNFSNONCACHE
)) {
702 if ((error
= nfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
,
703 ap
->a_p
, 1)) == EINTR
)
705 np
->n_brev
= np
->n_lrev
;
709 if (np
->n_flag
& NMODIFIED
) {
710 if ((error
= nfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
,
711 ap
->a_p
, 1)) == EINTR
)
714 if (vp
->v_type
== VDIR
)
715 np
->n_direofoffset
= 0;
716 error
= VOP_GETATTR(vp
, &vattr
, ap
->a_cred
, ap
->a_p
);
719 if (vp
->v_type
== VDIR
) {
720 /* if directory changed, purge any name cache entries */
721 if (np
->n_ncmtime
!= vattr
.va_mtime
.tv_sec
)
723 np
->n_ncmtime
= vattr
.va_mtime
.tv_sec
;
725 np
->n_mtime
= vattr
.va_mtime
.tv_sec
;
727 error
= VOP_GETATTR(vp
, &vattr
, ap
->a_cred
, ap
->a_p
);
730 if (np
->n_mtime
!= vattr
.va_mtime
.tv_sec
) {
731 if (vp
->v_type
== VDIR
) {
732 np
->n_direofoffset
= 0;
734 /* purge name cache entries */
735 if (np
->n_ncmtime
!= vattr
.va_mtime
.tv_sec
)
738 if ((error
= nfs_vinvalbuf(vp
, V_SAVE
,
739 ap
->a_cred
, ap
->a_p
, 1)) == EINTR
)
741 if (vp
->v_type
== VDIR
)
742 np
->n_ncmtime
= vattr
.va_mtime
.tv_sec
;
743 np
->n_mtime
= vattr
.va_mtime
.tv_sec
;
747 if ((nmp
->nm_flag
& NFSMNT_NQNFS
) == 0)
748 np
->n_xid
= 0; /* For Open/Close consistency */
754 * What an NFS client should do upon close after writing is a debatable issue.
755 * Most NFS clients push delayed writes to the server upon close, basically for
757 * 1 - So that any write errors may be reported back to the client process
758 * doing the close system call. By far the two most likely errors are
759 * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure.
760 * 2 - To put a worst case upper bound on cache inconsistency between
761 * multiple clients for the file.
762 * There is also a consistency problem for Version 2 of the protocol w.r.t.
763 * not being able to tell if other clients are writing a file concurrently,
764 * since there is no way of knowing if the changed modify time in the reply
765 * is only due to the write for this client.
766 * (NFS Version 3 provides weak cache consistency data in the reply that
767 * should be sufficient to detect and handle this case.)
769 * The current code does the following:
770 * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
771 * for NFS Version 3 - flush dirty buffers to the server but don't invalidate
773 * for NQNFS - do nothing now, since 2 is dealt with via leases and
774 * 1 should be dealt with via an fsync() system call for
775 * cases where write errors are important.
780 struct vop_close_args
/* {
781 struct vnodeop_desc *a_desc;
784 struct ucred *a_cred;
788 register struct vnode
*vp
= ap
->a_vp
;
789 register struct nfsnode
*np
= VTONFS(vp
);
790 struct nfsmount
*nmp
;
793 if (vp
->v_type
== VREG
) {
795 register struct sillyrename
*sp
= np
->n_sillyrename
;
797 kprintf("nfs_close: %s, dvp=%x, vp=%x, ap=%x, np=%x, sp=%x\n",
798 &sp
->s_name
[0], (unsigned)(sp
->s_dvp
), (unsigned)vp
,
799 (unsigned)ap
, (unsigned)np
, (unsigned)sp
);
801 nmp
= VFSTONFS(vp
->v_mount
);
804 if ((nmp
->nm_flag
& NFSMNT_NQNFS
) == 0 &&
805 (np
->n_flag
& NMODIFIED
)) {
806 int getlock
= !VOP_ISLOCKED(vp
);
808 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, ap
->a_p
);
809 if (!error
&& !VFSTONFS(vp
->v_mount
)) {
810 VOP_UNLOCK(vp
, 0, ap
->a_p
);
817 error
= nfs_flush(vp
, ap
->a_cred
, MNT_WAIT
, ap
->a_p
);
819 * We cannot clear the NMODIFIED bit in np->n_flag due to
820 * potential races with other processes
821 * NMODIFIED is a hint
823 /* np->n_flag &= ~NMODIFIED; */
825 error
= nfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
, ap
->a_p
, 1);
829 VOP_UNLOCK(vp
, 0, ap
->a_p
);
831 if (np
->n_flag
& NWRITEERR
) {
832 np
->n_flag
&= ~NWRITEERR
;
840 * nfs getattr call from vfs.
844 struct vop_getattr_args
/* {
847 struct ucred *a_cred;
851 register struct vnode
*vp
= ap
->a_vp
;
852 register struct nfsnode
*np
= VTONFS(vp
);
858 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
863 FSDBG_TOP(513, np
->n_size
, np
, np
->n_vattr
.va_size
, np
->n_flag
);
865 * Update local times for special files.
867 if (np
->n_flag
& (NACC
| NUPD
))
870 * First look in the cache.
872 if ((error
= nfs_getattrcache(vp
, ap
->a_vap
)) == 0) {
873 FSDBG_BOT(513, np
->n_size
, 0, np
->n_vattr
.va_size
, np
->n_flag
);
876 if (error
!= ENOENT
) {
877 FSDBG_BOT(513, np
->n_size
, error
, np
->n_vattr
.va_size
,
882 if (!VFSTONFS(vp
->v_mount
)) {
883 FSDBG_BOT(513, np
->n_size
, ENXIO
, np
->n_vattr
.va_size
, np
->n_flag
);
889 if (v3
&& nfsaccess_cache_timeout
> 0) {
890 /* nfsstats.accesscache_misses++; */
891 if (error
= nfs3_access_otw(vp
, NFSV3ACCESS_ALL
, ap
->a_p
,
894 if ((error
= nfs_getattrcache(vp
, ap
->a_vap
)) == 0)
902 nfsstats
.rpccnt
[NFSPROC_GETATTR
]++;
903 nfsm_reqhead(vp
, NFSPROC_GETATTR
, NFSX_FH(v3
));
905 nfsm_request(vp
, NFSPROC_GETATTR
, ap
->a_p
, ap
->a_cred
, &xid
);
907 nfsm_loadattr(vp
, ap
->a_vap
, &xid
);
908 if (!xid
) { /* out-of-order rpc - attributes were dropped */
911 FSDBG(513, -1, np
, np
->n_xid
<< 32, np
->n_xid
);
912 if (avoidfloods
++ < 100)
915 * avoidfloods>1 is bizarre. at 100 pull the plug
917 panic("nfs_getattr: getattr flood\n");
919 if (np
->n_mtime
!= ap
->a_vap
->va_mtime
.tv_sec
) {
920 FSDBG(513, -1, np
, -1, vp
);
921 if (vp
->v_type
== VDIR
) {
923 /* purge name cache entries */
924 if (np
->n_ncmtime
!= ap
->a_vap
->va_mtime
.tv_sec
)
927 error
= nfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
,
929 FSDBG(513, -1, np
, -2, error
);
931 if (vp
->v_type
== VDIR
)
932 np
->n_ncmtime
= ap
->a_vap
->va_mtime
.tv_sec
;
933 np
->n_mtime
= ap
->a_vap
->va_mtime
.tv_sec
;
939 FSDBG_BOT(513, np
->n_size
, -1, np
->n_vattr
.va_size
, error
);
948 struct vop_setattr_args
/* {
949 struct vnodeop_desc *a_desc;
952 struct ucred *a_cred;
956 register struct vnode
*vp
= ap
->a_vp
;
957 register struct nfsnode
*np
= VTONFS(vp
);
958 register struct vattr
*vap
= ap
->a_vap
;
966 #ifdef XXX /* enable this code soon! (but test it first) */
968 * Setting of flags is not supported.
970 if (vap
->va_flags
!= VNOVAL
)
975 * Disallow write attempts if the filesystem is mounted read-only.
977 if ((vap
->va_flags
!= VNOVAL
|| vap
->va_uid
!= (uid_t
)VNOVAL
||
978 vap
->va_gid
!= (gid_t
)VNOVAL
|| vap
->va_atime
.tv_sec
!= VNOVAL
||
979 vap
->va_mtime
.tv_sec
!= VNOVAL
|| vap
->va_mode
!= (mode_t
)VNOVAL
) &&
980 (vp
->v_mount
->mnt_flag
& MNT_RDONLY
))
982 if (vap
->va_size
!= VNOVAL
) {
983 switch (vp
->v_type
) {
990 if (vap
->va_mtime
.tv_sec
== VNOVAL
&&
991 vap
->va_atime
.tv_sec
== VNOVAL
&&
992 vap
->va_mode
== (u_short
)VNOVAL
&&
993 vap
->va_uid
== (uid_t
)VNOVAL
&&
994 vap
->va_gid
== (gid_t
)VNOVAL
)
996 vap
->va_size
= VNOVAL
;
1000 * Disallow write attempts if the filesystem is
1001 * mounted read-only.
1003 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1005 FSDBG_TOP(512, np
->n_size
, vap
->va_size
,
1006 np
->n_vattr
.va_size
, np
->n_flag
);
1007 if (np
->n_flag
& NMODIFIED
) {
1008 if (vap
->va_size
== 0)
1009 error
= nfs_vinvalbuf(vp
, 0,
1010 ap
->a_cred
, ap
->a_p
, 1);
1012 error
= nfs_vinvalbuf(vp
, V_SAVE
,
1013 ap
->a_cred
, ap
->a_p
, 1);
1015 printf("nfs_setattr: nfs_vinvalbuf %d\n", error
);
1016 FSDBG_BOT(512, np
->n_size
, vap
->va_size
,
1017 np
->n_vattr
.va_size
, -1);
1020 } else if (np
->n_size
> vap
->va_size
) { /* shrinking? */
1025 biosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
1026 obn
= (np
->n_size
- 1) / biosize
;
1027 bn
= vap
->va_size
/ biosize
;
1028 for ( ; obn
>= bn
; obn
--)
1029 if (nfs_buf_incore(vp
, obn
)) {
1030 bp
= nfs_buf_get(vp
, obn
, biosize
, 0, BLK_READ
);
1034 int neweofoff
, mustwrite
;
1036 neweofoff
= vap
->va_size
- NBOFF(bp
);
1037 /* check for any dirty data before the new EOF */
1038 if (bp
->nb_dirtyend
&& bp
->nb_dirtyoff
< neweofoff
) {
1039 /* clip dirty range to EOF */
1040 if (bp
->nb_dirtyend
> neweofoff
)
1041 bp
->nb_dirtyend
= neweofoff
;
1044 bp
->nb_dirty
&= (1 << round_page_32(neweofoff
)/PAGE_SIZE
) - 1;
1048 /* gotta write out dirty data before invalidating */
1049 /* (NB_STABLE indicates that data writes should be FILESYNC) */
1050 /* (NB_NOCACHE indicates buffer should be discarded) */
1051 CLR(bp
->nb_flags
, (NB_DONE
| NB_ERROR
| NB_INVAL
| NB_ASYNC
| NB_READ
));
1052 SET(bp
->nb_flags
, NB_STABLE
| NB_NOCACHE
);
1054 * NFS has embedded ucred so crhold() risks zone corruption
1056 if (bp
->nb_wcred
== NOCRED
)
1057 bp
->nb_wcred
= crdup(ap
->a_cred
);
1058 error
= nfs_buf_write(bp
);
1059 // Note: bp has been released
1061 FSDBG(512, bp
, 0xd00dee, 0xbad, error
);
1062 np
->n_error
= error
;
1063 np
->n_flag
|= NWRITEERR
;
1070 FSDBG(512, bp
, bp
->nb_flags
, 0, obn
);
1071 SET(bp
->nb_flags
, NB_INVAL
);
1072 nfs_buf_release(bp
, 1);
1077 np
->n_size
= np
->n_vattr
.va_size
= vap
->va_size
;
1078 ubc_setsize(vp
, (off_t
)vap
->va_size
); /* XXX error? */
1080 } else if ((vap
->va_mtime
.tv_sec
!= VNOVAL
||
1081 vap
->va_atime
.tv_sec
!= VNOVAL
) &&
1082 (np
->n_flag
& NMODIFIED
) && vp
->v_type
== VREG
) {
1083 error
= nfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
, ap
->a_p
, 1);
1087 error
= nfs_setattrrpc(vp
, vap
, ap
->a_cred
, ap
->a_p
);
1088 FSDBG_BOT(512, np
->n_size
, vap
->va_size
, np
->n_vattr
.va_size
, error
);
1089 if (error
&& vap
->va_size
!= VNOVAL
) {
1090 /* make every effort to resync file size w/ server... */
1091 int err
= 0; /* preserve "error" for return */
1093 printf("nfs_setattr: nfs_setattrrpc %d\n", error
);
1094 np
->n_size
= np
->n_vattr
.va_size
= tsize
;
1095 ubc_setsize(vp
, (off_t
)np
->n_size
); /* XXX check error */
1096 vap
->va_size
= tsize
;
1097 err
= nfs_setattrrpc(vp
, vap
, ap
->a_cred
, ap
->a_p
);
1099 printf("nfs_setattr1: nfs_setattrrpc %d\n", err
);
1105 * Do an nfs setattr rpc.
1108 nfs_setattrrpc(vp
, vap
, cred
, procp
)
1109 register struct vnode
*vp
;
1110 register struct vattr
*vap
;
1114 register struct nfsv2_sattr
*sp
;
1115 register caddr_t cp
;
1116 register long t1
, t2
;
1117 caddr_t bpos
, dpos
, cp2
;
1119 int error
= 0, wccpostattr
= 0;
1120 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1125 if (!VFSTONFS(vp
->v_mount
))
1129 nfsstats
.rpccnt
[NFSPROC_SETATTR
]++;
1130 nfsm_reqhead(vp
, NFSPROC_SETATTR
, NFSX_FH(v3
) + NFSX_SATTR(v3
));
1133 if (vap
->va_mode
!= (u_short
)VNOVAL
) {
1134 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1136 *tl
= txdr_unsigned(vap
->va_mode
);
1138 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1141 if (vap
->va_uid
!= (uid_t
)VNOVAL
) {
1142 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1144 *tl
= txdr_unsigned(vap
->va_uid
);
1146 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1149 if (vap
->va_gid
!= (gid_t
)VNOVAL
) {
1150 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1152 *tl
= txdr_unsigned(vap
->va_gid
);
1154 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1157 if (vap
->va_size
!= VNOVAL
) {
1158 nfsm_build(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
1160 txdr_hyper(&vap
->va_size
, tl
);
1162 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1166 if (vap
->va_atime
.tv_sec
!= VNOVAL
) {
1167 if (vap
->va_atime
.tv_sec
!= now
.tv_sec
) {
1168 nfsm_build(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
1169 *tl
++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT
);
1170 txdr_nfsv3time(&vap
->va_atime
, tl
);
1172 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1173 *tl
= txdr_unsigned(NFSV3SATTRTIME_TOSERVER
);
1176 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1177 *tl
= txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE
);
1179 if (vap
->va_mtime
.tv_sec
!= VNOVAL
) {
1180 if (vap
->va_mtime
.tv_sec
!= now
.tv_sec
) {
1181 nfsm_build(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
1182 *tl
++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT
);
1183 txdr_nfsv3time(&vap
->va_mtime
, tl
);
1185 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1186 *tl
= txdr_unsigned(NFSV3SATTRTIME_TOSERVER
);
1189 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1190 *tl
= txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE
);
1192 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1195 nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1196 if (vap
->va_mode
== (u_short
)VNOVAL
)
1197 sp
->sa_mode
= VNOVAL
;
1199 sp
->sa_mode
= vtonfsv2_mode(vp
->v_type
, vap
->va_mode
);
1200 if (vap
->va_uid
== (uid_t
)VNOVAL
)
1201 sp
->sa_uid
= VNOVAL
;
1203 sp
->sa_uid
= txdr_unsigned(vap
->va_uid
);
1204 if (vap
->va_gid
== (gid_t
)VNOVAL
)
1205 sp
->sa_gid
= VNOVAL
;
1207 sp
->sa_gid
= txdr_unsigned(vap
->va_gid
);
1208 sp
->sa_size
= txdr_unsigned(vap
->va_size
);
1209 txdr_nfsv2time(&vap
->va_atime
, &sp
->sa_atime
);
1210 txdr_nfsv2time(&vap
->va_mtime
, &sp
->sa_mtime
);
1212 nfsm_request(vp
, NFSPROC_SETATTR
, procp
, cred
, &xid
);
1214 time_t premtime
= 0;
1216 nfsm_wcc_data(vp
, premtime
, wccpostattr
, &xid
);
1218 /* if file hadn't changed, update cached mtime */
1219 if (VTONFS(vp
)->n_mtime
== premtime
) {
1220 VTONFS(vp
)->n_mtime
= VTONFS(vp
)->n_vattr
.va_mtime
.tv_sec
;
1222 /* if directory hadn't changed, update namecache mtime */
1223 if ((vp
->v_type
== VDIR
) && (VTONFS(vp
)->n_ncmtime
== premtime
)) {
1224 VTONFS(vp
)->n_ncmtime
= VTONFS(vp
)->n_vattr
.va_mtime
.tv_sec
;
1227 VTONFS(vp
)->n_xid
= 0;
1230 nfsm_loadattr(vp
, (struct vattr
*)0, &xid
);
1238 * nfs lookup call, one step at a time...
1239 * First look in cache
1240 * If not found, unlock the directory nfsnode and do the rpc
1244 struct vop_lookup_args
/* {
1245 struct vnodeop_desc *a_desc;
1246 struct vnode *a_dvp;
1247 struct vnode **a_vpp;
1248 struct componentname *a_cnp;
1251 register struct componentname
*cnp
= ap
->a_cnp
;
1252 register struct vnode
*dvp
= ap
->a_dvp
;
1253 register struct vnode
**vpp
= ap
->a_vpp
;
1254 register int flags
= cnp
->cn_flags
;
1255 register struct vnode
*newvp
;
1256 register u_long
*tl
;
1257 register caddr_t cp
;
1258 register long t1
, t2
;
1259 caddr_t bpos
, dpos
, cp2
;
1260 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1264 int lockparent
, wantparent
, error
= 0, attrflag
, fhsize
;
1265 int v3
= NFS_ISV3(dvp
);
1266 struct proc
*p
= cnp
->cn_proc
;
1271 if ((flags
& ISLASTCN
) && (dvp
->v_mount
->mnt_flag
& MNT_RDONLY
) &&
1272 (cnp
->cn_nameiop
== DELETE
|| cnp
->cn_nameiop
== RENAME
))
1275 if (dvp
->v_type
!= VDIR
)
1278 lockparent
= flags
& LOCKPARENT
;
1279 wantparent
= flags
& (LOCKPARENT
|WANTPARENT
);
1282 if (!VOP_GETATTR(dvp
, &vattr
, cnp
->cn_cred
, p
) &&
1283 (np
->n_ncmtime
!= vattr
.va_mtime
.tv_sec
)) {
1285 * This directory has changed on us.
1286 * Purge any name cache entries.
1289 np
->n_ncmtime
= vattr
.va_mtime
.tv_sec
;
1292 if ((error
= cache_lookup(dvp
, vpp
, cnp
)) && error
!= ENOENT
) {
1299 * See the comment starting `Step through' in ufs/ufs_lookup.c
1300 * for an explanation of the locking protocol
1304 * Note: we need to make sure to get a lock/ref on newvp
1305 * before we possibly go off to the server in VOP_ACCESS.
1310 } else if (flags
& ISDOTDOT
) {
1311 VOP_UNLOCK(dvp
, 0, p
);
1312 error
= vget(newvp
, LK_EXCLUSIVE
, p
);
1314 error
= vn_lock(dvp
, LK_EXCLUSIVE
, p
);
1316 error
= vget(newvp
, LK_EXCLUSIVE
, p
);
1318 VOP_UNLOCK(dvp
, 0, p
);
1322 goto cache_lookup_out
;
1324 if ((error
= VOP_ACCESS(dvp
, VEXEC
, cnp
->cn_cred
, p
))) {
1333 if ((dvp
!= newvp
) && (!lockparent
|| !(flags
& ISLASTCN
)))
1334 VOP_UNLOCK(dvp
, 0, p
);
1336 if (vpid
== newvp
->v_id
) {
1337 nfsstats
.lookupcache_hits
++;
1338 if (cnp
->cn_nameiop
!= LOOKUP
&& (flags
& ISLASTCN
))
1339 cnp
->cn_flags
|= SAVENAME
;
1340 error
= 0; /* ignore any from VOP_GETATTR */
1344 if ((dvp
!= newvp
) && lockparent
&& (flags
& ISLASTCN
))
1345 VOP_UNLOCK(dvp
, 0, p
);
1347 error
= vn_lock(dvp
, LK_EXCLUSIVE
, p
);
1355 nfsstats
.lookupcache_misses
++;
1356 nfsstats
.rpccnt
[NFSPROC_LOOKUP
]++;
1357 len
= cnp
->cn_namelen
;
1358 nfsm_reqhead(dvp
, NFSPROC_LOOKUP
,
1359 NFSX_FH(v3
) + NFSX_UNSIGNED
+ nfsm_rndup(len
));
1360 nfsm_fhtom(dvp
, v3
);
1361 nfsm_strtom(cnp
->cn_nameptr
, len
, NFS_MAXNAMLEN
);
1362 /* nfsm_request for NFSv2 causes you to goto to nfsmout upon errors */
1363 nfsm_request(dvp
, NFSPROC_LOOKUP
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
1367 nfsm_postop_attr(dvp
, attrflag
, &xid
);
1372 nfsm_getfh(fhp
, fhsize
, v3
);
1375 * Handle RENAME case...
1377 if (cnp
->cn_nameiop
== RENAME
&& wantparent
&& (flags
& ISLASTCN
)) {
1378 if (NFS_CMPFH(np
, fhp
, fhsize
)) {
1383 if ((error
= nfs_nget(dvp
->v_mount
, fhp
, fhsize
, &np
))) {
1389 u_int64_t dxid
= xid
;
1391 nfsm_postop_attr(newvp
, attrflag
, &xid
);
1392 nfsm_postop_attr(dvp
, attrflag
, &dxid
);
1393 if (np
->n_xid
== 0) {
1395 * VFS currently requires that we have valid
1396 * attributes when returning success.
1398 error
= VOP_GETATTR(newvp
, &vattr
, cnp
->cn_cred
, p
);
1406 nfsm_loadattr(newvp
, (struct vattr
*)0, &xid
);
1409 cnp
->cn_flags
|= SAVENAME
;
1411 VOP_UNLOCK(dvp
, 0, p
);
1416 if (NFS_CMPFH(np
, fhp
, fhsize
)) {
1419 } else if (flags
& ISDOTDOT
) {
1420 VOP_UNLOCK(dvp
, 0, p
);
1421 error
= nfs_nget(dvp
->v_mount
, fhp
, fhsize
, &np
);
1424 vn_lock(dvp
, LK_EXCLUSIVE
+ LK_RETRY
, p
);
1428 if (!lockparent
|| !(flags
& ISLASTCN
))
1429 unlockdvp
= 1; /* keep dvp locked until after postops */
1430 if (error
= vn_lock(dvp
, LK_EXCLUSIVE
, p
)) {
1436 if ((error
= nfs_nget(dvp
->v_mount
, fhp
, fhsize
, &np
))) {
1440 if (!lockparent
|| !(flags
& ISLASTCN
))
1441 unlockdvp
= 1; /* keep dvp locked until after postops */
1445 u_int64_t dxid
= xid
;
1447 nfsm_postop_attr(newvp
, attrflag
, &xid
);
1448 nfsm_postop_attr(dvp
, attrflag
, &dxid
);
1449 if (np
->n_xid
== 0) {
1451 * VFS currently requires that we have valid
1452 * attributes when returning success.
1454 error
= VOP_GETATTR(newvp
, &vattr
, cnp
->cn_cred
, p
);
1457 VOP_UNLOCK(dvp
, 0, p
);
1464 nfsm_loadattr(newvp
, (struct vattr
*)0, &xid
);
1465 if (cnp
->cn_nameiop
!= LOOKUP
&& (flags
& ISLASTCN
))
1466 cnp
->cn_flags
|= SAVENAME
;
1467 if ((cnp
->cn_flags
& MAKEENTRY
) &&
1468 (cnp
->cn_nameiop
!= DELETE
|| !(flags
& ISLASTCN
))) {
1469 cache_enter(dvp
, newvp
, cnp
);
1474 VOP_UNLOCK(dvp
, 0, p
);
1476 if (newvp
!= NULLVP
) {
1483 if ((cnp
->cn_nameiop
== CREATE
|| cnp
->cn_nameiop
== RENAME
) &&
1484 (flags
& ISLASTCN
) && error
== ENOENT
) {
1485 if (dvp
->v_mount
&& (dvp
->v_mount
->mnt_flag
& MNT_RDONLY
))
1488 error
= EJUSTRETURN
;
1490 VOP_UNLOCK(dvp
, 0, p
);
1492 if (cnp
->cn_nameiop
!= LOOKUP
&& (flags
& ISLASTCN
))
1493 cnp
->cn_flags
|= SAVENAME
;
1501 * Just call nfs_bioread() to do the work.
1505 struct vop_read_args
/* {
1509 struct ucred *a_cred;
1512 register struct vnode
*vp
= ap
->a_vp
;
1514 if (vp
->v_type
!= VREG
)
1516 return (nfs_bioread(vp
, ap
->a_uio
, ap
->a_ioflag
, ap
->a_cred
, 0));
1525 struct vop_readlink_args
/* {
1528 struct ucred *a_cred;
1531 register struct vnode
*vp
= ap
->a_vp
;
1533 if (vp
->v_type
!= VLNK
)
1535 return (nfs_bioread(vp
, ap
->a_uio
, 0, ap
->a_cred
, 0));
1539 * Do a readlink rpc.
1540 * Called by nfs_doio() from below the buffer cache.
1543 nfs_readlinkrpc(vp
, uiop
, cred
)
1544 register struct vnode
*vp
;
1548 register u_long
*tl
;
1549 register caddr_t cp
;
1550 register long t1
, t2
;
1551 caddr_t bpos
, dpos
, cp2
;
1552 int error
= 0, len
, attrflag
;
1553 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1557 if (!VFSTONFS(vp
->v_mount
))
1561 nfsstats
.rpccnt
[NFSPROC_READLINK
]++;
1562 nfsm_reqhead(vp
, NFSPROC_READLINK
, NFSX_FH(v3
));
1564 nfsm_request(vp
, NFSPROC_READLINK
, uiop
->uio_procp
, cred
, &xid
);
1566 nfsm_postop_attr(vp
, attrflag
, &xid
);
1568 nfsm_strsiz(len
, NFS_MAXPATHLEN
);
1569 if (len
== NFS_MAXPATHLEN
) {
1570 struct nfsnode
*np
= VTONFS(vp
);
1573 panic("nfs_readlinkrpc: null np");
1575 if (np
->n_size
&& np
->n_size
< NFS_MAXPATHLEN
)
1578 nfsm_mtouio(uiop
, len
);
1589 nfs_readrpc(vp
, uiop
, cred
)
1590 register struct vnode
*vp
;
1594 register u_long
*tl
;
1595 register caddr_t cp
;
1596 register long t1
, t2
;
1597 caddr_t bpos
, dpos
, cp2
;
1598 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1599 struct nfsmount
*nmp
;
1600 int error
= 0, len
, retlen
, tsiz
, eof
= 0, attrflag
;
1604 FSDBG_TOP(536, vp
, uiop
->uio_offset
, uiop
->uio_resid
, 0);
1605 nmp
= VFSTONFS(vp
->v_mount
);
1609 nmrsize
= nmp
->nm_rsize
;
1611 tsiz
= uiop
->uio_resid
;
1612 if (((u_int64_t
)uiop
->uio_offset
+ (unsigned int)tsiz
> 0xffffffff) && !v3
) {
1613 FSDBG_BOT(536, vp
, uiop
->uio_offset
, uiop
->uio_resid
, EFBIG
);
1617 nfsstats
.rpccnt
[NFSPROC_READ
]++;
1618 len
= (tsiz
> nmrsize
) ? nmrsize
: tsiz
;
1619 nfsm_reqhead(vp
, NFSPROC_READ
, NFSX_FH(v3
) + NFSX_UNSIGNED
* 3);
1621 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
* 3);
1623 txdr_hyper(&uiop
->uio_offset
, tl
);
1624 *(tl
+ 2) = txdr_unsigned(len
);
1626 *tl
++ = txdr_unsigned(uiop
->uio_offset
);
1627 *tl
++ = txdr_unsigned(len
);
1630 FSDBG(536, vp
, uiop
->uio_offset
, len
, 0);
1631 nfsm_request(vp
, NFSPROC_READ
, uiop
->uio_procp
, cred
, &xid
);
1634 nfsm_postop_attr(vp
, attrflag
, &xid
);
1640 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1641 eof
= fxdr_unsigned(int, *(tl
+ 1));
1644 nfsm_loadattr(vp
, (struct vattr
*)0, &xid
);
1648 nfsm_strsiz(retlen
, nmrsize
);
1649 nfsm_mtouio(uiop
, retlen
);
1656 if (eof
|| retlen
== 0)
1658 } else if (retlen
< len
)
1662 FSDBG_BOT(536, vp
, eof
, uiop
->uio_resid
, error
);
1670 nfs_writerpc(vp
, uiop
, cred
, iomode
, must_commit
)
1671 register struct vnode
*vp
;
1672 register struct uio
*uiop
;
1674 int *iomode
, *must_commit
;
1676 register u_long
*tl
;
1677 register caddr_t cp
;
1678 register int t1
, t2
, backup
;
1679 caddr_t bpos
, dpos
, cp2
;
1680 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1681 struct nfsmount
*nmp
;
1682 int error
= 0, len
, tsiz
, updatemtime
= 0, wccpostattr
= 0, rlen
, commit
;
1683 int v3
, committed
= NFSV3WRITE_FILESYNC
;
1687 if (uiop
->uio_iovcnt
!= 1)
1688 panic("nfs_writerpc: iovcnt > 1");
1690 FSDBG_TOP(537, vp
, uiop
->uio_offset
, uiop
->uio_resid
, *iomode
);
1691 nmp
= VFSTONFS(vp
->v_mount
);
1696 tsiz
= uiop
->uio_resid
;
1697 if (((u_int64_t
)uiop
->uio_offset
+ (unsigned int)tsiz
> 0xffffffff) && !v3
) {
1698 FSDBG_BOT(537, vp
, uiop
->uio_offset
, uiop
->uio_resid
, EFBIG
);
1702 nmp
= VFSTONFS(vp
->v_mount
);
1707 nfsstats
.rpccnt
[NFSPROC_WRITE
]++;
1708 len
= (tsiz
> nmp
->nm_wsize
) ? nmp
->nm_wsize
: tsiz
;
1709 nfsm_reqhead(vp
, NFSPROC_WRITE
,
1710 NFSX_FH(v3
) + 5 * NFSX_UNSIGNED
+ nfsm_rndup(len
));
1713 nfsm_build(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1714 txdr_hyper(&uiop
->uio_offset
, tl
);
1716 *tl
++ = txdr_unsigned(len
);
1717 *tl
++ = txdr_unsigned(*iomode
);
1719 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1720 *++tl
= txdr_unsigned(uiop
->uio_offset
);
1723 *tl
= txdr_unsigned(len
);
1724 FSDBG(537, vp
, uiop
->uio_offset
, len
, 0);
1725 nfsm_uiotom(uiop
, len
);
1726 nfsm_request(vp
, NFSPROC_WRITE
, uiop
->uio_procp
, cred
, &xid
);
1727 nmp
= VFSTONFS(vp
->v_mount
);
1733 nfsm_wcc_data(vp
, premtime
, wccpostattr
, &xid
);
1734 if (VTONFS(vp
)->n_mtime
== premtime
)
1738 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
+
1740 rlen
= fxdr_unsigned(int, *tl
++);
1744 } else if (rlen
< len
) {
1745 backup
= len
- rlen
;
1746 uiop
->uio_iov
->iov_base
-= backup
;
1747 uiop
->uio_iov
->iov_len
+= backup
;
1748 uiop
->uio_offset
-= backup
;
1749 uiop
->uio_resid
+= backup
;
1752 commit
= fxdr_unsigned(int, *tl
++);
1755 * Return the lowest committment level
1756 * obtained by any of the RPCs.
1758 if (committed
== NFSV3WRITE_FILESYNC
)
1760 else if (committed
== NFSV3WRITE_DATASYNC
&&
1761 commit
== NFSV3WRITE_UNSTABLE
)
1763 if ((nmp
->nm_state
& NFSSTA_HASWRITEVERF
) == 0) {
1764 bcopy((caddr_t
)tl
, (caddr_t
)nmp
->nm_verf
,
1766 nmp
->nm_state
|= NFSSTA_HASWRITEVERF
;
1767 } else if (bcmp((caddr_t
)tl
,
1768 (caddr_t
)nmp
->nm_verf
, NFSX_V3WRITEVERF
)) {
1770 bcopy((caddr_t
)tl
, (caddr_t
)nmp
->nm_verf
,
1776 nfsm_loadattr(vp
, (struct vattr
*)0, &xid
);
1781 VTONFS(vp
)->n_mtime
= VTONFS(vp
)->n_vattr
.va_mtime
.tv_sec
;
1784 * we seem to have a case where we end up looping on shutdown
1785 * and taking down nfs servers. For V3, error cases, there is
1786 * no way to terminate loop, if the len was 0, meaning,
1787 * nmp->nm_wsize was trashed. FreeBSD has this fix in it.
1795 if (vp
->v_mount
&& (vp
->v_mount
->mnt_flag
& MNT_ASYNC
))
1796 committed
= NFSV3WRITE_FILESYNC
;
1797 *iomode
= committed
;
1799 uiop
->uio_resid
= tsiz
;
1800 FSDBG_BOT(537, vp
, committed
, uiop
->uio_resid
, error
);
1806 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1807 * mode set to specify the file type and the size field for rdev.
1810 nfs_mknodrpc(dvp
, vpp
, cnp
, vap
)
1811 register struct vnode
*dvp
;
1812 register struct vnode
**vpp
;
1813 register struct componentname
*cnp
;
1814 register struct vattr
*vap
;
1816 register struct nfsv2_sattr
*sp
;
1817 register struct nfsv3_sattr
*sp3
;
1818 register u_long
*tl
;
1819 register caddr_t cp
;
1820 register long t1
, t2
;
1821 struct vnode
*newvp
= (struct vnode
*)0;
1822 struct nfsnode
*np
= (struct nfsnode
*)0;
1826 int error
= 0, wccpostattr
= 0, gotvp
= 0;
1827 time_t premtime
= 0;
1828 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1831 int v3
= NFS_ISV3(dvp
);
1833 if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
)
1834 rdev
= txdr_unsigned(vap
->va_rdev
);
1835 else if (vap
->va_type
== VFIFO
|| vap
->va_type
== VSOCK
)
1838 VOP_ABORTOP(dvp
, cnp
);
1840 return (EOPNOTSUPP
);
1842 if ((error
= VOP_GETATTR(dvp
, &vattr
, cnp
->cn_cred
, cnp
->cn_proc
))) {
1843 VOP_ABORTOP(dvp
, cnp
);
1847 nfsstats
.rpccnt
[NFSPROC_MKNOD
]++;
1848 nfsm_reqhead(dvp
, NFSPROC_MKNOD
, NFSX_FH(v3
) + 4 * NFSX_UNSIGNED
+
1849 + nfsm_rndup(cnp
->cn_namelen
) + NFSX_SATTR(v3
));
1850 nfsm_fhtom(dvp
, v3
);
1851 nfsm_strtom(cnp
->cn_nameptr
, cnp
->cn_namelen
, NFS_MAXNAMLEN
);
1853 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
+ NFSX_V3SRVSATTR
);
1854 *tl
++ = vtonfsv3_type(vap
->va_type
);
1855 sp3
= (struct nfsv3_sattr
*)tl
;
1856 nfsm_v3sattr(sp3
, vap
, cnp
->cn_cred
->cr_uid
, vattr
.va_gid
);
1857 if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
) {
1858 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1859 *tl
++ = txdr_unsigned(major(vap
->va_rdev
));
1860 *tl
= txdr_unsigned(minor(vap
->va_rdev
));
1863 nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1864 sp
->sa_mode
= vtonfsv2_mode(vap
->va_type
, vap
->va_mode
);
1865 sp
->sa_uid
= txdr_unsigned(cnp
->cn_cred
->cr_uid
);
1866 sp
->sa_gid
= txdr_unsigned(vattr
.va_gid
);
1868 txdr_nfsv2time(&vap
->va_atime
, &sp
->sa_atime
);
1869 txdr_nfsv2time(&vap
->va_mtime
, &sp
->sa_mtime
);
1871 nfsm_request(dvp
, NFSPROC_MKNOD
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
1873 nfsm_mtofh(dvp
, newvp
, v3
, gotvp
, &xid
);
1877 newvp
= (struct vnode
*)0;
1879 error
= nfs_lookitup(dvp
, cnp
->cn_nameptr
,
1880 cnp
->cn_namelen
, cnp
->cn_cred
, cnp
->cn_proc
, &np
);
1886 nfsm_wcc_data(dvp
, premtime
, wccpostattr
, &xid
);
1892 if (cnp
->cn_flags
& MAKEENTRY
)
1893 cache_enter(dvp
, newvp
, cnp
);
1896 VTONFS(dvp
)->n_flag
|= NMODIFIED
;
1897 /* if directory hadn't changed, update namecache mtime */
1898 if (VTONFS(dvp
)->n_ncmtime
== premtime
)
1899 VTONFS(dvp
)->n_ncmtime
= VTONFS(dvp
)->n_vattr
.va_mtime
.tv_sec
;
1901 VTONFS(dvp
)->n_xid
= 0;
1903 NFS_FREE_PNBUF(cnp
);
1909 * just call nfs_mknodrpc() to do the work.
1914 struct vop_mknod_args
/* {
1915 struct vnode *a_dvp;
1916 struct vnode **a_vpp;
1917 struct componentname *a_cnp;
1918 struct vattr *a_vap;
1921 struct vnode
*newvp
;
1924 error
= nfs_mknodrpc(ap
->a_dvp
, &newvp
, ap
->a_cnp
, ap
->a_vap
);
1925 if (!error
&& newvp
)
1931 static u_long create_verf
;
1933 * nfs file create call
1937 struct vop_create_args
/* {
1938 struct vnode *a_dvp;
1939 struct vnode **a_vpp;
1940 struct componentname *a_cnp;
1941 struct vattr *a_vap;
1944 register struct vnode
*dvp
= ap
->a_dvp
;
1945 register struct vattr
*vap
= ap
->a_vap
;
1946 register struct componentname
*cnp
= ap
->a_cnp
;
1947 register struct nfsv2_sattr
*sp
;
1948 register struct nfsv3_sattr
*sp3
;
1949 register u_long
*tl
;
1950 register caddr_t cp
;
1951 register long t1
, t2
;
1952 struct nfsnode
*np
= (struct nfsnode
*)0;
1953 struct vnode
*newvp
= (struct vnode
*)0;
1954 caddr_t bpos
, dpos
, cp2
;
1955 int error
= 0, wccpostattr
= 0, gotvp
= 0, fmode
= 0;
1956 time_t premtime
= 0;
1957 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1959 int v3
= NFS_ISV3(dvp
);
1963 * Oops, not for me..
1965 if (vap
->va_type
== VSOCK
)
1966 return (nfs_mknodrpc(dvp
, ap
->a_vpp
, cnp
, vap
));
1968 if ((error
= VOP_GETATTR(dvp
, &vattr
, cnp
->cn_cred
, cnp
->cn_proc
))) {
1969 VOP_ABORTOP(dvp
, cnp
);
1973 if (vap
->va_vaflags
& VA_EXCLUSIVE
)
1976 nfsstats
.rpccnt
[NFSPROC_CREATE
]++;
1977 nfsm_reqhead(dvp
, NFSPROC_CREATE
, NFSX_FH(v3
) + 2 * NFSX_UNSIGNED
+
1978 nfsm_rndup(cnp
->cn_namelen
) + NFSX_SATTR(v3
));
1979 nfsm_fhtom(dvp
, v3
);
1980 nfsm_strtom(cnp
->cn_nameptr
, cnp
->cn_namelen
, NFS_MAXNAMLEN
);
1982 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1983 if (fmode
& O_EXCL
) {
1984 *tl
= txdr_unsigned(NFSV3CREATE_EXCLUSIVE
);
1985 nfsm_build(tl
, u_long
*, NFSX_V3CREATEVERF
);
1986 if (!TAILQ_EMPTY(&in_ifaddrhead
))
1987 *tl
++ = IA_SIN(in_ifaddrhead
.tqh_first
)->sin_addr
.s_addr
;
1989 *tl
++ = create_verf
;
1990 *tl
= ++create_verf
;
1992 *tl
= txdr_unsigned(NFSV3CREATE_UNCHECKED
);
1993 nfsm_build(tl
, u_long
*, NFSX_V3SRVSATTR
);
1994 sp3
= (struct nfsv3_sattr
*)tl
;
1995 nfsm_v3sattr(sp3
, vap
, cnp
->cn_cred
->cr_uid
, vattr
.va_gid
);
1998 nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1999 sp
->sa_mode
= vtonfsv2_mode(vap
->va_type
, vap
->va_mode
);
2000 sp
->sa_uid
= txdr_unsigned(cnp
->cn_cred
->cr_uid
);
2001 sp
->sa_gid
= txdr_unsigned(vattr
.va_gid
);
2003 txdr_nfsv2time(&vap
->va_atime
, &sp
->sa_atime
);
2004 txdr_nfsv2time(&vap
->va_mtime
, &sp
->sa_mtime
);
2006 nfsm_request(dvp
, NFSPROC_CREATE
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
2008 nfsm_mtofh(dvp
, newvp
, v3
, gotvp
, &xid
);
2012 newvp
= (struct vnode
*)0;
2014 error
= nfs_lookitup(dvp
, cnp
->cn_nameptr
,
2015 cnp
->cn_namelen
, cnp
->cn_cred
, cnp
->cn_proc
, &np
);
2021 nfsm_wcc_data(dvp
, premtime
, wccpostattr
, &xid
);
2024 if (v3
&& (fmode
& O_EXCL
) && error
== NFSERR_NOTSUPP
) {
2030 } else if (v3
&& (fmode
& O_EXCL
)) {
2031 error
= nfs_setattrrpc(newvp
, vap
, cnp
->cn_cred
, cnp
->cn_proc
);
2036 if (cnp
->cn_flags
& MAKEENTRY
)
2037 cache_enter(dvp
, newvp
, cnp
);
2040 VTONFS(dvp
)->n_flag
|= NMODIFIED
;
2041 /* if directory hadn't changed, update namecache mtime */
2042 if (VTONFS(dvp
)->n_ncmtime
== premtime
)
2043 VTONFS(dvp
)->n_ncmtime
= VTONFS(dvp
)->n_vattr
.va_mtime
.tv_sec
;
2045 VTONFS(dvp
)->n_xid
= 0;
2047 NFS_FREE_PNBUF(cnp
);
2052 * nfs file remove call
2053 * To try and make nfs semantics closer to ufs semantics, a file that has
2054 * other processes using the vnode is renamed instead of removed and then
2055 * removed later on the last close.
2056 * - If v_usecount > 1
2057 * If a rename is not already in the works
2058 * call nfs_sillyrename() to set it up
2064 struct vop_remove_args
/* {
2065 struct vnodeop_desc *a_desc;
2066 struct vnode * a_dvp;
2067 struct vnode * a_vp;
2068 struct componentname * a_cnp;
2071 register struct vnode
*vp
= ap
->a_vp
;
2072 register struct vnode
*dvp
= ap
->a_dvp
;
2073 register struct componentname
*cnp
= ap
->a_cnp
;
2074 register struct nfsnode
*np
= VTONFS(vp
);
2075 int error
= 0, gofree
= 0;
2079 if ((cnp
->cn_flags
& HASBUF
) == 0)
2080 panic("nfs_remove: no name");
2081 if (vp
->v_usecount
< 1)
2082 panic("nfs_remove: bad v_usecount");
2085 if (UBCISVALID(vp
)) {
2087 if (UBCINFOEXISTS(vp
))
2088 gofree
= (ubc_isinuse(vp
, 1)) ? 0 : 1;
2090 /* dead or dying vnode.With vnode locking panic instead of error */
2093 NFS_FREE_PNBUF(cnp
);
2097 /* UBC not in play */
2098 if (vp
->v_usecount
== 1)
2101 if ((ap
->a_cnp
->cn_flags
& NODELETEBUSY
) && !gofree
) {
2102 /* Caller requested Carbon delete semantics, but file is busy */
2105 NFS_FREE_PNBUF(cnp
);
2108 if (gofree
|| (np
->n_sillyrename
&&
2109 VOP_GETATTR(vp
, &vattr
, cnp
->cn_cred
, cnp
->cn_proc
) == 0 &&
2110 vattr
.va_nlink
> 1)) {
2112 * Purge the name cache so that the chance of a lookup for
2113 * the name succeeding while the remove is in progress is
2118 * throw away biocache buffers, mainly to avoid
2119 * unnecessary delayed writes later.
2121 error
= nfs_vinvalbuf(vp
, 0, cnp
->cn_cred
, cnp
->cn_proc
, 1);
2123 ubc_setsize(vp
, (off_t
)0); /* XXX check error */
2126 error
= nfs_removerpc(dvp
, cnp
->cn_nameptr
,
2127 cnp
->cn_namelen
, cnp
->cn_cred
, cnp
->cn_proc
);
2129 * Kludge City: If the first reply to the remove rpc is lost..
2130 * the reply to the retransmitted request will be ENOENT
2131 * since the file was in fact removed
2132 * Therefore, we cheat and return success.
2134 if (error
== ENOENT
)
2138 * remove nfsnode from hash now so we can't accidentally find it
2139 * again if another object gets created with the same filehandle
2140 * before this vnode gets reclaimed
2142 LIST_REMOVE(np
, n_hash
);
2143 np
->n_flag
&= ~NHASHED
;
2145 } else if (!np
->n_sillyrename
) {
2146 error
= nfs_sillyrename(dvp
, vp
, cnp
);
2151 VOP_UNLOCK(vp
, 0, cnp
->cn_proc
);
2152 NFS_FREE_PNBUF(cnp
);
2160 * nfs file remove rpc called from nfs_inactive
2164 register struct sillyrename
*sp
;
2167 return (nfs_removerpc(sp
->s_dvp
, sp
->s_name
, sp
->s_namlen
, sp
->s_cred
,
2172 * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
2175 nfs_removerpc(dvp
, name
, namelen
, cred
, proc
)
2176 register struct vnode
*dvp
;
2182 register u_long
*tl
;
2183 register caddr_t cp
;
2184 register long t1
, t2
;
2185 caddr_t bpos
, dpos
, cp2
;
2186 int error
= 0, wccpostattr
= 0;
2187 time_t premtime
= 0;
2188 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2192 if (!VFSTONFS(dvp
->v_mount
))
2196 nfsstats
.rpccnt
[NFSPROC_REMOVE
]++;
2197 nfsm_reqhead(dvp
, NFSPROC_REMOVE
,
2198 NFSX_FH(v3
) + NFSX_UNSIGNED
+ nfsm_rndup(namelen
));
2199 nfsm_fhtom(dvp
, v3
);
2200 nfsm_strtom(name
, namelen
, NFS_MAXNAMLEN
);
2201 nfsm_request(dvp
, NFSPROC_REMOVE
, proc
, cred
, &xid
);
2203 nfsm_wcc_data(dvp
, premtime
, wccpostattr
, &xid
);
2205 VTONFS(dvp
)->n_flag
|= NMODIFIED
;
2206 /* if directory hadn't changed, update namecache mtime */
2207 if (VTONFS(dvp
)->n_ncmtime
== premtime
)
2208 VTONFS(dvp
)->n_ncmtime
= VTONFS(dvp
)->n_vattr
.va_mtime
.tv_sec
;
2210 VTONFS(dvp
)->n_xid
= 0;
2215 * nfs file rename call
2219 struct vop_rename_args
/* {
2220 struct vnode *a_fdvp;
2221 struct vnode *a_fvp;
2222 struct componentname *a_fcnp;
2223 struct vnode *a_tdvp;
2224 struct vnode *a_tvp;
2225 struct componentname *a_tcnp;
2228 register struct vnode
*fvp
= ap
->a_fvp
;
2229 register struct vnode
*tvp
= ap
->a_tvp
;
2230 register struct vnode
*fdvp
= ap
->a_fdvp
;
2231 register struct vnode
*tdvp
= ap
->a_tdvp
;
2232 register struct componentname
*tcnp
= ap
->a_tcnp
;
2233 register struct componentname
*fcnp
= ap
->a_fcnp
;
2237 if ((tcnp
->cn_flags
& HASBUF
) == 0 ||
2238 (fcnp
->cn_flags
& HASBUF
) == 0)
2239 panic("nfs_rename: no name");
2241 /* Check for cross-device rename */
2242 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
2243 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
2246 VOP_UNLOCK(tvp
, 0, tcnp
->cn_proc
);
2251 * If the tvp exists and is in use, sillyrename it before doing the
2252 * rename of the new file over it.
2253 * XXX Can't sillyrename a directory.
2254 * Don't sillyrename if source and target are same vnode (hard
2255 * links or case-variants)
2257 if (tvp
&& tvp
!= fvp
) {
2258 if (UBCISVALID(tvp
)) {
2260 if (UBCINFOEXISTS(tvp
))
2261 inuse
= (ubc_isinuse(tvp
, 1)) ? 1 : 0;
2263 /* dead or dying vnode.With vnode locking panic instead of error */
2265 VOP_UNLOCK(tvp
, 0, tcnp
->cn_proc
);
2269 /* UBC not in play */
2270 if (tvp
->v_usecount
> 1)
2274 if (inuse
&& !VTONFS(tvp
)->n_sillyrename
&& tvp
->v_type
!= VDIR
) {
2275 if (error
= nfs_sillyrename(tdvp
, tvp
, tcnp
)) {
2276 /* sillyrename failed. Instead of pressing on, return error */
2277 VOP_UNLOCK(tvp
, 0, tcnp
->cn_proc
);
2278 goto out
; /* should not be ENOENT. */
2280 /* sillyrename succeeded.*/
2281 VOP_UNLOCK(tvp
, 0, tcnp
->cn_proc
);
2282 ubc_uncache(tvp
); /* get the nfs turd file to disappear */
2288 error
= nfs_renamerpc(fdvp
, fcnp
->cn_nameptr
, fcnp
->cn_namelen
,
2289 tdvp
, tcnp
->cn_nameptr
, tcnp
->cn_namelen
, tcnp
->cn_cred
,
2292 if (!error
&& tvp
&& tvp
!= fvp
&& !VTONFS(tvp
)->n_sillyrename
) {
2294 * remove nfsnode from hash now so we can't accidentally find it
2295 * again if another object gets created with the same filehandle
2296 * before this vnode gets reclaimed
2298 LIST_REMOVE(VTONFS(tvp
), n_hash
);
2299 VTONFS(tvp
)->n_flag
&= ~NHASHED
;
2305 VOP_UNLOCK(tvp
, 0, tcnp
->cn_proc
);
2306 ubc_uncache(tvp
); /* get the nfs turd file to disappear */
2315 vrele(tvp
); /* already unlocked */
2319 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
2321 if (error
== ENOENT
)
2327 * nfs file rename rpc called from nfs_remove() above
2330 nfs_renameit(sdvp
, scnp
, sp
)
2332 struct componentname
*scnp
;
2333 register struct sillyrename
*sp
;
2335 return (nfs_renamerpc(sdvp
, scnp
->cn_nameptr
, scnp
->cn_namelen
,
2336 sdvp
, sp
->s_name
, sp
->s_namlen
, scnp
->cn_cred
, scnp
->cn_proc
));
2340 * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
2343 nfs_renamerpc(fdvp
, fnameptr
, fnamelen
, tdvp
, tnameptr
, tnamelen
, cred
, proc
)
2344 register struct vnode
*fdvp
;
2347 register struct vnode
*tdvp
;
2353 register u_long
*tl
;
2354 register caddr_t cp
;
2355 register long t1
, t2
;
2356 caddr_t bpos
, dpos
, cp2
;
2357 int error
= 0, fwccpostattr
= 0, twccpostattr
= 0;
2358 time_t fpremtime
= 0, tpremtime
= 0;
2359 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2363 if (!VFSTONFS(fdvp
->v_mount
))
2365 v3
= NFS_ISV3(fdvp
);
2367 nfsstats
.rpccnt
[NFSPROC_RENAME
]++;
2368 nfsm_reqhead(fdvp
, NFSPROC_RENAME
,
2369 (NFSX_FH(v3
) + NFSX_UNSIGNED
)*2 + nfsm_rndup(fnamelen
) +
2370 nfsm_rndup(tnamelen
));
2371 nfsm_fhtom(fdvp
, v3
);
2372 nfsm_strtom(fnameptr
, fnamelen
, NFS_MAXNAMLEN
);
2373 nfsm_fhtom(tdvp
, v3
);
2374 nfsm_strtom(tnameptr
, tnamelen
, NFS_MAXNAMLEN
);
2375 nfsm_request(fdvp
, NFSPROC_RENAME
, proc
, cred
, &xid
);
2377 u_int64_t txid
= xid
;
2379 nfsm_wcc_data(fdvp
, fpremtime
, fwccpostattr
, &xid
);
2380 nfsm_wcc_data(tdvp
, tpremtime
, twccpostattr
, &txid
);
2383 VTONFS(fdvp
)->n_flag
|= NMODIFIED
;
2384 /* if directory hadn't changed, update namecache mtime */
2385 if (VTONFS(fdvp
)->n_ncmtime
== fpremtime
)
2386 VTONFS(fdvp
)->n_ncmtime
= VTONFS(fdvp
)->n_vattr
.va_mtime
.tv_sec
;
2388 VTONFS(fdvp
)->n_xid
= 0;
2389 VTONFS(tdvp
)->n_flag
|= NMODIFIED
;
2390 /* if directory hadn't changed, update namecache mtime */
2391 if (VTONFS(tdvp
)->n_ncmtime
== tpremtime
)
2392 VTONFS(tdvp
)->n_ncmtime
= VTONFS(tdvp
)->n_vattr
.va_mtime
.tv_sec
;
2394 VTONFS(tdvp
)->n_xid
= 0;
2399 * nfs hard link create call
2403 struct vop_link_args
/* {
2405 struct vnode *a_tdvp;
2406 struct componentname *a_cnp;
2409 register struct vnode
*vp
= ap
->a_vp
;
2410 register struct vnode
*tdvp
= ap
->a_tdvp
;
2411 register struct componentname
*cnp
= ap
->a_cnp
;
2412 register u_long
*tl
;
2413 register caddr_t cp
;
2414 register long t1
, t2
;
2415 caddr_t bpos
, dpos
, cp2
;
2416 int error
= 0, wccpostattr
= 0, attrflag
= 0;
2417 time_t premtime
= 0;
2418 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2422 if (vp
->v_mount
!= tdvp
->v_mount
) {
2423 VOP_ABORTOP(vp
, cnp
);
2428 /* need to get vnode lock for vp before calling VOP_FSYNC() */
2429 if (error
= vn_lock(vp
, LK_EXCLUSIVE
, cnp
->cn_proc
)) {
2430 VOP_ABORTOP(vp
, cnp
);
2435 if (!VFSTONFS(vp
->v_mount
)) {
2436 VOP_UNLOCK(vp
, 0, cnp
->cn_proc
);
2437 VOP_ABORTOP(vp
, cnp
);
2444 * Push all writes to the server, so that the attribute cache
2445 * doesn't get "out of sync" with the server.
2446 * XXX There should be a better way!
2448 didhold
= ubc_hold(vp
);
2449 VOP_FSYNC(vp
, cnp
->cn_cred
, MNT_WAIT
, cnp
->cn_proc
);
2450 VOP_UNLOCK(vp
, 0, cnp
->cn_proc
);
2452 nfsstats
.rpccnt
[NFSPROC_LINK
]++;
2453 nfsm_reqhead(vp
, NFSPROC_LINK
,
2454 NFSX_FH(v3
)*2 + NFSX_UNSIGNED
+ nfsm_rndup(cnp
->cn_namelen
));
2456 nfsm_fhtom(tdvp
, v3
);
2457 nfsm_strtom(cnp
->cn_nameptr
, cnp
->cn_namelen
, NFS_MAXNAMLEN
);
2458 nfsm_request(vp
, NFSPROC_LINK
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
2460 u_int64_t txid
= xid
;
2462 nfsm_postop_attr(vp
, attrflag
, &xid
);
2463 nfsm_wcc_data(tdvp
, premtime
, wccpostattr
, &txid
);
2467 VTONFS(tdvp
)->n_flag
|= NMODIFIED
;
2469 VTONFS(vp
)->n_xid
= 0;
2470 /* if directory hadn't changed, update namecache mtime */
2471 if (VTONFS(tdvp
)->n_ncmtime
== premtime
)
2472 VTONFS(tdvp
)->n_ncmtime
= VTONFS(tdvp
)->n_vattr
.va_mtime
.tv_sec
;
2474 VTONFS(tdvp
)->n_xid
= 0;
2478 NFS_FREE_PNBUF(cnp
);
2480 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2482 if (error
== EEXIST
)
2488 * nfs symbolic link create call
2492 struct vop_symlink_args
/* {
2493 struct vnode *a_dvp;
2494 struct vnode **a_vpp;
2495 struct componentname *a_cnp;
2496 struct vattr *a_vap;
2500 register struct vnode
*dvp
= ap
->a_dvp
;
2501 register struct vattr
*vap
= ap
->a_vap
;
2502 register struct componentname
*cnp
= ap
->a_cnp
;
2503 register struct nfsv2_sattr
*sp
;
2504 register struct nfsv3_sattr
*sp3
;
2505 register u_long
*tl
;
2506 register caddr_t cp
;
2507 register long t1
, t2
;
2508 caddr_t bpos
, dpos
, cp2
;
2509 int slen
, error
= 0, wccpostattr
= 0, gotvp
;
2510 time_t premtime
= 0;
2511 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2512 struct vnode
*newvp
= (struct vnode
*)0;
2513 int v3
= NFS_ISV3(dvp
);
2516 nfsstats
.rpccnt
[NFSPROC_SYMLINK
]++;
2517 slen
= strlen(ap
->a_target
);
2518 nfsm_reqhead(dvp
, NFSPROC_SYMLINK
, NFSX_FH(v3
) + 2*NFSX_UNSIGNED
+
2519 nfsm_rndup(cnp
->cn_namelen
) + nfsm_rndup(slen
) + NFSX_SATTR(v3
));
2520 nfsm_fhtom(dvp
, v3
);
2521 nfsm_strtom(cnp
->cn_nameptr
, cnp
->cn_namelen
, NFS_MAXNAMLEN
);
2523 nfsm_build(sp3
, struct nfsv3_sattr
*, NFSX_V3SRVSATTR
);
2524 nfsm_v3sattr(sp3
, vap
, cnp
->cn_cred
->cr_uid
,
2525 cnp
->cn_cred
->cr_gid
);
2527 nfsm_strtom(ap
->a_target
, slen
, NFS_MAXPATHLEN
);
2529 nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2530 sp
->sa_mode
= vtonfsv2_mode(VLNK
, vap
->va_mode
);
2531 sp
->sa_uid
= txdr_unsigned(cnp
->cn_cred
->cr_uid
);
2532 sp
->sa_gid
= txdr_unsigned(cnp
->cn_cred
->cr_gid
);
2534 txdr_nfsv2time(&vap
->va_atime
, &sp
->sa_atime
);
2535 txdr_nfsv2time(&vap
->va_mtime
, &sp
->sa_mtime
);
2537 nfsm_request(dvp
, NFSPROC_SYMLINK
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
2539 u_int64_t dxid
= xid
;
2542 nfsm_mtofh(dvp
, newvp
, v3
, gotvp
, &xid
);
2543 nfsm_wcc_data(dvp
, premtime
, wccpostattr
, &dxid
);
2549 VTONFS(dvp
)->n_flag
|= NMODIFIED
;
2550 /* if directory hadn't changed, update namecache mtime */
2551 if (VTONFS(dvp
)->n_ncmtime
== premtime
)
2552 VTONFS(dvp
)->n_ncmtime
= VTONFS(dvp
)->n_vattr
.va_mtime
.tv_sec
;
2554 VTONFS(dvp
)->n_xid
= 0;
2556 NFS_FREE_PNBUF(cnp
);
2558 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2560 if (error
== EEXIST
)
2570 struct vop_mkdir_args
/* {
2571 struct vnode *a_dvp;
2572 struct vnode **a_vpp;
2573 struct componentname *a_cnp;
2574 struct vattr *a_vap;
2577 register struct vnode
*dvp
= ap
->a_dvp
;
2578 register struct vattr
*vap
= ap
->a_vap
;
2579 register struct componentname
*cnp
= ap
->a_cnp
;
2580 register struct nfsv2_sattr
*sp
;
2581 register struct nfsv3_sattr
*sp3
;
2582 register u_long
*tl
;
2583 register caddr_t cp
;
2584 register long t1
, t2
;
2586 struct nfsnode
*np
= (struct nfsnode
*)0;
2587 struct vnode
*newvp
= (struct vnode
*)0;
2588 caddr_t bpos
, dpos
, cp2
;
2589 int error
= 0, wccpostattr
= 0;
2590 time_t premtime
= 0;
2592 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2594 int v3
= NFS_ISV3(dvp
);
2595 u_int64_t xid
, dxid
;
2597 if ((error
= VOP_GETATTR(dvp
, &vattr
, cnp
->cn_cred
, cnp
->cn_proc
))) {
2598 VOP_ABORTOP(dvp
, cnp
);
2602 len
= cnp
->cn_namelen
;
2603 nfsstats
.rpccnt
[NFSPROC_MKDIR
]++;
2604 nfsm_reqhead(dvp
, NFSPROC_MKDIR
,
2605 NFSX_FH(v3
) + NFSX_UNSIGNED
+ nfsm_rndup(len
) + NFSX_SATTR(v3
));
2606 nfsm_fhtom(dvp
, v3
);
2607 nfsm_strtom(cnp
->cn_nameptr
, len
, NFS_MAXNAMLEN
);
2609 nfsm_build(sp3
, struct nfsv3_sattr
*, NFSX_V3SRVSATTR
);
2610 nfsm_v3sattr(sp3
, vap
, cnp
->cn_cred
->cr_uid
, vattr
.va_gid
);
2612 nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2613 sp
->sa_mode
= vtonfsv2_mode(VDIR
, vap
->va_mode
);
2614 sp
->sa_uid
= txdr_unsigned(cnp
->cn_cred
->cr_uid
);
2615 sp
->sa_gid
= txdr_unsigned(vattr
.va_gid
);
2617 txdr_nfsv2time(&vap
->va_atime
, &sp
->sa_atime
);
2618 txdr_nfsv2time(&vap
->va_mtime
, &sp
->sa_mtime
);
2620 nfsm_request(dvp
, NFSPROC_MKDIR
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
2623 nfsm_mtofh(dvp
, newvp
, v3
, gotvp
, &xid
);
2625 nfsm_wcc_data(dvp
, premtime
, wccpostattr
, &dxid
);
2627 VTONFS(dvp
)->n_flag
|= NMODIFIED
;
2628 /* if directory hadn't changed, update namecache mtime */
2629 if (VTONFS(dvp
)->n_ncmtime
== premtime
)
2630 VTONFS(dvp
)->n_ncmtime
= VTONFS(dvp
)->n_vattr
.va_mtime
.tv_sec
;
2632 VTONFS(dvp
)->n_xid
= 0;
2634 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
2635 * if we can succeed in looking up the directory.
2637 if (error
== EEXIST
|| (!error
&& !gotvp
)) {
2640 newvp
= (struct vnode
*)0;
2642 error
= nfs_lookitup(dvp
, cnp
->cn_nameptr
, len
, cnp
->cn_cred
,
2646 if (newvp
->v_type
!= VDIR
)
2654 if (cnp
->cn_flags
& MAKEENTRY
)
2655 cache_enter(dvp
, newvp
, cnp
);
2659 NFS_FREE_PNBUF(cnp
);
2664 * nfs remove directory call
2668 struct vop_rmdir_args
/* {
2669 struct vnode *a_dvp;
2671 struct componentname *a_cnp;
2674 register struct vnode
*vp
= ap
->a_vp
;
2675 register struct vnode
*dvp
= ap
->a_dvp
;
2676 register struct componentname
*cnp
= ap
->a_cnp
;
2677 register u_long
*tl
;
2678 register caddr_t cp
;
2679 register long t1
, t2
;
2680 caddr_t bpos
, dpos
, cp2
;
2681 int error
= 0, wccpostattr
= 0;
2682 time_t premtime
= 0;
2683 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2684 int v3
= NFS_ISV3(dvp
);
2687 nfsstats
.rpccnt
[NFSPROC_RMDIR
]++;
2688 nfsm_reqhead(dvp
, NFSPROC_RMDIR
,
2689 NFSX_FH(v3
) + NFSX_UNSIGNED
+ nfsm_rndup(cnp
->cn_namelen
));
2690 nfsm_fhtom(dvp
, v3
);
2691 nfsm_strtom(cnp
->cn_nameptr
, cnp
->cn_namelen
, NFS_MAXNAMLEN
);
2692 nfsm_request(dvp
, NFSPROC_RMDIR
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
2694 nfsm_wcc_data(dvp
, premtime
, wccpostattr
, &xid
);
2696 VTONFS(dvp
)->n_flag
|= NMODIFIED
;
2697 /* if directory hadn't changed, update namecache mtime */
2698 if (VTONFS(dvp
)->n_ncmtime
== premtime
)
2699 VTONFS(dvp
)->n_ncmtime
= VTONFS(dvp
)->n_vattr
.va_mtime
.tv_sec
;
2701 VTONFS(dvp
)->n_xid
= 0;
2704 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2706 if (error
== ENOENT
)
2710 * remove nfsnode from hash now so we can't accidentally find it
2711 * again if another object gets created with the same filehandle
2712 * before this vnode gets reclaimed
2714 LIST_REMOVE(VTONFS(vp
), n_hash
);
2715 VTONFS(vp
)->n_flag
&= ~NHASHED
;
2719 NFS_FREE_PNBUF(cnp
);
2728 struct vop_readdir_args
/* {
2731 struct ucred *a_cred;
2734 register struct vnode
*vp
= ap
->a_vp
;
2735 register struct nfsnode
*np
= VTONFS(vp
);
2736 register struct uio
*uio
= ap
->a_uio
;
2740 if (vp
->v_type
!= VDIR
)
2743 * First, check for hit on the EOF offset cache
2745 if (np
->n_direofoffset
> 0 && uio
->uio_offset
>= np
->n_direofoffset
&&
2746 (np
->n_flag
& NMODIFIED
) == 0) {
2747 if (VFSTONFS(vp
->v_mount
)->nm_flag
& NFSMNT_NQNFS
) {
2748 if (NQNFS_CKCACHABLE(vp
, ND_READ
)) {
2749 nfsstats
.direofcache_hits
++;
2752 } else if (!VOP_GETATTR(vp
, &vattr
, ap
->a_cred
, uio
->uio_procp
)) {
2753 if (np
->n_mtime
== vattr
.va_mtime
.tv_sec
) {
2754 nfsstats
.direofcache_hits
++;
2757 if (np
->n_ncmtime
!= vattr
.va_mtime
.tv_sec
) {
2758 /* directory changed, purge any name cache entries */
2765 * Call nfs_bioread() to do the real work.
2767 tresid
= uio
->uio_resid
;
2768 error
= nfs_bioread(vp
, uio
, 0, ap
->a_cred
, 0);
2770 if (!error
&& uio
->uio_resid
== tresid
)
2771 nfsstats
.direofcache_misses
++;
2777 * Called from below the buffer cache by nfs_doio().
2780 nfs_readdirrpc(vp
, uiop
, cred
)
2782 register struct uio
*uiop
;
2786 register int len
, left
;
2787 register struct dirent
*dp
;
2788 register u_long
*tl
;
2789 register caddr_t cp
;
2790 register long t1
, t2
;
2791 register nfsuint64
*cookiep
;
2792 caddr_t bpos
, dpos
, cp2
;
2793 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2795 struct nfsmount
*nmp
;
2796 struct nfsnode
*dnp
= VTONFS(vp
);
2798 int error
= 0, tlen
, more_dirs
= 1, blksiz
= 0, bigenough
= 1;
2800 int v3
, nmreaddirsize
;
2804 dp
= (struct dirent
*)0;
2807 if (uiop
->uio_iovcnt
!= 1 || (uiop
->uio_offset
& (NFS_DIRBLKSIZ
- 1)) ||
2808 (uiop
->uio_resid
& (NFS_DIRBLKSIZ
- 1)))
2809 panic("nfs_readdirrpc: bad uio");
2811 nmp
= VFSTONFS(vp
->v_mount
);
2815 nmreaddirsize
= nmp
->nm_readdirsize
;
2818 * If there is no cookie, assume directory was stale.
2820 cookiep
= nfs_getcookie(dnp
, uiop
->uio_offset
, 0);
2824 return (NFSERR_BAD_COOKIE
);
2826 * Loop around doing readdir rpc's of size nm_readdirsize
2827 * truncated to a multiple of DIRBLKSIZ.
2828 * The stopping criteria is EOF or buffer full.
2830 while (more_dirs
&& bigenough
) {
2831 nfsstats
.rpccnt
[NFSPROC_READDIR
]++;
2832 nfsm_reqhead(vp
, NFSPROC_READDIR
, NFSX_FH(v3
) +
2836 nfsm_build(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
2837 *tl
++ = cookie
.nfsuquad
[0];
2838 *tl
++ = cookie
.nfsuquad
[1];
2839 *tl
++ = dnp
->n_cookieverf
.nfsuquad
[0];
2840 *tl
++ = dnp
->n_cookieverf
.nfsuquad
[1];
2842 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2843 *tl
++ = cookie
.nfsuquad
[0];
2845 *tl
= txdr_unsigned(nmreaddirsize
);
2846 nfsm_request(vp
, NFSPROC_READDIR
, uiop
->uio_procp
, cred
, &xid
);
2849 nfsm_postop_attr(vp
, attrflag
, &xid
);
2852 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2853 dnp
->n_cookieverf
.nfsuquad
[0] = *tl
++;
2854 dnp
->n_cookieverf
.nfsuquad
[1] = *tl
;
2860 // XXX assert error?
2863 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
2864 more_dirs
= fxdr_unsigned(int, *tl
);
2866 /* loop thru the dir entries, doctoring them to 4bsd form */
2867 while (more_dirs
&& bigenough
) {
2869 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
2870 fxdr_hyper(tl
, &fileno
);
2871 len
= fxdr_unsigned(int, *(tl
+ 2));
2873 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2874 fileno
= fxdr_unsigned(u_quad_t
, *tl
++);
2875 len
= fxdr_unsigned(int, *tl
);
2877 if (len
<= 0 || len
> NFS_MAXNAMLEN
) {
2882 tlen
= nfsm_rndup(len
);
2884 tlen
+= 4; /* To ensure null termination */
2885 left
= DIRBLKSIZ
- blksiz
;
2886 if ((tlen
+ DIRHDSIZ
) > left
) {
2887 dp
->d_reclen
+= left
;
2888 uiop
->uio_iov
->iov_base
+= left
;
2889 uiop
->uio_iov
->iov_len
-= left
;
2890 uiop
->uio_offset
+= left
;
2891 uiop
->uio_resid
-= left
;
2894 if ((tlen
+ DIRHDSIZ
) > uiop
->uio_resid
)
2897 dp
= (struct dirent
*)uiop
->uio_iov
->iov_base
;
2898 dp
->d_fileno
= (int)fileno
;
2900 dp
->d_reclen
= tlen
+ DIRHDSIZ
;
2901 dp
->d_type
= DT_UNKNOWN
;
2902 blksiz
+= dp
->d_reclen
;
2903 if (blksiz
== DIRBLKSIZ
)
2905 uiop
->uio_offset
+= DIRHDSIZ
;
2906 uiop
->uio_resid
-= DIRHDSIZ
;
2907 uiop
->uio_iov
->iov_base
+= DIRHDSIZ
;
2908 uiop
->uio_iov
->iov_len
-= DIRHDSIZ
;
2909 nfsm_mtouio(uiop
, len
);
2910 cp
= uiop
->uio_iov
->iov_base
;
2912 *cp
= '\0'; /* null terminate */
2913 uiop
->uio_iov
->iov_base
+= tlen
;
2914 uiop
->uio_iov
->iov_len
-= tlen
;
2915 uiop
->uio_offset
+= tlen
;
2916 uiop
->uio_resid
-= tlen
;
2918 nfsm_adv(nfsm_rndup(len
));
2920 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
2922 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2925 cookie
.nfsuquad
[0] = *tl
++;
2927 cookie
.nfsuquad
[1] = *tl
++;
2932 more_dirs
= fxdr_unsigned(int, *tl
);
2935 * If at end of rpc data, get the eof boolean
2938 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
2939 more_dirs
= (fxdr_unsigned(int, *tl
) == 0);
2944 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
2945 * by increasing d_reclen for the last record.
2948 left
= DIRBLKSIZ
- blksiz
;
2949 dp
->d_reclen
+= left
;
2950 uiop
->uio_iov
->iov_base
+= left
;
2951 uiop
->uio_iov
->iov_len
-= left
;
2952 uiop
->uio_offset
+= left
;
2953 uiop
->uio_resid
-= left
;
2957 * We are now either at the end of the directory or have filled the
2961 dnp
->n_direofoffset
= uiop
->uio_offset
;
2963 if (uiop
->uio_resid
> 0)
2964 printf("EEK! readdirrpc resid > 0\n");
2965 cookiep
= nfs_getcookie(dnp
, uiop
->uio_offset
, 1);
2973 * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
2976 nfs_readdirplusrpc(vp
, uiop
, cred
)
2978 register struct uio
*uiop
;
2981 register int len
, left
;
2982 register struct dirent
*dp
;
2983 register u_long
*tl
;
2984 register caddr_t cp
;
2985 register long t1
, t2
;
2986 register struct vnode
*newvp
;
2987 register nfsuint64
*cookiep
;
2988 caddr_t bpos
, dpos
, cp2
, dpossav1
, dpossav2
;
2989 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
, *mdsav1
, *mdsav2
;
2990 struct nameidata nami
, *ndp
= &nami
;
2991 struct componentname
*cnp
= &ndp
->ni_cnd
;
2993 struct nfsmount
*nmp
;
2994 struct nfsnode
*dnp
= VTONFS(vp
), *np
;
2997 int error
= 0, tlen
, more_dirs
= 1, blksiz
= 0, doit
, bigenough
= 1, i
;
2998 int attrflag
, fhsize
, nmreaddirsize
, nmrsize
;
2999 u_int64_t xid
, savexid
;
3002 dp
= (struct dirent
*)0;
3005 if (uiop
->uio_iovcnt
!= 1 || (uiop
->uio_offset
& (DIRBLKSIZ
- 1)) ||
3006 (uiop
->uio_resid
& (DIRBLKSIZ
- 1)))
3007 panic("nfs_readdirplusrpc: bad uio");
3009 nmp
= VFSTONFS(vp
->v_mount
);
3012 nmreaddirsize
= nmp
->nm_readdirsize
;
3013 nmrsize
= nmp
->nm_rsize
;
3019 * If there is no cookie, assume directory was stale.
3021 cookiep
= nfs_getcookie(dnp
, uiop
->uio_offset
, 0);
3025 return (NFSERR_BAD_COOKIE
);
3027 * Loop around doing readdir rpc's of size nm_readdirsize
3028 * truncated to a multiple of DIRBLKSIZ.
3029 * The stopping criteria is EOF or buffer full.
3031 while (more_dirs
&& bigenough
) {
3032 nfsstats
.rpccnt
[NFSPROC_READDIRPLUS
]++;
3033 nfsm_reqhead(vp
, NFSPROC_READDIRPLUS
,
3034 NFSX_FH(1) + 6 * NFSX_UNSIGNED
);
3036 nfsm_build(tl
, u_long
*, 6 * NFSX_UNSIGNED
);
3037 *tl
++ = cookie
.nfsuquad
[0];
3038 *tl
++ = cookie
.nfsuquad
[1];
3039 *tl
++ = dnp
->n_cookieverf
.nfsuquad
[0];
3040 *tl
++ = dnp
->n_cookieverf
.nfsuquad
[1];
3041 *tl
++ = txdr_unsigned(nmreaddirsize
);
3042 *tl
= txdr_unsigned(nmrsize
);
3043 nfsm_request(vp
, NFSPROC_READDIRPLUS
, uiop
->uio_procp
, cred
,
3047 nfsm_postop_attr(vp
, attrflag
, &xid
);
3053 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
3054 dnp
->n_cookieverf
.nfsuquad
[0] = *tl
++;
3055 dnp
->n_cookieverf
.nfsuquad
[1] = *tl
++;
3056 more_dirs
= fxdr_unsigned(int, *tl
);
3058 /* loop thru the dir entries, doctoring them to 4bsd form */
3059 while (more_dirs
&& bigenough
) {
3060 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
3061 fxdr_hyper(tl
, &fileno
);
3062 len
= fxdr_unsigned(int, *(tl
+ 2));
3063 if (len
<= 0 || len
> NFS_MAXNAMLEN
) {
3068 tlen
= nfsm_rndup(len
);
3070 tlen
+= 4; /* To ensure null termination*/
3071 left
= DIRBLKSIZ
- blksiz
;
3072 if ((tlen
+ DIRHDSIZ
) > left
) {
3073 dp
->d_reclen
+= left
;
3074 uiop
->uio_iov
->iov_base
+= left
;
3075 uiop
->uio_iov
->iov_len
-= left
;
3076 uiop
->uio_offset
+= left
;
3077 uiop
->uio_resid
-= left
;
3080 if ((tlen
+ DIRHDSIZ
) > uiop
->uio_resid
)
3083 dp
= (struct dirent
*)uiop
->uio_iov
->iov_base
;
3084 dp
->d_fileno
= (int)fileno
;
3086 dp
->d_reclen
= tlen
+ DIRHDSIZ
;
3087 dp
->d_type
= DT_UNKNOWN
;
3088 blksiz
+= dp
->d_reclen
;
3089 if (blksiz
== DIRBLKSIZ
)
3091 uiop
->uio_offset
+= DIRHDSIZ
;
3092 uiop
->uio_resid
-= DIRHDSIZ
;
3093 uiop
->uio_iov
->iov_base
+= DIRHDSIZ
;
3094 uiop
->uio_iov
->iov_len
-= DIRHDSIZ
;
3095 cnp
->cn_nameptr
= uiop
->uio_iov
->iov_base
;
3096 cnp
->cn_namelen
= len
;
3097 nfsm_mtouio(uiop
, len
);
3098 cp
= uiop
->uio_iov
->iov_base
;
3101 uiop
->uio_iov
->iov_base
+= tlen
;
3102 uiop
->uio_iov
->iov_len
-= tlen
;
3103 uiop
->uio_offset
+= tlen
;
3104 uiop
->uio_resid
-= tlen
;
3106 nfsm_adv(nfsm_rndup(len
));
3107 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
3109 cookie
.nfsuquad
[0] = *tl
++;
3110 cookie
.nfsuquad
[1] = *tl
++;
3115 * Since the attributes are before the file handle
3116 * (sigh), we must skip over the attributes and then
3117 * come back and get them.
3119 attrflag
= fxdr_unsigned(int, *tl
);
3123 nfsm_adv(NFSX_V3FATTR
);
3124 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
3125 doit
= fxdr_unsigned(int, *tl
);
3127 nfsm_getfh(fhp
, fhsize
, 1);
3128 if (NFS_CMPFH(dnp
, fhp
, fhsize
)) {
3132 } else if (!bigenough
||
3133 (cnp
->cn_namelen
== 2 &&
3134 cnp
->cn_nameptr
[1] == '.' &&
3135 cnp
->cn_nameptr
[0] == '.')) {
3137 * don't doit if we can't guarantee
3138 * that this entry is NOT ".." because
3139 * we would have to drop the lock on
3140 * the directory before getting the
3141 * (lock on) the ".." vnode... and we
3142 * don't want to drop the dvp lock in
3143 * the middle of a readdirplus.
3147 if ((error
= nfs_nget(vp
->v_mount
, fhp
,
3154 if (doit
&& bigenough
) {
3160 nfsm_loadattr(newvp
, (struct vattr
*)0, &xid
);
3164 IFTODT(VTTOIF(np
->n_vattr
.va_type
));
3167 for (cp
= cnp
->cn_nameptr
, i
= 1; i
<= len
;
3169 cnp
->cn_hash
+= (unsigned char)*cp
* i
;
3170 cache_enter(ndp
->ni_dvp
, ndp
->ni_vp
, cnp
);
3173 /* Just skip over the file handle */
3174 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
3175 i
= fxdr_unsigned(int, *tl
);
3176 nfsm_adv(nfsm_rndup(i
));
3178 if (newvp
!= NULLVP
) {
3185 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
3186 more_dirs
= fxdr_unsigned(int, *tl
);
3189 * If at end of rpc data, get the eof boolean
3192 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
3193 more_dirs
= (fxdr_unsigned(int, *tl
) == 0);
3198 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
3199 * by increasing d_reclen for the last record.
3202 left
= DIRBLKSIZ
- blksiz
;
3203 dp
->d_reclen
+= left
;
3204 uiop
->uio_iov
->iov_base
+= left
;
3205 uiop
->uio_iov
->iov_len
-= left
;
3206 uiop
->uio_offset
+= left
;
3207 uiop
->uio_resid
-= left
;
3211 * We are now either at the end of the directory or have filled the
3215 dnp
->n_direofoffset
= uiop
->uio_offset
;
3217 if (uiop
->uio_resid
> 0)
3218 printf("EEK! readdirplusrpc resid > 0\n");
3219 cookiep
= nfs_getcookie(dnp
, uiop
->uio_offset
, 1);
3223 if (newvp
!= NULLVP
) {
3234 * Silly rename. To make the NFS filesystem that is stateless look a little
3235 * more like the "ufs" a remove of an active vnode is translated to a rename
3236 * to a funny looking filename that is removed by nfs_inactive on the
3237 * nfsnode. There is the potential for another process on a different client
3238 * to create the same funny name between the nfs_lookitup() fails and the
3239 * nfs_rename() completes, but...
3242 /* format of "random" names and next name to try */
3243 /* (note: shouldn't exceed size of sillyrename.s_name) */
3244 static char sillyrename_name
[] = ".nfsAAA%04x4.4";
3247 nfs_sillyrename(dvp
, vp
, cnp
)
3248 struct vnode
*dvp
, *vp
;
3249 struct componentname
*cnp
;
3251 register struct sillyrename
*sp
;
3261 if (vp
->v_type
== VDIR
)
3262 panic("nfs_sillyrename: dir");
3264 MALLOC_ZONE(sp
, struct sillyrename
*,
3265 sizeof (struct sillyrename
), M_NFSREQ
, M_WAITOK
);
3266 sp
->s_cred
= crdup(cnp
->cn_cred
);
3270 /* Fudge together a funny name */
3271 pid
= cnp
->cn_proc
->p_pid
;
3272 sp
->s_namlen
= sprintf(sp
->s_name
, sillyrename_name
, pid
);
3274 /* Try lookitups until we get one that isn't there */
3276 while (nfs_lookitup(dvp
, sp
->s_name
, sp
->s_namlen
, sp
->s_cred
,
3277 cnp
->cn_proc
, (struct nfsnode
**)0) == 0) {
3278 if (sp
->s_name
[4]++ >= 'z')
3279 sp
->s_name
[4] = 'A';
3280 if (++i
> ('z' - 'A' + 1)) {
3282 if (sp
->s_name
[5]++ >= 'z')
3283 sp
->s_name
[5] = 'A';
3284 if (++j
> ('z' - 'A' + 1)) {
3286 if (sp
->s_name
[6]++ >= 'z')
3287 sp
->s_name
[6] = 'A';
3288 if (++k
> ('z' - 'A' + 1)) {
3295 /* make note of next "random" name to try */
3296 if ((sillyrename_name
[4] = (sp
->s_name
[4] + 1)) > 'z') {
3297 sillyrename_name
[4] = 'A';
3298 if ((sillyrename_name
[5] = (sp
->s_name
[5] + 1)) > 'z') {
3299 sillyrename_name
[5] = 'A';
3300 if ((sillyrename_name
[6] = (sp
->s_name
[6] + 1)) > 'z')
3301 sillyrename_name
[6] = 'A';
3304 /* now, do the rename */
3305 if ((error
= nfs_renameit(dvp
, cnp
, sp
)))
3307 error
= nfs_lookitup(dvp
, sp
->s_name
, sp
->s_namlen
, sp
->s_cred
,
3310 kprintf("sillyrename: %s, vp=%x, np=%x, dvp=%x\n",
3311 &sp
->s_name
[0], (unsigned)vp
, (unsigned)np
, (unsigned)dvp
);
3313 np
->n_sillyrename
= sp
;
3318 sp
->s_cred
= NOCRED
;
3320 FREE_ZONE((caddr_t
)sp
, sizeof (struct sillyrename
), M_NFSREQ
);
3325 * Look up a file name and optionally either update the file handle or
3326 * allocate an nfsnode, depending on the value of npp.
3327 * npp == NULL --> just do the lookup
3328 * *npp == NULL --> allocate a new nfsnode and make sure attributes are
3330 * *npp != NULL --> update the file handle in the vnode
3333 nfs_lookitup(dvp
, name
, len
, cred
, procp
, npp
)
3334 register struct vnode
*dvp
;
3339 struct nfsnode
**npp
;
3341 register u_long
*tl
;
3342 register caddr_t cp
;
3343 register long t1
, t2
;
3344 struct vnode
*newvp
= (struct vnode
*)0;
3345 struct nfsnode
*np
, *dnp
= VTONFS(dvp
);
3346 caddr_t bpos
, dpos
, cp2
;
3347 int error
= 0, fhlen
, attrflag
;
3348 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
3353 if (!VFSTONFS(dvp
->v_mount
))
3357 nfsstats
.rpccnt
[NFSPROC_LOOKUP
]++;
3358 nfsm_reqhead(dvp
, NFSPROC_LOOKUP
,
3359 NFSX_FH(v3
) + NFSX_UNSIGNED
+ nfsm_rndup(len
));
3360 nfsm_fhtom(dvp
, v3
);
3361 nfsm_strtom(name
, len
, NFS_MAXNAMLEN
);
3362 nfsm_request(dvp
, NFSPROC_LOOKUP
, procp
, cred
, &xid
);
3363 if (npp
&& !error
) {
3364 nfsm_getfh(nfhp
, fhlen
, v3
);
3367 if (np
->n_fhsize
> NFS_SMALLFH
&& fhlen
<= NFS_SMALLFH
) {
3368 FREE_ZONE((caddr_t
)np
->n_fhp
,
3369 np
->n_fhsize
, M_NFSBIGFH
);
3370 np
->n_fhp
= &np
->n_fh
;
3371 } else if (np
->n_fhsize
<= NFS_SMALLFH
&& fhlen
>NFS_SMALLFH
)
3372 MALLOC_ZONE(np
->n_fhp
, nfsfh_t
*,
3373 fhlen
, M_NFSBIGFH
, M_WAITOK
);
3374 bcopy((caddr_t
)nfhp
, (caddr_t
)np
->n_fhp
, fhlen
);
3375 np
->n_fhsize
= fhlen
;
3377 } else if (NFS_CMPFH(dnp
, nfhp
, fhlen
)) {
3381 error
= nfs_nget(dvp
->v_mount
, nfhp
, fhlen
, &np
);
3389 nfsm_postop_attr(newvp
, attrflag
, &xid
);
3390 if (!attrflag
&& *npp
== NULL
) {
3399 nfsm_loadattr(newvp
, (struct vattr
*)0, &xid
);
3402 if (npp
&& *npp
== NULL
) {
3416 * Nfs Version 3 commit rpc
3419 nfs_commit(vp
, offset
, cnt
, cred
, procp
)
3420 register struct vnode
*vp
;
3426 register caddr_t cp
;
3427 register u_long
*tl
;
3428 register int t1
, t2
;
3429 register struct nfsmount
*nmp
= VFSTONFS(vp
->v_mount
);
3430 caddr_t bpos
, dpos
, cp2
;
3431 int error
= 0, wccpostattr
= 0;
3432 time_t premtime
= 0;
3433 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
3436 FSDBG(521, vp
, offset
, cnt
, nmp
->nm_state
);
3439 if ((nmp
->nm_state
& NFSSTA_HASWRITEVERF
) == 0)
3441 nfsstats
.rpccnt
[NFSPROC_COMMIT
]++;
3442 nfsm_reqhead(vp
, NFSPROC_COMMIT
, NFSX_FH(1));
3444 nfsm_build(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
3445 txdr_hyper(&offset
, tl
);
3447 *tl
= txdr_unsigned(cnt
);
3448 nfsm_request(vp
, NFSPROC_COMMIT
, procp
, cred
, &xid
);
3450 nfsm_wcc_data(vp
, premtime
, wccpostattr
, &xid
);
3451 /* XXX can we do anything useful with the wcc info? */
3454 nfsm_dissect(tl
, u_long
*, NFSX_V3WRITEVERF
);
3455 if (bcmp((caddr_t
)nmp
->nm_verf
, (caddr_t
)tl
,
3456 NFSX_V3WRITEVERF
)) {
3457 bcopy((caddr_t
)tl
, (caddr_t
)nmp
->nm_verf
,
3459 error
= NFSERR_STALEWRITEVERF
;
3468 struct vop_bmap_args
/* {
3471 struct vnode **a_vpp;
3477 register struct vnode
*vp
= ap
->a_vp
;
3478 int devBlockSize
= DEV_BSIZE
;
3480 if (ap
->a_vpp
!= NULL
)
3482 if (ap
->a_bnp
!= NULL
) {
3485 *ap
->a_bnp
= ap
->a_bn
* btodb(vp
->v_mount
->mnt_stat
.f_iosize
,
3488 if (ap
->a_runp
!= NULL
)
3491 if (ap
->a_runb
!= NULL
)
3500 * NB Currently unsupported.
3505 struct vop_mmap_args
/* {
3508 struct ucred *a_cred;
3517 * fsync vnode op. Just call nfs_flush().
3522 struct vop_fsync_args
/* {
3523 struct vnodeop_desc *a_desc;
3524 struct vnode * a_vp;
3525 struct ucred * a_cred;
3530 return (nfs_flush(ap
->a_vp
, ap
->a_cred
, ap
->a_waitfor
, ap
->a_p
));
3534 nfs_flushcommits(struct vnode
*vp
, struct proc
*p
)
3536 struct nfsnode
*np
= VTONFS(vp
);
3537 struct nfsbuf
*bp
, *nbp
;
3538 int i
, s
, error
= 0, retv
, bvecpos
, wcred_set
;
3539 u_quad_t off
, endoff
, toff
;
3540 struct ucred
* wcred
;
3541 struct nfsbuf
**bvec
= NULL
;
3542 #define NFS_COMMITBVECSIZ 20
3543 #define NFS_MAXCOMMITBVECSIZ 1024
3544 struct nfsbuf
*bvec_on_stack
[NFS_COMMITBVECSIZ
];
3545 int bvecsize
= NFS_MAXCOMMITBVECSIZ
;
3547 FSDBG_TOP(557, vp
, np
, 0, 0);
3550 * A nb_flags == (NB_DELWRI | NB_NEEDCOMMIT) block has been written to the
3551 * server, but nas not been committed to stable storage on the server
3552 * yet. The byte range is worked out for as many nfsbufs as we can handle
3553 * and the commit rpc is done.
3555 if (np
->n_dirtyblkhd
.lh_first
)
3556 np
->n_flag
|= NMODIFIED
;
3563 if (!VFSTONFS(vp
->v_mount
)) {
3567 if (!NFS_ISV3(vp
)) {
3574 * Allocate space to remember the list of bufs to commit. It is
3575 * important to use M_NOWAIT here to avoid a race with nfs_write
3577 MALLOC(bvec
, struct nfsbuf
**,
3578 bvecsize
* sizeof(struct nfsbuf
*), M_TEMP
,
3581 bvec
= bvec_on_stack
;
3582 bvecsize
= NFS_COMMITBVECSIZ
;
3584 for (bp
= np
->n_dirtyblkhd
.lh_first
; bp
&& bvecpos
< bvecsize
; bp
= nbp
) {
3585 nbp
= bp
->nb_vnbufs
.le_next
;
3587 if (((bp
->nb_flags
& (NB_BUSY
| NB_DELWRI
| NB_NEEDCOMMIT
))
3588 != (NB_DELWRI
| NB_NEEDCOMMIT
)))
3591 nfs_buf_remfree(bp
);
3592 SET(bp
->nb_flags
, NB_BUSY
);
3594 * we need a upl to see if the page has been
3595 * dirtied (think mmap) since the unstable write, and
3596 * also to prevent vm from paging it during our commit rpc
3598 if (!ISSET(bp
->nb_flags
, NB_PAGELIST
)) {
3599 retv
= nfs_buf_upl_setup(bp
);
3601 /* unable to create upl */
3602 /* vm object must no longer exist */
3603 /* this could be fatal if we need */
3604 /* to write the data again, we'll see... */
3605 printf("nfs_flushcommits: upl create failed %d\n", retv
);
3606 bp
->nb_valid
= bp
->nb_dirty
= 0;
3609 nfs_buf_upl_check(bp
);
3611 FSDBG(557, bp
, bp
->nb_flags
, bp
->nb_valid
, bp
->nb_dirty
);
3612 FSDBG(557, bp
->nb_validoff
, bp
->nb_validend
,
3613 bp
->nb_dirtyoff
, bp
->nb_dirtyend
);
3616 * We used to check for dirty pages here; if there were any
3617 * we'd abort the commit and force the entire buffer to be
3620 * Instead of doing that, we now go ahead and commit the dirty
3621 * range, and then leave the buffer around with dirty pages
3622 * that will be written out later.
3625 /* in case blocking calls were made, re-evaluate nbp */
3626 nbp
= bp
->nb_vnbufs
.le_next
;
3629 * Work out if all buffers are using the same cred
3630 * so we can deal with them all with one commit.
3632 if (wcred_set
== 0) {
3633 wcred
= bp
->nb_wcred
;
3634 if (wcred
== NOCRED
)
3635 panic("nfs: needcommit w/out wcred");
3637 } else if ((wcred_set
== 1) && crcmp(wcred
, bp
->nb_wcred
)) {
3640 SET(bp
->nb_flags
, NB_WRITEINPROG
);
3643 * A list of these buffers is kept so that the
3644 * second loop knows which buffers have actually
3645 * been committed. This is necessary, since there
3646 * may be a race between the commit rpc and new
3647 * uncommitted writes on the file.
3649 bvec
[bvecpos
++] = bp
;
3650 toff
= NBOFF(bp
) + bp
->nb_dirtyoff
;
3653 toff
+= (u_quad_t
)(bp
->nb_dirtyend
- bp
->nb_dirtyoff
);
3665 * Commit data on the server, as required.
3666 * If all bufs are using the same wcred, then use that with
3667 * one call for all of them, otherwise commit each one
3671 retv
= nfs_commit(vp
, off
, (int)(endoff
- off
), wcred
, p
);
3675 for (i
= 0; i
< bvecpos
; i
++) {
3678 off
= NBOFF(bp
) + bp
->nb_dirtyoff
;
3679 size
= (u_quad_t
)(bp
->nb_dirtyend
- bp
->nb_dirtyoff
);
3680 retv
= nfs_commit(vp
, off
, (int)size
, bp
->nb_wcred
, p
);
3684 if (retv
== NFSERR_STALEWRITEVERF
)
3685 nfs_clearcommit(vp
->v_mount
);
3688 * Now, either mark the blocks I/O done or mark the
3689 * blocks dirty, depending on whether the commit
3692 for (i
= 0; i
< bvecpos
; i
++) {
3694 FSDBG(557, bp
, retv
, bp
->nb_flags
, bp
->nb_dirty
);
3696 CLR(bp
->nb_flags
, (NB_NEEDCOMMIT
| NB_WRITEINPROG
));
3698 np
->n_needcommitcnt
--;
3699 CHECK_NEEDCOMMITCNT(np
);
3702 nfs_buf_release(bp
, 1);
3707 if (ISSET(bp
->nb_flags
, NB_DELWRI
)) {
3710 wakeup((caddr_t
)&nfs_nbdwrite
);
3712 CLR(bp
->nb_flags
, (NB_READ
|NB_DONE
|NB_ERROR
|NB_DELWRI
));
3713 /* if block still has dirty pages, we don't want it to */
3714 /* be released in nfs_buf_iodone(). So, don't set NB_ASYNC. */
3716 SET(bp
->nb_flags
, NB_ASYNC
);
3718 /* move to clean list */
3719 if (bp
->nb_vnbufs
.le_next
!= NFSNOLIST
)
3720 LIST_REMOVE(bp
, nb_vnbufs
);
3721 LIST_INSERT_HEAD(&VTONFS(vp
)->n_cleanblkhd
, bp
, nb_vnbufs
);
3723 bp
->nb_dirtyoff
= bp
->nb_dirtyend
= 0;
3728 /* throw it back in as a delayed write buffer */
3729 CLR(bp
->nb_flags
, NB_DONE
);
3730 nfs_buf_write_delayed(bp
);
3736 if (bvec
!= NULL
&& bvec
!= bvec_on_stack
)
3737 _FREE(bvec
, M_TEMP
);
3738 FSDBG_BOT(557, vp
, np
, 0, error
);
3743 * Flush all the blocks associated with a vnode.
3744 * Walk through the buffer pool and push any dirty pages
3745 * associated with the vnode.
3748 nfs_flush(vp
, cred
, waitfor
, p
)
3749 register struct vnode
*vp
;
3754 struct nfsnode
*np
= VTONFS(vp
);
3755 struct nfsbuf
*bp
, *nbp
;
3756 struct nfsmount
*nmp
= VFSTONFS(vp
->v_mount
);
3757 int i
, s
, error
= 0, error2
, slptimeo
= 0, slpflag
= 0;
3760 FSDBG_TOP(517, vp
, np
, waitfor
, 0);
3766 if (nmp
->nm_flag
& NFSMNT_INT
)
3770 * On the first pass, start async/unstable writes on all
3771 * delayed write buffers. Then wait for all writes to complete
3772 * and call nfs_flushcommits() to commit any uncommitted buffers.
3773 * On all subsequent passes, start STABLE writes on any remaining
3774 * dirty buffers. Then wait for all writes to complete.
3777 FSDBG(518, np
->n_dirtyblkhd
.lh_first
, np
->n_flag
, 0, 0);
3778 if (np
->n_dirtyblkhd
.lh_first
)
3779 np
->n_flag
|= NMODIFIED
;
3780 if (!VFSTONFS(vp
->v_mount
)) {
3785 /* Start/do any write(s) that are required. */
3788 for (bp
= np
->n_dirtyblkhd
.lh_first
; bp
; bp
= nbp
) {
3789 nbp
= bp
->nb_vnbufs
.le_next
;
3790 if (ISSET(bp
->nb_flags
, NB_BUSY
)) {
3791 FSDBG(524, bp
, waitfor
, passone
, bp
->nb_flags
);
3792 if (waitfor
!= MNT_WAIT
|| passone
)
3794 SET(bp
->nb_flags
, NB_WANTED
);
3795 error
= tsleep((caddr_t
)bp
, slpflag
| (PRIBIO
+ 1),
3796 "nfsfsync", slptimeo
);
3799 error2
= nfs_sigintr(VFSTONFS(vp
->v_mount
),
3800 (struct nfsreq
*)0, p
);
3805 if (slpflag
== PCATCH
) {
3812 if (!ISSET(bp
->nb_flags
, NB_DELWRI
))
3813 panic("nfs_fsync: not dirty");
3814 FSDBG(525, bp
, passone
, 0, bp
->nb_flags
);
3815 if ((passone
|| (waitfor
!= MNT_WAIT
)) && ISSET(bp
->nb_flags
, NB_NEEDCOMMIT
))
3817 nfs_buf_remfree(bp
);
3818 if (ISSET(bp
->nb_flags
, NB_ERROR
)) {
3819 np
->n_error
= bp
->nb_error
? bp
->nb_error
: EIO
;
3820 np
->n_flag
|= NWRITEERR
;
3821 nfs_buf_release(bp
, 1);
3825 SET(bp
->nb_flags
, NB_BUSY
|NB_ASYNC
);
3827 /* the NB_STABLE forces this to be written FILESYNC */
3828 SET(bp
->nb_flags
, NB_BUSY
|NB_ASYNC
|NB_STABLE
);
3836 if (waitfor
== MNT_WAIT
) {
3837 while (vp
->v_numoutput
) {
3838 vp
->v_flag
|= VBWAIT
;
3839 error
= tsleep((caddr_t
)&vp
->v_numoutput
,
3840 slpflag
| (PRIBIO
+ 1), "nfsfsync", slptimeo
);
3842 error2
= nfs_sigintr(VFSTONFS(vp
->v_mount
),
3843 (struct nfsreq
*)0, p
);
3848 if (slpflag
== PCATCH
) {
3857 /* loop while it looks like there are still buffers to be */
3858 /* commited and nfs_flushcommits() seems to be handling them. */
3859 while (np
->n_needcommitcnt
)
3860 if (nfs_flushcommits(vp
, p
))
3869 if (waitfor
== MNT_WAIT
) {
3870 if (np
->n_dirtyblkhd
.lh_first
) {
3875 FSDBG(526, np
->n_flag
, np
->n_error
, 0, 0);
3876 if (np
->n_flag
& NWRITEERR
) {
3877 error
= np
->n_error
;
3878 np
->n_flag
&= ~NWRITEERR
;
3881 FSDBG_BOT(517, vp
, np
, error
, 0);
3886 * Return POSIX pathconf information applicable to nfs.
3888 * The NFS V2 protocol doesn't support this, so just return EINVAL
3894 struct vop_pathconf_args
/* {
3905 * NFS advisory byte-level locks (client)
3909 struct vop_advlock_args
/* {
3917 return (nfs_dolock(ap
));
3921 * Print out the contents of an nfsnode.
3925 struct vop_print_args
/* {
3929 register struct vnode
*vp
= ap
->a_vp
;
3930 register struct nfsnode
*np
= VTONFS(vp
);
3932 printf("tag VT_NFS, fileid %ld fsid 0x%lx",
3933 np
->n_vattr
.va_fileid
, np
->n_vattr
.va_fsid
);
3934 if (vp
->v_type
== VFIFO
)
3941 * NFS directory offset lookup.
3942 * Currently unsupported.
3946 struct vop_blkatoff_args
/* {
3955 printf("nfs_blkatoff: unimplemented!!");
3957 return (EOPNOTSUPP
);
3961 * NFS flat namespace allocation.
3962 * Currently unsupported.
3966 struct vop_valloc_args
/* {
3967 struct vnode *a_pvp;
3969 struct ucred *a_cred;
3970 struct vnode **a_vpp;
3974 return (EOPNOTSUPP
);
3978 * NFS flat namespace free.
3979 * Currently unsupported.
3983 struct vop_vfree_args
/* {
3984 struct vnode *a_pvp;
3991 printf("nfs_vfree: unimplemented!!");
3993 return (EOPNOTSUPP
);
3997 * NFS file truncation.
4001 struct vop_truncate_args
/* {
4005 struct ucred *a_cred;
4010 /* Use nfs_setattr */
4012 printf("nfs_truncate: unimplemented!!");
4014 return (EOPNOTSUPP
);
4022 struct vop_update_args
/* {
4024 struct timeval *a_ta;
4025 struct timeval *a_tm;
4030 /* Use nfs_setattr */
4032 printf("nfs_update: unimplemented!!");
4034 return (EOPNOTSUPP
);
4038 * write (or commit) the given NFS buffer
4041 nfs_buf_write(struct nfsbuf
*bp
)
4044 int oldflags
= bp
->nb_flags
, rv
= 0;
4046 struct vnode
*vp
= bp
->nb_vp
;
4048 struct proc
*p
= current_proc();
4050 FSDBG_TOP(553, bp
, NBOFF(bp
), bp
->nb_flags
, 0);
4052 if (!ISSET(bp
->nb_flags
, NB_BUSY
))
4053 panic("nfs_buf_write: buffer is not busy???");
4056 CLR(bp
->nb_flags
, (NB_READ
|NB_DONE
|NB_ERROR
|NB_DELWRI
));
4057 if (ISSET(oldflags
, NB_DELWRI
)) {
4060 wakeup((caddr_t
)&nfs_nbdwrite
);
4063 /* move to clean list */
4064 if (ISSET(oldflags
, (NB_ASYNC
|NB_DELWRI
))) {
4065 if (bp
->nb_vnbufs
.le_next
!= NFSNOLIST
)
4066 LIST_REMOVE(bp
, nb_vnbufs
);
4067 LIST_INSERT_HEAD(&VTONFS(vp
)->n_cleanblkhd
, bp
, nb_vnbufs
);
4071 if (p
&& p
->p_stats
)
4072 p
->p_stats
->p_ru
.ru_oublock
++;
4076 * For async requests when nfsiod(s) are running, queue the request by
4077 * calling nfs_asyncio(), otherwise just all nfs_doio() to do the request.
4079 if (ISSET(bp
->nb_flags
, NB_ASYNC
))
4080 p
= (struct proc
*)0;
4081 if (ISSET(bp
->nb_flags
, NB_READ
))
4085 if (!ISSET(bp
->nb_flags
, NB_ASYNC
) || nfs_asyncio(bp
, NOCRED
))
4086 rv
= nfs_doio(bp
, cr
, p
);
4088 if ((oldflags
& NB_ASYNC
) == 0) {
4089 rv
= nfs_buf_iowait(bp
);
4090 /* move to clean list */
4091 if (oldflags
& NB_DELWRI
) {
4093 if (bp
->nb_vnbufs
.le_next
!= NFSNOLIST
)
4094 LIST_REMOVE(bp
, nb_vnbufs
);
4095 LIST_INSERT_HEAD(&VTONFS(vp
)->n_cleanblkhd
, bp
, nb_vnbufs
);
4098 FSDBG_BOT(553, bp
, NBOFF(bp
), bp
->nb_flags
, rv
);
4099 nfs_buf_release(bp
, 1);
4103 FSDBG_BOT(553, bp
, NBOFF(bp
), bp
->nb_flags
, rv
);
4108 * nfs special file access vnode op.
4109 * Essentially just get vattr and then imitate iaccess() since the device is
4110 * local to the client.
4114 struct vop_access_args
/* {
4117 struct ucred *a_cred;
4121 register struct vattr
*vap
;
4123 register struct ucred
*cred
= ap
->a_cred
;
4124 struct vnode
*vp
= ap
->a_vp
;
4125 mode_t mode
= ap
->a_mode
;
4131 * Disallow write attempts on filesystems mounted read-only;
4132 * unless the file is a socket, fifo, or a block or character
4133 * device resident on the filesystem.
4135 if ((mode
& VWRITE
) && vp
->v_mount
&& (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
4136 switch (vp
->v_type
) {
4137 case VREG
: case VDIR
: case VLNK
:
4142 * If you're the super-user,
4143 * you always get access.
4145 if (cred
->cr_uid
== 0)
4148 error
= VOP_GETATTR(vp
, vap
, cred
, ap
->a_p
);
4152 * Access check is based on only one of owner, group, public.
4153 * If not owner, then check group. If not a member of the
4154 * group, then check public access.
4156 if (cred
->cr_uid
!= vap
->va_uid
) {
4158 gp
= cred
->cr_groups
;
4159 for (i
= 0; i
< cred
->cr_ngroups
; i
++, gp
++)
4160 if (vap
->va_gid
== *gp
)
4166 error
= (vap
->va_mode
& mode
) == mode
? 0 : EACCES
;
4171 * Read wrapper for special devices.
4175 struct vop_read_args
/* {
4179 struct ucred *a_cred;
4182 register struct nfsnode
*np
= VTONFS(ap
->a_vp
);
4190 np
->n_atim
.tv_sec
= now
.tv_sec
;
4191 np
->n_atim
.tv_nsec
= now
.tv_usec
* 1000;
4192 return (VOCALL(spec_vnodeop_p
, VOFFSET(vop_read
), ap
));
4196 * Write wrapper for special devices.
4200 struct vop_write_args
/* {
4204 struct ucred *a_cred;
4207 register struct nfsnode
*np
= VTONFS(ap
->a_vp
);
4215 np
->n_mtim
.tv_sec
= now
.tv_sec
;
4216 np
->n_mtim
.tv_nsec
= now
.tv_usec
* 1000;
4217 return (VOCALL(spec_vnodeop_p
, VOFFSET(vop_write
), ap
));
4221 * Close wrapper for special devices.
4223 * Update the times on the nfsnode then do device close.
4227 struct vop_close_args
/* {
4230 struct ucred *a_cred;
4234 register struct vnode
*vp
= ap
->a_vp
;
4235 register struct nfsnode
*np
= VTONFS(vp
);
4238 if (np
->n_flag
& (NACC
| NUPD
)) {
4240 if (vp
->v_usecount
== 1 && vp
->v_mount
&&
4241 (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) == 0) {
4243 if (np
->n_flag
& NACC
)
4244 vattr
.va_atime
= np
->n_atim
;
4245 if (np
->n_flag
& NUPD
)
4246 vattr
.va_mtime
= np
->n_mtim
;
4247 (void)VOP_SETATTR(vp
, &vattr
, ap
->a_cred
, ap
->a_p
);
4250 return (VOCALL(spec_vnodeop_p
, VOFFSET(vop_close
), ap
));
4254 * Read wrapper for fifos.
4258 struct vop_read_args
/* {
4262 struct ucred *a_cred;
4265 extern vop_t
**fifo_vnodeop_p
;
4266 register struct nfsnode
*np
= VTONFS(ap
->a_vp
);
4274 np
->n_atim
.tv_sec
= now
.tv_sec
;
4275 np
->n_atim
.tv_nsec
= now
.tv_usec
* 1000;
4276 return (VOCALL(fifo_vnodeop_p
, VOFFSET(vop_read
), ap
));
4280 * Write wrapper for fifos.
4284 struct vop_write_args
/* {
4288 struct ucred *a_cred;
4291 extern vop_t
**fifo_vnodeop_p
;
4292 register struct nfsnode
*np
= VTONFS(ap
->a_vp
);
4300 np
->n_mtim
.tv_sec
= now
.tv_sec
;
4301 np
->n_mtim
.tv_nsec
= now
.tv_usec
* 1000;
4302 return (VOCALL(fifo_vnodeop_p
, VOFFSET(vop_write
), ap
));
4306 * Close wrapper for fifos.
4308 * Update the times on the nfsnode then do fifo close.
4312 struct vop_close_args
/* {
4315 struct ucred *a_cred;
4319 register struct vnode
*vp
= ap
->a_vp
;
4320 register struct nfsnode
*np
= VTONFS(vp
);
4323 extern vop_t
**fifo_vnodeop_p
;
4325 if (np
->n_flag
& (NACC
| NUPD
)) {
4327 if (np
->n_flag
& NACC
) {
4328 np
->n_atim
.tv_sec
= now
.tv_sec
;
4329 np
->n_atim
.tv_nsec
= now
.tv_usec
* 1000;
4331 if (np
->n_flag
& NUPD
) {
4332 np
->n_mtim
.tv_sec
= now
.tv_sec
;
4333 np
->n_mtim
.tv_nsec
= now
.tv_usec
* 1000;
4336 if (vp
->v_usecount
== 1 && vp
->v_mount
&&
4337 (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) == 0) {
4339 if (np
->n_flag
& NACC
)
4340 vattr
.va_atime
= np
->n_atim
;
4341 if (np
->n_flag
& NUPD
)
4342 vattr
.va_mtime
= np
->n_mtim
;
4343 (void)VOP_SETATTR(vp
, &vattr
, ap
->a_cred
, ap
->a_p
);
4346 return (VOCALL(fifo_vnodeop_p
, VOFFSET(vop_close
), ap
));
4351 struct vop_ioctl_args
*ap
;
4355 * XXX we were once bogusly enoictl() which returned this (ENOTTY).
4356 * Probably we should return ENODEV.
4363 struct vop_select_args
*ap
;
4367 * We were once bogusly seltrue() which returns 1. Is this right?
4373 * Vnode op for pagein using getblk_pages
4374 * derived from nfs_bioread()
4375 * No read aheads are started from pagein operation
4379 struct vop_pagein_args
/* {
4382 vm_offset_t a_pl_offset,
4385 struct ucred *a_cred,
4389 register struct vnode
*vp
= ap
->a_vp
;
4390 upl_t pl
= ap
->a_pl
;
4391 size_t size
= ap
->a_size
;
4392 off_t f_offset
= ap
->a_f_offset
;
4393 vm_offset_t pl_offset
= ap
->a_pl_offset
;
4394 int flags
= ap
->a_flags
;
4396 struct nfsnode
*np
= VTONFS(vp
);
4397 int biosize
, xsize
, iosize
;
4399 struct proc
*p
= current_proc();
4400 struct nfsmount
*nmp
;
4405 struct uio
* uio
= &auio
;
4406 int nofreeupl
= flags
& UPL_NOCOMMIT
;
4407 upl_page_info_t
*plinfo
;
4409 FSDBG(322, vp
, f_offset
, size
, flags
);
4410 if (pl
== (upl_t
)NULL
)
4411 panic("nfs_pagein: no upl");
4413 if (UBCINVALID(vp
)) {
4414 printf("nfs_pagein: invalid vnode 0x%x", (int)vp
);
4416 (void) ubc_upl_abort(pl
, NULL
);
4419 UBCINFOCHECK("nfs_pagein", vp
);
4422 printf("nfs_pagein: invalid size %d", size
);
4424 (void) ubc_upl_abort(pl
, NULL
);
4427 if (f_offset
< 0 || f_offset
>= np
->n_size
|| (f_offset
& PAGE_MASK_64
)) {
4429 ubc_upl_abort_range(pl
, pl_offset
, size
,
4430 UPL_ABORT_ERROR
| UPL_ABORT_FREE_ON_EMPTY
);
4433 cred
= ubc_getcred(vp
);
4437 auio
.uio_offset
= f_offset
;
4438 auio
.uio_segflg
= UIO_SYSSPACE
;
4439 auio
.uio_rw
= UIO_READ
;
4440 auio
.uio_procp
= NULL
;
4442 nmp
= VFSTONFS(vp
->v_mount
);
4445 ubc_upl_abort_range(pl
, pl_offset
, size
,
4446 UPL_ABORT_ERROR
| UPL_ABORT_FREE_ON_EMPTY
);
4449 if ((nmp
->nm_flag
& NFSMNT_NFSV3
) && !(nmp
->nm_state
& NFSSTA_GOTFSINFO
))
4450 (void)nfs_fsinfo(nmp
, vp
, cred
, p
);
4451 biosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
4453 plinfo
= ubc_upl_pageinfo(pl
);
4454 ubc_upl_map(pl
, &ioaddr
);
4455 ioaddr
+= pl_offset
;
4460 * It would be nice to be able to issue all these requests
4461 * in parallel instead of waiting for each one to complete
4462 * before sending the next one.
4463 * XXX Should we align these requests to block boundaries?
4465 iosize
= min(biosize
, xsize
);
4466 uio
->uio_resid
= iosize
;
4467 aiov
.iov_len
= iosize
;
4468 aiov
.iov_base
= (caddr_t
)ioaddr
;
4469 auio
.uio_iov
= &aiov
;
4470 auio
.uio_iovcnt
= 1;
4472 FSDBG(322, uio
->uio_offset
, uio
->uio_resid
, ioaddr
, xsize
);
4473 // XXX #warning our nfs_pagein does not support NQNFS
4475 * With UBC we get here only when the file data is not in the VM
4476 * page cache, so go ahead and read in.
4479 upl_ubc_alias_set(pl
, current_act(), 2);
4480 #endif /* UBC_DEBUG */
4483 error
= nfs_readrpc(vp
, uio
, cred
);
4486 if (uio
->uio_resid
) {
4488 * If uio_resid > 0, there is a hole in the file
4489 * and no writes after the hole have been pushed
4490 * to the server yet... or we're at the EOF
4491 * Just zero fill the rest of the valid area.
4493 int zcnt
= uio
->uio_resid
;
4494 int zoff
= iosize
- zcnt
;
4495 bzero((char *)ioaddr
+ zoff
, zcnt
);
4497 FSDBG(324, uio
->uio_offset
, zoff
, zcnt
, ioaddr
);
4498 uio
->uio_offset
+= zcnt
;
4503 FSDBG(322, uio
->uio_offset
, uio
->uio_resid
, error
, -1);
4505 nmp
= VFSTONFS(vp
->v_mount
);
4506 if (p
&& (vp
->v_flag
& VTEXT
) && nmp
&&
4507 ((nmp
->nm_flag
& NFSMNT_NQNFS
&&
4508 NQNFS_CKINVALID(vp
, np
, ND_READ
) &&
4509 np
->n_lrev
!= np
->n_brev
) ||
4510 (!(nmp
->nm_flag
& NFSMNT_NQNFS
) &&
4511 np
->n_mtime
!= np
->n_vattr
.va_mtime
.tv_sec
))) {
4512 uprintf("Process killed due to text file modification\n");
4513 psignal(p
, SIGKILL
);
4514 p
->p_flag
|= P_NOSWAP
;
4517 } while (error
== 0 && xsize
> 0);
4523 ubc_upl_abort_range(pl
, pl_offset
, size
,
4525 UPL_ABORT_FREE_ON_EMPTY
);
4527 ubc_upl_commit_range(pl
, pl_offset
, size
,
4528 UPL_COMMIT_CLEAR_DIRTY
|
4529 UPL_COMMIT_FREE_ON_EMPTY
);
4536 * Vnode op for pageout using UPL
4537 * Derived from nfs_write()
4538 * File size changes are not permitted in pageout.
4542 struct vop_pageout_args
/* {
4545 vm_offset_t a_pl_offset,
4548 struct ucred *a_cred,
4552 register struct vnode
*vp
= ap
->a_vp
;
4553 upl_t pl
= ap
->a_pl
;
4554 size_t size
= ap
->a_size
;
4555 off_t f_offset
= ap
->a_f_offset
;
4556 vm_offset_t pl_offset
= ap
->a_pl_offset
;
4557 int flags
= ap
->a_flags
;
4558 int ioflag
= ap
->a_flags
;
4559 struct proc
*p
= current_proc();
4560 struct nfsnode
*np
= VTONFS(vp
);
4561 register struct ucred
*cred
;
4563 struct nfsmount
*nmp
= VFSTONFS(vp
->v_mount
);
4565 int n
= 0, on
, error
= 0, iomode
, must_commit
, s
;
4570 int nofreeupl
= flags
& UPL_NOCOMMIT
;
4571 int biosize
, iosize
, pgsize
, xsize
;
4573 FSDBG(323, f_offset
, size
, pl
, pl_offset
);
4575 if (pl
== (upl_t
)NULL
)
4576 panic("nfs_pageout: no upl");
4578 if (UBCINVALID(vp
)) {
4579 printf("nfs_pageout: invalid vnode 0x%x", (int)vp
);
4581 ubc_upl_abort(pl
, 0);
4584 UBCINFOCHECK("nfs_pageout", vp
);
4587 printf("nfs_pageout: invalid size %d", size
);
4589 ubc_upl_abort(pl
, 0);
4595 ubc_upl_abort(pl
, UPL_ABORT_DUMP_PAGES
|UPL_ABORT_FREE_ON_EMPTY
);
4598 biosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
4601 * Check to see whether the buffer is incore.
4602 * If incore and not busy, invalidate it from the cache.
4604 for (iosize
= 0; iosize
< size
; iosize
+= xsize
) {
4605 off
= f_offset
+ iosize
;
4606 /* need make sure we do things on block boundaries */
4607 xsize
= biosize
- (off
% biosize
);
4608 if (off
+ xsize
> f_offset
+ size
)
4609 xsize
= f_offset
+ size
- off
;
4610 lbn
= ubc_offtoblk(vp
, off
);
4612 if (bp
= nfs_buf_incore(vp
, lbn
)) {
4613 FSDBG(323, off
, 1, bp
, bp
->nb_flags
);
4614 if (ISSET(bp
->nb_flags
, NB_BUSY
)) {
4615 /* no panic. just tell vm we are busy */
4617 ubc_upl_abort(pl
, 0);
4620 if (bp
->nb_dirtyend
> 0) {
4622 * if there's a dirty range in the buffer, check to
4623 * see if it extends beyond the pageout region
4625 * if the dirty region lies completely within the
4626 * pageout region, we just invalidate the buffer
4627 * because it's all being written out now anyway.
4629 * if any of the dirty region lies outside the
4630 * pageout region, we'll try to clip the dirty
4631 * region to eliminate the portion that's being
4632 * paged out. If that's not possible, because
4633 * the dirty region extends before and after the
4634 * pageout region, then we'll just return EBUSY.
4636 off_t boff
, start
, end
;
4640 /* clip end to EOF */
4641 if (end
> np
->n_size
)
4645 if ((bp
->nb_dirtyoff
< start
) &&
4646 (bp
->nb_dirtyend
> end
)) {
4647 /* not gonna be able to clip the dirty region */
4648 FSDBG(323, vp
, bp
, 0xd00deebc, EBUSY
);
4650 ubc_upl_abort(pl
, 0);
4653 if ((bp
->nb_dirtyoff
< start
) ||
4654 (bp
->nb_dirtyend
> end
)) {
4655 /* clip dirty region, if necessary */
4656 if (bp
->nb_dirtyoff
< start
)
4657 bp
->nb_dirtyend
= min(bp
->nb_dirtyend
, start
);
4658 if (bp
->nb_dirtyend
> end
)
4659 bp
->nb_dirtyoff
= max(bp
->nb_dirtyoff
, end
);
4660 FSDBG(323, bp
, bp
->nb_dirtyoff
, bp
->nb_dirtyend
, 0xd00dee00);
4661 /* we're leaving this block dirty */
4665 nfs_buf_remfree(bp
);
4666 SET(bp
->nb_flags
, (NB_BUSY
| NB_INVAL
));
4667 if (ISSET(bp
->nb_flags
, NB_NEEDCOMMIT
)) {
4668 CLR(bp
->nb_flags
, NB_NEEDCOMMIT
);
4669 np
->n_needcommitcnt
--;
4670 CHECK_NEEDCOMMITCNT(np
);
4672 nfs_buf_release(bp
, 1);
4677 cred
= ubc_getcred(vp
);
4681 if (np
->n_flag
& NWRITEERR
) {
4682 np
->n_flag
&= ~NWRITEERR
;
4684 ubc_upl_abort_range(pl
, pl_offset
, size
,
4685 UPL_ABORT_FREE_ON_EMPTY
);
4686 return (np
->n_error
);
4688 if ((nmp
->nm_flag
& NFSMNT_NFSV3
) &&
4689 !(nmp
->nm_state
& NFSSTA_GOTFSINFO
))
4690 (void)nfs_fsinfo(nmp
, vp
, cred
, p
);
4692 if (f_offset
< 0 || f_offset
>= np
->n_size
||
4693 f_offset
& PAGE_MASK_64
|| size
& PAGE_MASK_64
) {
4695 ubc_upl_abort_range(pl
, pl_offset
, size
,
4696 UPL_ABORT_FREE_ON_EMPTY
);
4700 ubc_upl_map(pl
, &ioaddr
);
4701 ioaddr
+= pl_offset
;
4703 if (f_offset
+ size
> np
->n_size
)
4704 xsize
= np
->n_size
- f_offset
;
4708 pgsize
= round_page_64(xsize
);
4709 if (size
> pgsize
) {
4711 ubc_upl_abort_range(pl
, pl_offset
+ pgsize
,
4713 UPL_ABORT_FREE_ON_EMPTY
);
4717 * check for partial page and clear the
4718 * contents past end of the file before
4719 * releasing it in the VM page cache
4721 if (f_offset
< np
->n_size
&& f_offset
+ size
> np
->n_size
) {
4722 size_t io
= np
->n_size
- f_offset
;
4723 bzero((caddr_t
)(ioaddr
+ io
), size
- io
);
4724 FSDBG(321, np
->n_size
, f_offset
, f_offset
+ io
, size
- io
);
4727 auio
.uio_offset
= f_offset
;
4728 auio
.uio_segflg
= UIO_SYSSPACE
;
4729 auio
.uio_rw
= UIO_READ
;
4730 auio
.uio_procp
= NULL
;
4734 * It would be nice to be able to issue all these requests
4735 * in parallel instead of waiting for each one to complete
4736 * before sending the next one.
4737 * XXX Should we align these requests to block boundaries?
4739 iosize
= min(biosize
, xsize
);
4740 auio
.uio_resid
= iosize
;
4741 aiov
.iov_len
= iosize
;
4742 aiov
.iov_base
= (caddr_t
)ioaddr
;
4743 auio
.uio_iov
= &aiov
;
4744 auio
.uio_iovcnt
= 1;
4746 FSDBG(323, auio
.uio_offset
, auio
.uio_resid
, ioaddr
, xsize
);
4747 // XXX #warning our nfs_pageout does not support NQNFS
4748 nfsstats
.pageouts
++;
4751 /* NMODIFIED would be set here if doing unstable writes */
4752 iomode
= NFSV3WRITE_FILESYNC
;
4753 error
= nfs_writerpc(vp
, &auio
, cred
, &iomode
, &must_commit
);
4755 nfs_clearcommit(vp
->v_mount
);
4759 /* Note: no need to check uio_resid, because */
4760 /* it'll only be set if there was an error. */
4763 } while (xsize
> 0);
4768 * We've had several different solutions on what to do when the pageout
4769 * gets an error. If we don't handle it, and return an error to the
4770 * caller, vm, it will retry . This can end in endless looping
4771 * between vm and here doing retries of the same page. Doing a dump
4772 * back to vm, will get it out of vm's knowledge and we lose whatever
4773 * data existed. This is risky, but in some cases necessary. For
4774 * example, the initial fix here was to do that for ESTALE. In that case
4775 * the server is telling us that the file is no longer the same. We
4776 * would not want to keep paging out to that. We also saw some 151
4777 * errors from Auspex server and NFSv3 can return errors higher than
4778 * ELAST. Those along with NFS known server errors we will "dump" from
4779 * vm. Errors we don't expect to occur, we dump and log for further
4780 * analysis. Errors that could be transient, networking ones,
4781 * we let vm "retry". Lastly, errors that we retry, but may have potential
4782 * to storm the network, we "retrywithsleep". "sever" will be used in
4783 * in the future to dump all pages of object for cases like ESTALE.
4784 * All this is the basis for the states returned and first guesses on
4785 * error handling. Tweaking expected as more statistics are gathered.
4786 * Note, in the long run we may need another more robust solution to
4787 * have some kind of persistant store when the vm cannot dump nor keep
4788 * retrying as a solution, but this would be a file architectural change
4791 if (!nofreeupl
) { /* otherwise stacked file system has to handle this */
4794 short action
= nfs_pageouterrorhandler(error
);
4798 abortflags
= UPL_ABORT_DUMP_PAGES
|UPL_ABORT_FREE_ON_EMPTY
;
4801 abortflags
= UPL_ABORT_DUMP_PAGES
|UPL_ABORT_FREE_ON_EMPTY
;
4802 if (error
<= ELAST
&&
4803 (errorcount
[error
] % 100 == 0))
4804 printf("nfs_pageout: unexpected error %d. dumping vm page\n", error
);
4805 errorcount
[error
]++;
4808 abortflags
= UPL_ABORT_FREE_ON_EMPTY
;
4810 case RETRYWITHSLEEP
:
4811 abortflags
= UPL_ABORT_FREE_ON_EMPTY
;
4812 /* pri unused. PSOCK for placeholder. */
4813 (void) tsleep(&lbolt
, PSOCK
,
4816 case SEVER
: /* not implemented */
4818 printf("nfs_pageout: action %d not expected\n", action
);
4822 ubc_upl_abort_range(pl
, pl_offset
, size
, abortflags
);
4823 /* return error in all cases above */
4826 ubc_upl_commit_range(pl
, pl_offset
, pgsize
,
4827 UPL_COMMIT_CLEAR_DIRTY
|
4828 UPL_COMMIT_FREE_ON_EMPTY
);
4833 /* Blktooff derives file offset given a logical block number */
4836 struct vop_blktooff_args
/* {
4843 register struct vnode
*vp
= ap
->a_vp
;
4848 biosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
4850 *ap
->a_offset
= (off_t
)ap
->a_lblkno
* biosize
;
4857 struct vop_offtoblk_args
/* {
4864 register struct vnode
*vp
= ap
->a_vp
;
4869 biosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
4871 *ap
->a_lblkno
= (daddr_t
)(ap
->a_offset
/ biosize
);
4877 struct vop_cmap_args
/* {
4886 return (EOPNOTSUPP
);