2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
27 * Copyright (c) 1989, 1993
28 * The Regents of the University of California. All rights reserved.
30 * This code is derived from software contributed to Berkeley by
31 * Rick Macklem at The University of Guelph.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
62 * FreeBSD-Id: nfs_vnops.c,v 1.72 1997/11/07 09:20:48 phk Exp $
67 * vnode op calls for Sun NFS version 2 and 3
69 #include <sys/param.h>
70 #include <sys/kernel.h>
71 #include <sys/systm.h>
72 #include <sys/resourcevar.h>
74 #include <sys/mount.h>
75 #include <sys/malloc.h>
78 #include <sys/namei.h>
79 #include <sys/vnode.h>
80 #include <sys/dirent.h>
81 #include <sys/fcntl.h>
82 #include <sys/lockf.h>
85 #include <vfs/vfs_support.h>
88 #include <machine/spl.h>
89 #include <vm/vm_pageout.h>
92 #include <kern/clock.h>
94 #include <miscfs/fifofs/fifo.h>
95 #include <miscfs/specfs/specdev.h>
97 #include <nfs/rpcv2.h>
98 #include <nfs/nfsproto.h>
100 #include <nfs/nfsnode.h>
101 #include <nfs/nfsmount.h>
102 #include <nfs/nfs_lock.h>
103 #include <nfs/xdr_subs.h>
104 #include <nfs/nfsm_subs.h>
105 #include <nfs/nqnfs.h>
108 #include <netinet/in.h>
109 #include <netinet/in_var.h>
110 #include <vm/vm_kern.h>
112 #include <kern/task.h>
113 #include <kern/sched_prim.h>
115 #include <sys/kdebug.h>
117 #define FSDBG(A, B, C, D, E) \
118 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_NONE, \
119 (int)(B), (int)(C), (int)(D), (int)(E), 0)
120 #define FSDBG_TOP(A, B, C, D, E) \
121 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_START, \
122 (int)(B), (int)(C), (int)(D), (int)(E), 0)
123 #define FSDBG_BOT(A, B, C, D, E) \
124 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_END, \
125 (int)(B), (int)(C), (int)(D), (int)(E), 0)
130 #define NFS_FREE_PNBUF(CNP) \
132 char *tmp = (CNP)->cn_pnbuf; \
133 (CNP)->cn_pnbuf = NULL; \
134 (CNP)->cn_flags &= ~HASBUF; \
135 FREE_ZONE(tmp, (CNP)->cn_pnlen, M_NAMEI); \
139 static int nfsspec_read
__P((struct vop_read_args
*));
140 static int nfsspec_write
__P((struct vop_write_args
*));
141 static int nfsfifo_read
__P((struct vop_read_args
*));
142 static int nfsfifo_write
__P((struct vop_write_args
*));
143 static int nfsspec_close
__P((struct vop_close_args
*));
144 static int nfsfifo_close
__P((struct vop_close_args
*));
145 #define nfs_poll vop_nopoll
146 static int nfs_ioctl
__P((struct vop_ioctl_args
*));
147 static int nfs_select
__P((struct vop_select_args
*));
148 static int nfs_flush
__P((struct vnode
*,struct ucred
*,int,struct proc
*,int));
149 static int nfs_setattrrpc
__P((struct vnode
*,struct vattr
*,struct ucred
*,struct proc
*));
150 static int nfs_lookup
__P((struct vop_lookup_args
*));
151 static int nfs_create
__P((struct vop_create_args
*));
152 static int nfs_mknod
__P((struct vop_mknod_args
*));
153 static int nfs_open
__P((struct vop_open_args
*));
154 static int nfs_close
__P((struct vop_close_args
*));
155 static int nfs_access
__P((struct vop_access_args
*));
156 static int nfs_getattr
__P((struct vop_getattr_args
*));
157 static int nfs_setattr
__P((struct vop_setattr_args
*));
158 static int nfs_read
__P((struct vop_read_args
*));
159 static int nfs_mmap
__P((struct vop_mmap_args
*));
160 static int nfs_fsync
__P((struct vop_fsync_args
*));
161 static int nfs_remove
__P((struct vop_remove_args
*));
162 static int nfs_link
__P((struct vop_link_args
*));
163 static int nfs_rename
__P((struct vop_rename_args
*));
164 static int nfs_mkdir
__P((struct vop_mkdir_args
*));
165 static int nfs_rmdir
__P((struct vop_rmdir_args
*));
166 static int nfs_symlink
__P((struct vop_symlink_args
*));
167 static int nfs_readdir
__P((struct vop_readdir_args
*));
168 static int nfs_bmap
__P((struct vop_bmap_args
*));
169 static int nfs_lookitup
__P((struct vnode
*,char *,int,struct ucred
*,struct proc
*,struct nfsnode
**));
170 static int nfs_sillyrename
__P((struct vnode
*,struct vnode
*,struct componentname
*));
171 static int nfsspec_access
__P((struct vop_access_args
*));
172 static int nfs_readlink
__P((struct vop_readlink_args
*));
173 static int nfs_print
__P((struct vop_print_args
*));
174 static int nfs_pathconf
__P((struct vop_pathconf_args
*));
175 static int nfs_advlock
__P((struct vop_advlock_args
*));
176 static int nfs_blkatoff
__P((struct vop_blkatoff_args
*));
177 static int nfs_valloc
__P((struct vop_valloc_args
*));
178 static int nfs_vfree
__P((struct vop_vfree_args
*));
179 static int nfs_truncate
__P((struct vop_truncate_args
*));
180 static int nfs_update
__P((struct vop_update_args
*));
181 static int nfs_pagein
__P((struct vop_pagein_args
*));
182 static int nfs_pageout
__P((struct vop_pageout_args
*));
183 static int nfs_blktooff
__P((struct vop_blktooff_args
*));
184 static int nfs_offtoblk
__P((struct vop_offtoblk_args
*));
185 static int nfs_cmap
__P((struct vop_cmap_args
*));
188 * Global vfs data structures for nfs
190 vop_t
**nfsv2_vnodeop_p
;
191 static struct vnodeopv_entry_desc nfsv2_vnodeop_entries
[] = {
192 { &vop_default_desc
, (vop_t
*)vn_default_error
},
193 { &vop_lookup_desc
, (vop_t
*)nfs_lookup
}, /* lookup */
194 { &vop_create_desc
, (vop_t
*)nfs_create
}, /* create */
195 { &vop_mknod_desc
, (vop_t
*)nfs_mknod
}, /* mknod */
196 { &vop_open_desc
, (vop_t
*)nfs_open
}, /* open */
197 { &vop_close_desc
, (vop_t
*)nfs_close
}, /* close */
198 { &vop_access_desc
, (vop_t
*)nfs_access
}, /* access */
199 { &vop_getattr_desc
, (vop_t
*)nfs_getattr
}, /* getattr */
200 { &vop_setattr_desc
, (vop_t
*)nfs_setattr
}, /* setattr */
201 { &vop_read_desc
, (vop_t
*)nfs_read
}, /* read */
202 { &vop_write_desc
, (vop_t
*)nfs_write
}, /* write */
203 { &vop_lease_desc
, (vop_t
*)nfs_lease_check
}, /* lease */
204 { &vop_ioctl_desc
, (vop_t
*)nfs_ioctl
}, /* ioctl */
205 { &vop_select_desc
, (vop_t
*)nfs_select
}, /* select */
206 { &vop_revoke_desc
, (vop_t
*)nfs_revoke
}, /* revoke */
207 { &vop_mmap_desc
, (vop_t
*)nfs_mmap
}, /* mmap */
208 { &vop_fsync_desc
, (vop_t
*)nfs_fsync
}, /* fsync */
209 { &vop_seek_desc
, (vop_t
*)nfs_seek
}, /* seek */
210 { &vop_remove_desc
, (vop_t
*)nfs_remove
}, /* remove */
211 { &vop_link_desc
, (vop_t
*)nfs_link
}, /* link */
212 { &vop_rename_desc
, (vop_t
*)nfs_rename
}, /* rename */
213 { &vop_mkdir_desc
, (vop_t
*)nfs_mkdir
}, /* mkdir */
214 { &vop_rmdir_desc
, (vop_t
*)nfs_rmdir
}, /* rmdir */
215 { &vop_symlink_desc
, (vop_t
*)nfs_symlink
}, /* symlink */
216 { &vop_readdir_desc
, (vop_t
*)nfs_readdir
}, /* readdir */
217 { &vop_readlink_desc
, (vop_t
*)nfs_readlink
}, /* readlink */
218 { &vop_abortop_desc
, (vop_t
*)nop_abortop
}, /* abortop */
219 { &vop_inactive_desc
, (vop_t
*)nfs_inactive
}, /* inactive */
220 { &vop_reclaim_desc
, (vop_t
*)nfs_reclaim
}, /* reclaim */
221 { &vop_lock_desc
, (vop_t
*)nfs_lock
}, /* lock */
222 { &vop_unlock_desc
, (vop_t
*)nfs_unlock
}, /* unlock */
223 { &vop_bmap_desc
, (vop_t
*)nfs_bmap
}, /* bmap */
224 { &vop_strategy_desc
, (vop_t
*)err_strategy
}, /* strategy */
225 { &vop_print_desc
, (vop_t
*)nfs_print
}, /* print */
226 { &vop_islocked_desc
, (vop_t
*)nfs_islocked
}, /* islocked */
227 { &vop_pathconf_desc
, (vop_t
*)nfs_pathconf
}, /* pathconf */
228 { &vop_advlock_desc
, (vop_t
*)nfs_advlock
}, /* advlock */
229 { &vop_blkatoff_desc
, (vop_t
*)nfs_blkatoff
}, /* blkatoff */
230 { &vop_valloc_desc
, (vop_t
*)nfs_valloc
}, /* valloc */
231 { &vop_reallocblks_desc
, (vop_t
*)nfs_reallocblks
}, /* reallocblks */
232 { &vop_vfree_desc
, (vop_t
*)nfs_vfree
}, /* vfree */
233 { &vop_truncate_desc
, (vop_t
*)nfs_truncate
}, /* truncate */
234 { &vop_update_desc
, (vop_t
*)nfs_update
}, /* update */
235 { &vop_bwrite_desc
, (vop_t
*)err_bwrite
}, /* bwrite */
236 { &vop_pagein_desc
, (vop_t
*)nfs_pagein
}, /* Pagein */
237 { &vop_pageout_desc
, (vop_t
*)nfs_pageout
}, /* Pageout */
238 { &vop_copyfile_desc
, (vop_t
*)err_copyfile
}, /* Copyfile */
239 { &vop_blktooff_desc
, (vop_t
*)nfs_blktooff
}, /* blktooff */
240 { &vop_offtoblk_desc
, (vop_t
*)nfs_offtoblk
}, /* offtoblk */
241 { &vop_cmap_desc
, (vop_t
*)nfs_cmap
}, /* cmap */
244 struct vnodeopv_desc nfsv2_vnodeop_opv_desc
=
245 { &nfsv2_vnodeop_p
, nfsv2_vnodeop_entries
};
247 VNODEOP_SET(nfsv2_vnodeop_opv_desc
);
251 * Special device vnode ops
253 vop_t
**spec_nfsv2nodeop_p
;
254 static struct vnodeopv_entry_desc spec_nfsv2nodeop_entries
[] = {
255 { &vop_default_desc
, (vop_t
*)vn_default_error
},
256 { &vop_lookup_desc
, (vop_t
*)spec_lookup
}, /* lookup */
257 { &vop_create_desc
, (vop_t
*)spec_create
}, /* create */
258 { &vop_mknod_desc
, (vop_t
*)spec_mknod
}, /* mknod */
259 { &vop_open_desc
, (vop_t
*)spec_open
}, /* open */
260 { &vop_close_desc
, (vop_t
*)nfsspec_close
}, /* close */
261 { &vop_access_desc
, (vop_t
*)nfsspec_access
}, /* access */
262 { &vop_getattr_desc
, (vop_t
*)nfs_getattr
}, /* getattr */
263 { &vop_setattr_desc
, (vop_t
*)nfs_setattr
}, /* setattr */
264 { &vop_read_desc
, (vop_t
*)nfsspec_read
}, /* read */
265 { &vop_write_desc
, (vop_t
*)nfsspec_write
}, /* write */
266 { &vop_lease_desc
, (vop_t
*)spec_lease_check
}, /* lease */
267 { &vop_ioctl_desc
, (vop_t
*)spec_ioctl
}, /* ioctl */
268 { &vop_select_desc
, (vop_t
*)spec_select
}, /* select */
269 { &vop_revoke_desc
, (vop_t
*)spec_revoke
}, /* revoke */
270 { &vop_mmap_desc
, (vop_t
*)spec_mmap
}, /* mmap */
271 { &vop_fsync_desc
, (vop_t
*)nfs_fsync
}, /* fsync */
272 { &vop_seek_desc
, (vop_t
*)spec_seek
}, /* seek */
273 { &vop_remove_desc
, (vop_t
*)spec_remove
}, /* remove */
274 { &vop_link_desc
, (vop_t
*)spec_link
}, /* link */
275 { &vop_rename_desc
, (vop_t
*)spec_rename
}, /* rename */
276 { &vop_mkdir_desc
, (vop_t
*)spec_mkdir
}, /* mkdir */
277 { &vop_rmdir_desc
, (vop_t
*)spec_rmdir
}, /* rmdir */
278 { &vop_symlink_desc
, (vop_t
*)spec_symlink
}, /* symlink */
279 { &vop_readdir_desc
, (vop_t
*)spec_readdir
}, /* readdir */
280 { &vop_readlink_desc
, (vop_t
*)spec_readlink
}, /* readlink */
281 { &vop_abortop_desc
, (vop_t
*)spec_abortop
}, /* abortop */
282 { &vop_inactive_desc
, (vop_t
*)nfs_inactive
}, /* inactive */
283 { &vop_reclaim_desc
, (vop_t
*)nfs_reclaim
}, /* reclaim */
284 { &vop_lock_desc
, (vop_t
*)nfs_lock
}, /* lock */
285 { &vop_unlock_desc
, (vop_t
*)nfs_unlock
}, /* unlock */
286 { &vop_bmap_desc
, (vop_t
*)spec_bmap
}, /* bmap */
287 { &vop_strategy_desc
, (vop_t
*)spec_strategy
}, /* strategy */
288 { &vop_print_desc
, (vop_t
*)nfs_print
}, /* print */
289 { &vop_islocked_desc
, (vop_t
*)nfs_islocked
}, /* islocked */
290 { &vop_pathconf_desc
, (vop_t
*)spec_pathconf
}, /* pathconf */
291 { &vop_advlock_desc
, (vop_t
*)spec_advlock
}, /* advlock */
292 { &vop_blkatoff_desc
, (vop_t
*)spec_blkatoff
}, /* blkatoff */
293 { &vop_valloc_desc
, (vop_t
*)spec_valloc
}, /* valloc */
294 { &vop_reallocblks_desc
, (vop_t
*)spec_reallocblks
}, /* reallocblks */
295 { &vop_vfree_desc
, (vop_t
*)spec_vfree
}, /* vfree */
296 { &vop_truncate_desc
, (vop_t
*)spec_truncate
}, /* truncate */
297 { &vop_update_desc
, (vop_t
*)nfs_update
}, /* update */
298 { &vop_bwrite_desc
, (vop_t
*)vn_bwrite
}, /* bwrite */
299 { &vop_devblocksize_desc
, (vop_t
*)spec_devblocksize
}, /* devblocksize */
300 { &vop_pagein_desc
, (vop_t
*)nfs_pagein
}, /* Pagein */
301 { &vop_pageout_desc
, (vop_t
*)nfs_pageout
}, /* Pageout */
302 { &vop_blktooff_desc
, (vop_t
*)nfs_blktooff
}, /* blktooff */
303 { &vop_offtoblk_desc
, (vop_t
*)nfs_offtoblk
}, /* offtoblk */
304 { &vop_cmap_desc
, (vop_t
*)nfs_cmap
}, /* cmap */
307 struct vnodeopv_desc spec_nfsv2nodeop_opv_desc
=
308 { &spec_nfsv2nodeop_p
, spec_nfsv2nodeop_entries
};
310 VNODEOP_SET(spec_nfsv2nodeop_opv_desc
);
313 vop_t
**fifo_nfsv2nodeop_p
;
314 static struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries
[] = {
315 { &vop_default_desc
, (vop_t
*)vn_default_error
},
316 { &vop_lookup_desc
, (vop_t
*)fifo_lookup
}, /* lookup */
317 { &vop_create_desc
, (vop_t
*)fifo_create
}, /* create */
318 { &vop_mknod_desc
, (vop_t
*)fifo_mknod
}, /* mknod */
319 { &vop_open_desc
, (vop_t
*)fifo_open
}, /* open */
320 { &vop_close_desc
, (vop_t
*)nfsfifo_close
}, /* close */
321 { &vop_access_desc
, (vop_t
*)nfsspec_access
}, /* access */
322 { &vop_getattr_desc
, (vop_t
*)nfs_getattr
}, /* getattr */
323 { &vop_setattr_desc
, (vop_t
*)nfs_setattr
}, /* setattr */
324 { &vop_read_desc
, (vop_t
*)nfsfifo_read
}, /* read */
325 { &vop_write_desc
, (vop_t
*)nfsfifo_write
}, /* write */
326 { &vop_lease_desc
, (vop_t
*)fifo_lease_check
}, /* lease */
327 { &vop_ioctl_desc
, (vop_t
*)fifo_ioctl
}, /* ioctl */
328 { &vop_select_desc
, (vop_t
*)fifo_select
}, /* select */
329 { &vop_revoke_desc
, (vop_t
*)fifo_revoke
}, /* revoke */
330 { &vop_mmap_desc
, (vop_t
*)fifo_mmap
}, /* mmap */
331 { &vop_fsync_desc
, (vop_t
*)nfs_fsync
}, /* fsync */
332 { &vop_seek_desc
, (vop_t
*)fifo_seek
}, /* seek */
333 { &vop_remove_desc
, (vop_t
*)fifo_remove
}, /* remove */
334 { &vop_link_desc
, (vop_t
*)fifo_link
}, /* link */
335 { &vop_rename_desc
, (vop_t
*)fifo_rename
}, /* rename */
336 { &vop_mkdir_desc
, (vop_t
*)fifo_mkdir
}, /* mkdir */
337 { &vop_rmdir_desc
, (vop_t
*)fifo_rmdir
}, /* rmdir */
338 { &vop_symlink_desc
, (vop_t
*)fifo_symlink
}, /* symlink */
339 { &vop_readdir_desc
, (vop_t
*)fifo_readdir
}, /* readdir */
340 { &vop_readlink_desc
, (vop_t
*)fifo_readlink
}, /* readlink */
341 { &vop_abortop_desc
, (vop_t
*)fifo_abortop
}, /* abortop */
342 { &vop_inactive_desc
, (vop_t
*)nfs_inactive
}, /* inactive */
343 { &vop_reclaim_desc
, (vop_t
*)nfs_reclaim
}, /* reclaim */
344 { &vop_lock_desc
, (vop_t
*)nfs_lock
}, /* lock */
345 { &vop_unlock_desc
, (vop_t
*)nfs_unlock
}, /* unlock */
346 { &vop_bmap_desc
, (vop_t
*)fifo_bmap
}, /* bmap */
347 { &vop_strategy_desc
, (vop_t
*)fifo_strategy
}, /* strategy */
348 { &vop_print_desc
, (vop_t
*)nfs_print
}, /* print */
349 { &vop_islocked_desc
, (vop_t
*)nfs_islocked
}, /* islocked */
350 { &vop_pathconf_desc
, (vop_t
*)fifo_pathconf
}, /* pathconf */
351 { &vop_advlock_desc
, (vop_t
*)fifo_advlock
}, /* advlock */
352 { &vop_blkatoff_desc
, (vop_t
*)fifo_blkatoff
}, /* blkatoff */
353 { &vop_valloc_desc
, (vop_t
*)fifo_valloc
}, /* valloc */
354 { &vop_reallocblks_desc
, (vop_t
*)fifo_reallocblks
}, /* reallocblks */
355 { &vop_vfree_desc
, (vop_t
*)fifo_vfree
}, /* vfree */
356 { &vop_truncate_desc
, (vop_t
*)fifo_truncate
}, /* truncate */
357 { &vop_update_desc
, (vop_t
*)nfs_update
}, /* update */
358 { &vop_bwrite_desc
, (vop_t
*)vn_bwrite
}, /* bwrite */
359 { &vop_pagein_desc
, (vop_t
*)nfs_pagein
}, /* Pagein */
360 { &vop_pageout_desc
, (vop_t
*)nfs_pageout
}, /* Pageout */
361 { &vop_blktooff_desc
, (vop_t
*)nfs_blktooff
}, /* blktooff */
362 { &vop_offtoblk_desc
, (vop_t
*)nfs_offtoblk
}, /* offtoblk */
363 { &vop_cmap_desc
, (vop_t
*)nfs_cmap
}, /* cmap */
366 struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc
=
367 { &fifo_nfsv2nodeop_p
, fifo_nfsv2nodeop_entries
};
369 VNODEOP_SET(fifo_nfsv2nodeop_opv_desc
);
372 static int nfs_mknodrpc
__P((struct vnode
*dvp
, struct vnode
**vpp
,
373 struct componentname
*cnp
,
375 static int nfs_removerpc
__P((struct vnode
*dvp
, char *name
, int namelen
,
376 struct ucred
*cred
, struct proc
*proc
));
377 static int nfs_renamerpc
__P((struct vnode
*fdvp
, char *fnameptr
,
378 int fnamelen
, struct vnode
*tdvp
,
379 char *tnameptr
, int tnamelen
,
380 struct ucred
*cred
, struct proc
*proc
));
381 static int nfs_renameit
__P((struct vnode
*sdvp
,
382 struct componentname
*scnp
,
383 struct sillyrename
*sp
));
388 extern u_long nfs_true
, nfs_false
;
389 extern struct nfsstats nfsstats
;
390 extern nfstype nfsv3_type
[9];
391 struct proc
*nfs_iodwant
[NFS_MAXASYNCDAEMON
];
392 struct nfsmount
*nfs_iodmount
[NFS_MAXASYNCDAEMON
];
393 int nfs_numasync
= 0;
394 int nfs_ioddelwri
= 0;
395 #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
397 static int nfsaccess_cache_timeout
= NFS_MAXATTRTIMO
;
398 /* SYSCTL_INT(_vfs_nfs, OID_AUTO, access_cache_timeout, CTLFLAG_RW,
399 &nfsaccess_cache_timeout, 0, "NFS ACCESS cache timeout");
401 #define NFSV3ACCESS_ALL (NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY \
402 | NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE \
403 | NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP)
407 * the following are needed only by nfs_pageout to know how to handle errors
408 * see nfs_pageout comments on explanation of actions.
409 * the errors here are copied from errno.h and errors returned by servers
410 * are expected to match the same numbers here. If not, our actions maybe
413 enum actiontype
{NOACTION
, DUMP
, DUMPANDLOG
, RETRY
, RETRYWITHSLEEP
, SEVER
};
415 static int errorcount
[ELAST
+1]; /* better be zeros when initialized */
417 static const short errortooutcome
[ELAST
+1] = {
419 DUMP
, /* EPERM 1 Operation not permitted */
420 DUMP
, /* ENOENT 2 No such file or directory */
421 DUMPANDLOG
, /* ESRCH 3 No such process */
422 RETRY
, /* EINTR 4 Interrupted system call */
423 DUMP
, /* EIO 5 Input/output error */
424 DUMP
, /* ENXIO 6 Device not configured */
425 DUMPANDLOG
, /* E2BIG 7 Argument list too long */
426 DUMPANDLOG
, /* ENOEXEC 8 Exec format error */
427 DUMPANDLOG
, /* EBADF 9 Bad file descriptor */
428 DUMPANDLOG
, /* ECHILD 10 No child processes */
429 DUMPANDLOG
, /* EDEADLK 11 Resource deadlock avoided - was EAGAIN */
430 RETRY
, /* ENOMEM 12 Cannot allocate memory */
431 DUMP
, /* EACCES 13 Permission denied */
432 DUMPANDLOG
, /* EFAULT 14 Bad address */
433 DUMPANDLOG
, /* ENOTBLK 15 POSIX - Block device required */
434 RETRY
, /* EBUSY 16 Device busy */
435 DUMP
, /* EEXIST 17 File exists */
436 DUMP
, /* EXDEV 18 Cross-device link */
437 DUMP
, /* ENODEV 19 Operation not supported by device */
438 DUMP
, /* ENOTDIR 20 Not a directory */
439 DUMP
, /* EISDIR 21 Is a directory */
440 DUMP
, /* EINVAL 22 Invalid argument */
441 DUMPANDLOG
, /* ENFILE 23 Too many open files in system */
442 DUMPANDLOG
, /* EMFILE 24 Too many open files */
443 DUMPANDLOG
, /* ENOTTY 25 Inappropriate ioctl for device */
444 DUMPANDLOG
, /* ETXTBSY 26 Text file busy - POSIX */
445 DUMP
, /* EFBIG 27 File too large */
446 DUMP
, /* ENOSPC 28 No space left on device */
447 DUMPANDLOG
, /* ESPIPE 29 Illegal seek */
448 DUMP
, /* EROFS 30 Read-only file system */
449 DUMP
, /* EMLINK 31 Too many links */
450 RETRY
, /* EPIPE 32 Broken pipe */
452 DUMPANDLOG
, /* EDOM 33 Numerical argument out of domain */
453 DUMPANDLOG
, /* ERANGE 34 Result too large */
454 RETRY
, /* EAGAIN/EWOULDBLOCK 35 Resource temporarily unavailable */
455 DUMPANDLOG
, /* EINPROGRESS 36 Operation now in progress */
456 DUMPANDLOG
, /* EALREADY 37 Operation already in progress */
457 /* ipc/network software -- argument errors */
458 DUMPANDLOG
, /* ENOTSOC 38 Socket operation on non-socket */
459 DUMPANDLOG
, /* EDESTADDRREQ 39 Destination address required */
460 DUMPANDLOG
, /* EMSGSIZE 40 Message too long */
461 DUMPANDLOG
, /* EPROTOTYPE 41 Protocol wrong type for socket */
462 DUMPANDLOG
, /* ENOPROTOOPT 42 Protocol not available */
463 DUMPANDLOG
, /* EPROTONOSUPPORT 43 Protocol not supported */
464 DUMPANDLOG
, /* ESOCKTNOSUPPORT 44 Socket type not supported */
465 DUMPANDLOG
, /* ENOTSUP 45 Operation not supported */
466 DUMPANDLOG
, /* EPFNOSUPPORT 46 Protocol family not supported */
467 DUMPANDLOG
, /* EAFNOSUPPORT 47 Address family not supported by protocol family */
468 DUMPANDLOG
, /* EADDRINUSE 48 Address already in use */
469 DUMPANDLOG
, /* EADDRNOTAVAIL 49 Can't assign requested address */
470 /* ipc/network software -- operational errors */
471 RETRY
, /* ENETDOWN 50 Network is down */
472 RETRY
, /* ENETUNREACH 51 Network is unreachable */
473 RETRY
, /* ENETRESET 52 Network dropped connection on reset */
474 RETRY
, /* ECONNABORTED 53 Software caused connection abort */
475 RETRY
, /* ECONNRESET 54 Connection reset by peer */
476 RETRY
, /* ENOBUFS 55 No buffer space available */
477 RETRY
, /* EISCONN 56 Socket is already connected */
478 RETRY
, /* ENOTCONN 57 Socket is not connected */
479 RETRY
, /* ESHUTDOWN 58 Can't send after socket shutdown */
480 RETRY
, /* ETOOMANYREFS 59 Too many references: can't splice */
481 RETRY
, /* ETIMEDOUT 60 Operation timed out */
482 RETRY
, /* ECONNREFUSED 61 Connection refused */
484 DUMPANDLOG
, /* ELOOP 62 Too many levels of symbolic links */
485 DUMP
, /* ENAMETOOLONG 63 File name too long */
486 RETRY
, /* EHOSTDOWN 64 Host is down */
487 RETRY
, /* EHOSTUNREACH 65 No route to host */
488 DUMP
, /* ENOTEMPTY 66 Directory not empty */
490 DUMPANDLOG
, /* PROCLIM 67 Too many processes */
491 DUMPANDLOG
, /* EUSERS 68 Too many users */
492 DUMPANDLOG
, /* EDQUOT 69 Disc quota exceeded */
493 /* Network File System */
494 DUMP
, /* ESTALE 70 Stale NFS file handle */
495 DUMP
, /* EREMOTE 71 Too many levels of remote in path */
496 DUMPANDLOG
, /* EBADRPC 72 RPC struct is bad */
497 DUMPANDLOG
, /* ERPCMISMATCH 73 RPC version wrong */
498 DUMPANDLOG
, /* EPROGUNAVAIL 74 RPC prog. not avail */
499 DUMPANDLOG
, /* EPROGMISMATCH 75 Program version wrong */
500 DUMPANDLOG
, /* EPROCUNAVAIL 76 Bad procedure for program */
502 DUMPANDLOG
, /* ENOLCK 77 No locks available */
503 DUMPANDLOG
, /* ENOSYS 78 Function not implemented */
504 DUMPANDLOG
, /* EFTYPE 79 Inappropriate file type or format */
505 DUMPANDLOG
, /* EAUTH 80 Authentication error */
506 DUMPANDLOG
, /* ENEEDAUTH 81 Need authenticator */
507 /* Intelligent device errors */
508 DUMPANDLOG
, /* EPWROFF 82 Device power is off */
509 DUMPANDLOG
, /* EDEVERR 83 Device error, e.g. paper out */
510 DUMPANDLOG
, /* EOVERFLOW 84 Value too large to be stored in data type */
511 /* Program loading errors */
512 DUMPANDLOG
, /* EBADEXEC 85 Bad executable */
513 DUMPANDLOG
, /* EBADARCH 86 Bad CPU type in executable */
514 DUMPANDLOG
, /* ESHLIBVERS 87 Shared library version mismatch */
515 DUMPANDLOG
, /* EBADMACHO 88 Malformed Macho file */
520 nfs_pageouterrorhandler(error
)
526 return(errortooutcome
[error
]);
530 nfs3_access_otw(struct vnode
*vp
,
537 int error
= 0, attrflag
;
539 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
540 caddr_t bpos
, dpos
, cp2
;
541 register long t1
, t2
;
544 struct nfsnode
*np
= VTONFS(vp
);
548 nfsstats
.rpccnt
[NFSPROC_ACCESS
]++;
549 nfsm_reqhead(vp
, NFSPROC_ACCESS
, NFSX_FH(v3
) + NFSX_UNSIGNED
);
551 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
552 *tl
= txdr_unsigned(wmode
);
553 nfsm_request(vp
, NFSPROC_ACCESS
, p
, cred
, &xid
);
554 nfsm_postop_attr(vp
, attrflag
, &xid
);
556 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
557 rmode
= fxdr_unsigned(u_int32_t
, *tl
);
559 np
->n_modeuid
= cred
->cr_uid
;
561 np
->n_modestamp
= now
.tv_sec
;
568 * nfs access vnode op.
569 * For nfs version 2, just return ok. File accesses may fail later.
570 * For nfs version 3, use the access rpc to check accessibility. If file modes
571 * are changed on the server, accesses might still fail later.
575 struct vop_access_args
/* {
578 struct ucred *a_cred;
582 register struct vnode
*vp
= ap
->a_vp
;
585 int v3
= NFS_ISV3(vp
);
586 struct nfsnode
*np
= VTONFS(vp
);
590 * For nfs v3, do an access rpc, otherwise you are stuck emulating
591 * ufs_access() locally using the vattr. This may not be correct,
592 * since the server may apply other access criteria such as
593 * client uid-->server uid mapping that we do not know about, but
594 * this is better than just returning anything that is lying about
598 if (ap
->a_mode
& VREAD
)
599 mode
= NFSV3ACCESS_READ
;
602 if (vp
->v_type
== VDIR
) {
603 if (ap
->a_mode
& VWRITE
)
604 mode
|= NFSV3ACCESS_MODIFY
|
605 NFSV3ACCESS_EXTEND
| NFSV3ACCESS_DELETE
;
606 if (ap
->a_mode
& VEXEC
)
607 mode
|= NFSV3ACCESS_LOOKUP
;
609 if (ap
->a_mode
& VWRITE
)
610 mode
|= NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
;
611 if (ap
->a_mode
& VEXEC
)
612 mode
|= NFSV3ACCESS_EXECUTE
;
614 /* XXX safety belt, only make blanket request if caching */
615 if (nfsaccess_cache_timeout
> 0) {
616 wmode
= NFSV3ACCESS_READ
| NFSV3ACCESS_MODIFY
|
617 NFSV3ACCESS_EXTEND
| NFSV3ACCESS_EXECUTE
|
618 NFSV3ACCESS_DELETE
| NFSV3ACCESS_LOOKUP
;
623 * Does our cached result allow us to give a definite yes to
627 if (now
.tv_sec
< np
->n_modestamp
+ nfsaccess_cache_timeout
&&
628 ap
->a_cred
->cr_uid
== np
->n_modeuid
&&
629 (np
->n_mode
& mode
) == mode
) {
630 /* nfsstats.accesscache_hits++; */
633 * Either a no, or a don't know. Go to the wire.
635 /* nfsstats.accesscache_misses++; */
636 error
= nfs3_access_otw(vp
, wmode
, ap
->a_p
,ap
->a_cred
);
638 if ((np
->n_mode
& mode
) != mode
)
643 return (nfsspec_access(ap
)); /* NFSv2 case checks for EROFS here */
645 * Disallow write attempts on filesystems mounted read-only;
646 * unless the file is a socket, fifo, or a block or character
647 * device resident on the filesystem.
648 * CSM - moved EROFS check down per NetBSD rev 1.71. So you
649 * get the correct error value with layered filesystems.
650 * EKN - moved the return(error) below this so it does get called.
652 if (!error
&& (ap
->a_mode
& VWRITE
) && (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
653 switch (vp
->v_type
) {
654 case VREG
: case VDIR
: case VLNK
:
665 * Check to see if the type is ok
666 * and that deletion is not in progress.
667 * For paged in text files, you will need to flush the page cache
668 * if consistency is lost.
674 struct vop_open_args
/* {
677 struct ucred *a_cred;
681 register struct vnode
*vp
= ap
->a_vp
;
682 struct nfsnode
*np
= VTONFS(vp
);
683 struct nfsmount
*nmp
= VFSTONFS(vp
->v_mount
);
687 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VDIR
&& vp
->v_type
!= VLNK
) {
691 * Get a valid lease. If cached data is stale, flush it.
693 if (nmp
->nm_flag
& NFSMNT_NQNFS
) {
694 if (NQNFS_CKINVALID(vp
, np
, ND_READ
)) {
696 error
= nqnfs_getlease(vp
, ND_READ
, ap
->a_cred
,
698 } while (error
== NQNFS_EXPIRED
);
701 if (np
->n_lrev
!= np
->n_brev
||
702 (np
->n_flag
& NQNFSNONCACHE
)) {
703 if ((error
= nfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
,
704 ap
->a_p
, 1)) == EINTR
)
706 np
->n_brev
= np
->n_lrev
;
710 if (np
->n_flag
& NMODIFIED
) {
711 if ((error
= nfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
,
712 ap
->a_p
, 1)) == EINTR
)
715 if (vp
->v_type
== VDIR
)
716 np
->n_direofoffset
= 0;
717 error
= VOP_GETATTR(vp
, &vattr
, ap
->a_cred
, ap
->a_p
);
720 /* if directory changed, purge any name cache entries */
721 if ((vp
->v_type
== VDIR
) &&
722 (np
->n_mtime
!= vattr
.va_mtime
.tv_sec
))
724 np
->n_mtime
= vattr
.va_mtime
.tv_sec
;
726 error
= VOP_GETATTR(vp
, &vattr
, ap
->a_cred
, ap
->a_p
);
729 if (np
->n_mtime
!= vattr
.va_mtime
.tv_sec
) {
730 if (vp
->v_type
== VDIR
) {
731 np
->n_direofoffset
= 0;
733 /* purge name cache entries */
736 if ((error
= nfs_vinvalbuf(vp
, V_SAVE
,
737 ap
->a_cred
, ap
->a_p
, 1)) == EINTR
)
739 np
->n_mtime
= vattr
.va_mtime
.tv_sec
;
743 if ((nmp
->nm_flag
& NFSMNT_NQNFS
) == 0)
744 np
->n_xid
= 0; /* For Open/Close consistency */
750 * What an NFS client should do upon close after writing is a debatable issue.
751 * Most NFS clients push delayed writes to the server upon close, basically for
753 * 1 - So that any write errors may be reported back to the client process
754 * doing the close system call. By far the two most likely errors are
755 * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure.
756 * 2 - To put a worst case upper bound on cache inconsistency between
757 * multiple clients for the file.
758 * There is also a consistency problem for Version 2 of the protocol w.r.t.
759 * not being able to tell if other clients are writing a file concurrently,
760 * since there is no way of knowing if the changed modify time in the reply
761 * is only due to the write for this client.
762 * (NFS Version 3 provides weak cache consistency data in the reply that
763 * should be sufficient to detect and handle this case.)
765 * The current code does the following:
766 * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
767 * for NFS Version 3 - flush dirty buffers to the server but don't invalidate
768 * or commit them (this satisfies 1 and 2 except for the
769 * case where the server crashes after this close but
770 * before the commit RPC, which is felt to be "good
771 * enough". Changing the last argument to nfs_flush() to
772 * a 1 would force a commit operation, if it is felt a
773 * commit is necessary now.
774 * for NQNFS - do nothing now, since 2 is dealt with via leases and
775 * 1 should be dealt with via an fsync() system call for
776 * cases where write errors are important.
781 struct vop_close_args
/* {
782 struct vnodeop_desc *a_desc;
785 struct ucred *a_cred;
789 register struct vnode
*vp
= ap
->a_vp
;
790 register struct nfsnode
*np
= VTONFS(vp
);
791 struct nfsmount
*nmp
;
794 if (vp
->v_type
== VREG
) {
796 register struct sillyrename
*sp
= np
->n_sillyrename
;
798 kprintf("nfs_close: %s, dvp=%x, vp=%x, ap=%x, np=%x, sp=%x\n",
799 &sp
->s_name
[0], (unsigned)(sp
->s_dvp
), (unsigned)vp
,
800 (unsigned)ap
, (unsigned)np
, (unsigned)sp
);
802 nmp
= VFSTONFS(vp
->v_mount
);
805 if ((nmp
->nm_flag
& NFSMNT_NQNFS
) == 0 &&
806 (np
->n_flag
& NMODIFIED
)) {
807 int getlock
= !VOP_ISLOCKED(vp
);
809 error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, ap
->a_p
);
810 if (!error
&& !VFSTONFS(vp
->v_mount
)) {
811 VOP_UNLOCK(vp
, 0, ap
->a_p
);
818 error
= nfs_flush(vp
, ap
->a_cred
, MNT_WAIT
, ap
->a_p
, 1);
820 * We cannot clear the NMODIFIED bit in np->n_flag due to
821 * potential races with other processes
822 * NMODIFIED is a hint
824 /* np->n_flag &= ~NMODIFIED; */
826 error
= nfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
, ap
->a_p
, 1);
830 VOP_UNLOCK(vp
, 0, ap
->a_p
);
832 if (np
->n_flag
& NWRITEERR
) {
833 np
->n_flag
&= ~NWRITEERR
;
841 * nfs getattr call from vfs.
845 struct vop_getattr_args
/* {
848 struct ucred *a_cred;
852 register struct vnode
*vp
= ap
->a_vp
;
853 register struct nfsnode
*np
= VTONFS(vp
);
859 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
864 FSDBG_TOP(513, np
->n_size
, np
, np
->n_vattr
.va_size
, np
->n_flag
);
866 * Update local times for special files.
868 if (np
->n_flag
& (NACC
| NUPD
))
871 * First look in the cache.
873 if ((error
= nfs_getattrcache(vp
, ap
->a_vap
)) == 0) {
874 FSDBG_BOT(513, np
->n_size
, 0, np
->n_vattr
.va_size
, np
->n_flag
);
877 if (error
!= ENOENT
) {
878 FSDBG_BOT(513, np
->n_size
, error
, np
->n_vattr
.va_size
,
883 if (!VFSTONFS(vp
->v_mount
)) {
884 FSDBG_BOT(513, np
->n_size
, ENXIO
, np
->n_vattr
.va_size
, np
->n_flag
);
890 if (v3
&& nfsaccess_cache_timeout
> 0) {
891 /* nfsstats.accesscache_misses++; */
892 if (error
= nfs3_access_otw(vp
, NFSV3ACCESS_ALL
, ap
->a_p
,
895 if ((error
= nfs_getattrcache(vp
, ap
->a_vap
)) == 0)
903 nfsstats
.rpccnt
[NFSPROC_GETATTR
]++;
904 nfsm_reqhead(vp
, NFSPROC_GETATTR
, NFSX_FH(v3
));
906 nfsm_request(vp
, NFSPROC_GETATTR
, ap
->a_p
, ap
->a_cred
, &xid
);
908 nfsm_loadattr(vp
, ap
->a_vap
, &xid
);
909 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 */
926 error
= nfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
,
928 FSDBG(513, -1, np
, -2, error
);
930 np
->n_mtime
= ap
->a_vap
->va_mtime
.tv_sec
;
936 FSDBG_BOT(513, np
->n_size
, -1, np
->n_vattr
.va_size
, error
);
945 struct vop_setattr_args
/* {
946 struct vnodeop_desc *a_desc;
949 struct ucred *a_cred;
953 register struct vnode
*vp
= ap
->a_vp
;
954 register struct nfsnode
*np
= VTONFS(vp
);
955 register struct vattr
*vap
= ap
->a_vap
;
963 #ifdef XXX /* enable this code soon! (but test it first) */
965 * Setting of flags is not supported.
967 if (vap
->va_flags
!= VNOVAL
)
972 * Disallow write attempts if the filesystem is mounted read-only.
974 if ((vap
->va_flags
!= VNOVAL
|| vap
->va_uid
!= (uid_t
)VNOVAL
||
975 vap
->va_gid
!= (gid_t
)VNOVAL
|| vap
->va_atime
.tv_sec
!= VNOVAL
||
976 vap
->va_mtime
.tv_sec
!= VNOVAL
|| vap
->va_mode
!= (mode_t
)VNOVAL
) &&
977 (vp
->v_mount
->mnt_flag
& MNT_RDONLY
))
979 if (vap
->va_size
!= VNOVAL
) {
980 switch (vp
->v_type
) {
987 if (vap
->va_mtime
.tv_sec
== VNOVAL
&&
988 vap
->va_atime
.tv_sec
== VNOVAL
&&
989 vap
->va_mode
== (u_short
)VNOVAL
&&
990 vap
->va_uid
== (uid_t
)VNOVAL
&&
991 vap
->va_gid
== (gid_t
)VNOVAL
)
993 vap
->va_size
= VNOVAL
;
997 * Disallow write attempts if the filesystem is
1000 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
1002 FSDBG_TOP(512, np
->n_size
, vap
->va_size
,
1003 np
->n_vattr
.va_size
, np
->n_flag
);
1004 if (np
->n_flag
& NMODIFIED
) {
1005 if (vap
->va_size
== 0)
1006 error
= nfs_vinvalbuf(vp
, 0,
1007 ap
->a_cred
, ap
->a_p
, 1);
1009 error
= nfs_vinvalbuf(vp
, V_SAVE
,
1010 ap
->a_cred
, ap
->a_p
, 1);
1012 printf("nfs_setattr: nfs_vinvalbuf %d\n", error
);
1013 FSDBG_BOT(512, np
->n_size
, vap
->va_size
,
1014 np
->n_vattr
.va_size
, -1);
1017 } else if (np
->n_size
> vap
->va_size
) { /* shrinking? */
1022 biosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
1023 obn
= (np
->n_size
- 1) / biosize
;
1024 bn
= vap
->va_size
/ biosize
;
1025 for ( ; obn
>= bn
; obn
--)
1026 if (nfs_buf_incore(vp
, obn
)) {
1027 bp
= nfs_buf_get(vp
, obn
, biosize
, 0, BLK_READ
);
1031 int neweofoff
, mustwrite
;
1033 neweofoff
= vap
->va_size
- NBOFF(bp
);
1034 /* check for any dirty data before the new EOF */
1035 if (bp
->nb_dirtyend
&& bp
->nb_dirtyoff
< neweofoff
) {
1036 /* clip dirty range to EOF */
1037 if (bp
->nb_dirtyend
> neweofoff
)
1038 bp
->nb_dirtyend
= neweofoff
;
1041 bp
->nb_dirty
&= (1 << round_page_32(neweofoff
)/PAGE_SIZE
) - 1;
1045 /* gotta write out dirty data before invalidating */
1046 /* (NB_STABLE indicates that data writes should be FILESYNC) */
1047 /* (NB_NOCACHE indicates buffer should be discarded) */
1048 CLR(bp
->nb_flags
, (NB_DONE
| NB_ERROR
| NB_INVAL
| NB_ASYNC
| NB_READ
));
1049 SET(bp
->nb_flags
, NB_STABLE
| NB_NOCACHE
);
1051 * NFS has embedded ucred so crhold() risks zone corruption
1053 if (bp
->nb_wcred
== NOCRED
)
1054 bp
->nb_wcred
= crdup(ap
->a_cred
);
1055 error
= nfs_buf_write(bp
);
1056 // Note: bp has been released
1058 FSDBG(512, bp
, 0xd00dee, 0xbad, error
);
1059 np
->n_error
= error
;
1060 np
->n_flag
|= NWRITEERR
;
1067 FSDBG(512, bp
, bp
->nb_flags
, 0, obn
);
1068 SET(bp
->nb_flags
, NB_INVAL
);
1069 nfs_buf_release(bp
);
1074 np
->n_size
= np
->n_vattr
.va_size
= vap
->va_size
;
1075 ubc_setsize(vp
, (off_t
)vap
->va_size
); /* XXX error? */
1077 } else if ((vap
->va_mtime
.tv_sec
!= VNOVAL
||
1078 vap
->va_atime
.tv_sec
!= VNOVAL
) &&
1079 (np
->n_flag
& NMODIFIED
) && vp
->v_type
== VREG
) {
1080 error
= nfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
, ap
->a_p
, 1);
1084 error
= nfs_setattrrpc(vp
, vap
, ap
->a_cred
, ap
->a_p
);
1085 FSDBG_BOT(512, np
->n_size
, vap
->va_size
, np
->n_vattr
.va_size
, error
);
1086 if (error
&& vap
->va_size
!= VNOVAL
) {
1087 /* make every effort to resync file size w/ server... */
1088 int err
= 0; /* preserve "error" for return */
1090 printf("nfs_setattr: nfs_setattrrpc %d\n", error
);
1091 np
->n_size
= np
->n_vattr
.va_size
= tsize
;
1092 ubc_setsize(vp
, (off_t
)np
->n_size
); /* XXX check error */
1093 vap
->va_size
= tsize
;
1094 err
= nfs_setattrrpc(vp
, vap
, ap
->a_cred
, ap
->a_p
);
1096 printf("nfs_setattr1: nfs_setattrrpc %d\n", err
);
1102 * Do an nfs setattr rpc.
1105 nfs_setattrrpc(vp
, vap
, cred
, procp
)
1106 register struct vnode
*vp
;
1107 register struct vattr
*vap
;
1111 register struct nfsv2_sattr
*sp
;
1112 register caddr_t cp
;
1113 register long t1
, t2
;
1114 caddr_t bpos
, dpos
, cp2
;
1116 int error
= 0, wccflag
= NFSV3_WCCRATTR
;
1117 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1122 if (!VFSTONFS(vp
->v_mount
))
1126 nfsstats
.rpccnt
[NFSPROC_SETATTR
]++;
1127 nfsm_reqhead(vp
, NFSPROC_SETATTR
, NFSX_FH(v3
) + NFSX_SATTR(v3
));
1130 if (vap
->va_mode
!= (u_short
)VNOVAL
) {
1131 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1133 *tl
= txdr_unsigned(vap
->va_mode
);
1135 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1138 if (vap
->va_uid
!= (uid_t
)VNOVAL
) {
1139 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1141 *tl
= txdr_unsigned(vap
->va_uid
);
1143 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1146 if (vap
->va_gid
!= (gid_t
)VNOVAL
) {
1147 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1149 *tl
= txdr_unsigned(vap
->va_gid
);
1151 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1154 if (vap
->va_size
!= VNOVAL
) {
1155 nfsm_build(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
1157 txdr_hyper(&vap
->va_size
, tl
);
1159 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1163 if (vap
->va_atime
.tv_sec
!= VNOVAL
) {
1164 if (vap
->va_atime
.tv_sec
!= now
.tv_sec
) {
1165 nfsm_build(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
1166 *tl
++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT
);
1167 txdr_nfsv3time(&vap
->va_atime
, tl
);
1169 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1170 *tl
= txdr_unsigned(NFSV3SATTRTIME_TOSERVER
);
1173 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1174 *tl
= txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE
);
1176 if (vap
->va_mtime
.tv_sec
!= VNOVAL
) {
1177 if (vap
->va_mtime
.tv_sec
!= now
.tv_sec
) {
1178 nfsm_build(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
1179 *tl
++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT
);
1180 txdr_nfsv3time(&vap
->va_mtime
, tl
);
1182 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1183 *tl
= txdr_unsigned(NFSV3SATTRTIME_TOSERVER
);
1186 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1187 *tl
= txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE
);
1189 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1192 nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1193 if (vap
->va_mode
== (u_short
)VNOVAL
)
1194 sp
->sa_mode
= VNOVAL
;
1196 sp
->sa_mode
= vtonfsv2_mode(vp
->v_type
, vap
->va_mode
);
1197 if (vap
->va_uid
== (uid_t
)VNOVAL
)
1198 sp
->sa_uid
= VNOVAL
;
1200 sp
->sa_uid
= txdr_unsigned(vap
->va_uid
);
1201 if (vap
->va_gid
== (gid_t
)VNOVAL
)
1202 sp
->sa_gid
= VNOVAL
;
1204 sp
->sa_gid
= txdr_unsigned(vap
->va_gid
);
1205 sp
->sa_size
= txdr_unsigned(vap
->va_size
);
1206 txdr_nfsv2time(&vap
->va_atime
, &sp
->sa_atime
);
1207 txdr_nfsv2time(&vap
->va_mtime
, &sp
->sa_mtime
);
1209 nfsm_request(vp
, NFSPROC_SETATTR
, procp
, cred
, &xid
);
1211 nfsm_wcc_data(vp
, wccflag
, &xid
);
1213 VTONFS(vp
)->n_xid
= 0;
1215 nfsm_loadattr(vp
, (struct vattr
*)0, &xid
);
1221 * nfs lookup call, one step at a time...
1222 * First look in cache
1223 * If not found, unlock the directory nfsnode and do the rpc
1227 struct vop_lookup_args
/* {
1228 struct vnodeop_desc *a_desc;
1229 struct vnode *a_dvp;
1230 struct vnode **a_vpp;
1231 struct componentname *a_cnp;
1234 register struct componentname
*cnp
= ap
->a_cnp
;
1235 register struct vnode
*dvp
= ap
->a_dvp
;
1236 register struct vnode
**vpp
= ap
->a_vpp
;
1237 register int flags
= cnp
->cn_flags
;
1238 register struct vnode
*newvp
;
1239 register u_long
*tl
;
1240 register caddr_t cp
;
1241 register long t1
, t2
;
1242 caddr_t bpos
, dpos
, cp2
;
1243 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1247 int lockparent
, wantparent
, error
= 0, attrflag
, fhsize
;
1248 int v3
= NFS_ISV3(dvp
);
1249 struct proc
*p
= cnp
->cn_proc
;
1254 if ((flags
& ISLASTCN
) && (dvp
->v_mount
->mnt_flag
& MNT_RDONLY
) &&
1255 (cnp
->cn_nameiop
== DELETE
|| cnp
->cn_nameiop
== RENAME
))
1258 if (dvp
->v_type
!= VDIR
)
1261 lockparent
= flags
& LOCKPARENT
;
1262 wantparent
= flags
& (LOCKPARENT
|WANTPARENT
);
1265 /* if directory has changed, purge any name cache entries */
1266 if (!VOP_GETATTR(dvp
, &vattr
, cnp
->cn_cred
, p
) &&
1267 (np
->n_mtime
!= vattr
.va_mtime
.tv_sec
))
1270 if ((error
= cache_lookup(dvp
, vpp
, cnp
)) && error
!= ENOENT
) {
1277 * See the comment starting `Step through' in ufs/ufs_lookup.c
1278 * for an explanation of the locking protocol
1282 * Note: we need to make sure to get a lock/ref on newvp
1283 * before we possibly go off to the server in VOP_ACCESS.
1288 } else if (flags
& ISDOTDOT
) {
1289 VOP_UNLOCK(dvp
, 0, p
);
1290 error
= vget(newvp
, LK_EXCLUSIVE
, p
);
1292 error
= vn_lock(dvp
, LK_EXCLUSIVE
, p
);
1294 error
= vget(newvp
, LK_EXCLUSIVE
, p
);
1296 VOP_UNLOCK(dvp
, 0, p
);
1300 goto cache_lookup_out
;
1302 if ((error
= VOP_ACCESS(dvp
, VEXEC
, cnp
->cn_cred
, p
))) {
1311 if ((dvp
!= newvp
) && (!lockparent
|| !(flags
& ISLASTCN
)))
1312 VOP_UNLOCK(dvp
, 0, p
);
1314 if (vpid
== newvp
->v_id
) {
1315 if (!VOP_GETATTR(newvp
, &vattr
, cnp
->cn_cred
, p
)
1316 && vattr
.va_ctime
.tv_sec
== VTONFS(newvp
)->n_ctime
) {
1317 nfsstats
.lookupcache_hits
++;
1318 if (cnp
->cn_nameiop
!= LOOKUP
&& (flags
& ISLASTCN
))
1319 cnp
->cn_flags
|= SAVENAME
;
1320 error
= 0; /* ignore any from VOP_GETATTR */
1326 if ((dvp
!= newvp
) && lockparent
&& (flags
& ISLASTCN
))
1327 VOP_UNLOCK(dvp
, 0, p
);
1329 error
= vn_lock(dvp
, LK_EXCLUSIVE
, p
);
1337 nfsstats
.lookupcache_misses
++;
1338 nfsstats
.rpccnt
[NFSPROC_LOOKUP
]++;
1339 len
= cnp
->cn_namelen
;
1340 nfsm_reqhead(dvp
, NFSPROC_LOOKUP
,
1341 NFSX_FH(v3
) + NFSX_UNSIGNED
+ nfsm_rndup(len
));
1342 nfsm_fhtom(dvp
, v3
);
1343 nfsm_strtom(cnp
->cn_nameptr
, len
, NFS_MAXNAMLEN
);
1344 /* nfsm_request for NFSv2 causes you to goto to nfsmout upon errors */
1345 nfsm_request(dvp
, NFSPROC_LOOKUP
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
1348 nfsm_postop_attr(dvp
, attrflag
, &xid
);
1352 nfsm_getfh(fhp
, fhsize
, v3
);
1355 * Handle RENAME case...
1357 if (cnp
->cn_nameiop
== RENAME
&& wantparent
&& (flags
& ISLASTCN
)) {
1358 if (NFS_CMPFH(np
, fhp
, fhsize
)) {
1363 if ((error
= nfs_nget(dvp
->v_mount
, fhp
, fhsize
, &np
))) {
1369 u_int64_t dxid
= xid
;
1371 nfsm_postop_attr(newvp
, attrflag
, &xid
);
1372 nfsm_postop_attr(dvp
, attrflag
, &dxid
);
1374 nfsm_loadattr(newvp
, (struct vattr
*)0, &xid
);
1377 cnp
->cn_flags
|= SAVENAME
;
1379 VOP_UNLOCK(dvp
, 0, p
);
1384 if (NFS_CMPFH(np
, fhp
, fhsize
)) {
1387 } else if (flags
& ISDOTDOT
) {
1388 VOP_UNLOCK(dvp
, 0, p
);
1389 error
= nfs_nget(dvp
->v_mount
, fhp
, fhsize
, &np
);
1392 vn_lock(dvp
, LK_EXCLUSIVE
+ LK_RETRY
, p
);
1396 if (!lockparent
|| !(flags
& ISLASTCN
))
1397 unlockdvp
= 1; /* keep dvp locked until after postops */
1398 if (error
= vn_lock(dvp
, LK_EXCLUSIVE
, p
)) {
1404 if ((error
= nfs_nget(dvp
->v_mount
, fhp
, fhsize
, &np
))) {
1408 if (!lockparent
|| !(flags
& ISLASTCN
))
1409 unlockdvp
= 1; /* keep dvp locked until after postops */
1413 u_int64_t dxid
= xid
;
1415 nfsm_postop_attr(newvp
, attrflag
, &xid
);
1416 nfsm_postop_attr(dvp
, attrflag
, &dxid
);
1418 nfsm_loadattr(newvp
, (struct vattr
*)0, &xid
);
1419 if (cnp
->cn_nameiop
!= LOOKUP
&& (flags
& ISLASTCN
))
1420 cnp
->cn_flags
|= SAVENAME
;
1421 if ((cnp
->cn_flags
& MAKEENTRY
) &&
1422 (cnp
->cn_nameiop
!= DELETE
|| !(flags
& ISLASTCN
))) {
1423 np
->n_ctime
= np
->n_vattr
.va_ctime
.tv_sec
;
1424 cache_enter(dvp
, newvp
, cnp
);
1429 VOP_UNLOCK(dvp
, 0, p
);
1431 if (newvp
!= NULLVP
) {
1438 if ((cnp
->cn_nameiop
== CREATE
|| cnp
->cn_nameiop
== RENAME
) &&
1439 (flags
& ISLASTCN
) && error
== ENOENT
) {
1440 if (dvp
->v_mount
&& (dvp
->v_mount
->mnt_flag
& MNT_RDONLY
))
1443 error
= EJUSTRETURN
;
1445 VOP_UNLOCK(dvp
, 0, p
);
1447 if (cnp
->cn_nameiop
!= LOOKUP
&& (flags
& ISLASTCN
))
1448 cnp
->cn_flags
|= SAVENAME
;
1456 * Just call nfs_bioread() to do the work.
1460 struct vop_read_args
/* {
1464 struct ucred *a_cred;
1467 register struct vnode
*vp
= ap
->a_vp
;
1469 if (vp
->v_type
!= VREG
)
1471 return (nfs_bioread(vp
, ap
->a_uio
, ap
->a_ioflag
, ap
->a_cred
, 0));
1480 struct vop_readlink_args
/* {
1483 struct ucred *a_cred;
1486 register struct vnode
*vp
= ap
->a_vp
;
1488 if (vp
->v_type
!= VLNK
)
1490 return (nfs_bioread(vp
, ap
->a_uio
, 0, ap
->a_cred
, 0));
1494 * Do a readlink rpc.
1495 * Called by nfs_doio() from below the buffer cache.
1498 nfs_readlinkrpc(vp
, uiop
, cred
)
1499 register struct vnode
*vp
;
1503 register u_long
*tl
;
1504 register caddr_t cp
;
1505 register long t1
, t2
;
1506 caddr_t bpos
, dpos
, cp2
;
1507 int error
= 0, len
, attrflag
;
1508 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1512 if (!VFSTONFS(vp
->v_mount
))
1516 nfsstats
.rpccnt
[NFSPROC_READLINK
]++;
1517 nfsm_reqhead(vp
, NFSPROC_READLINK
, NFSX_FH(v3
));
1519 nfsm_request(vp
, NFSPROC_READLINK
, uiop
->uio_procp
, cred
, &xid
);
1521 nfsm_postop_attr(vp
, attrflag
, &xid
);
1523 nfsm_strsiz(len
, NFS_MAXPATHLEN
);
1524 if (len
== NFS_MAXPATHLEN
) {
1525 struct nfsnode
*np
= VTONFS(vp
);
1528 panic("nfs_readlinkrpc: null np");
1530 if (np
->n_size
&& np
->n_size
< NFS_MAXPATHLEN
)
1533 nfsm_mtouio(uiop
, len
);
1544 nfs_readrpc(vp
, uiop
, cred
)
1545 register struct vnode
*vp
;
1549 register u_long
*tl
;
1550 register caddr_t cp
;
1551 register long t1
, t2
;
1552 caddr_t bpos
, dpos
, cp2
;
1553 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1554 struct nfsmount
*nmp
;
1555 int error
= 0, len
, retlen
, tsiz
, eof
= 0, attrflag
;
1559 FSDBG_TOP(536, vp
, uiop
->uio_offset
, uiop
->uio_resid
, 0);
1560 nmp
= VFSTONFS(vp
->v_mount
);
1564 nmrsize
= nmp
->nm_rsize
;
1566 tsiz
= uiop
->uio_resid
;
1567 if (((u_int64_t
)uiop
->uio_offset
+ (unsigned int)tsiz
> 0xffffffff) && !v3
) {
1568 FSDBG_BOT(536, vp
, uiop
->uio_offset
, uiop
->uio_resid
, EFBIG
);
1572 nfsstats
.rpccnt
[NFSPROC_READ
]++;
1573 len
= (tsiz
> nmrsize
) ? nmrsize
: tsiz
;
1574 nfsm_reqhead(vp
, NFSPROC_READ
, NFSX_FH(v3
) + NFSX_UNSIGNED
* 3);
1576 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
* 3);
1578 txdr_hyper(&uiop
->uio_offset
, tl
);
1579 *(tl
+ 2) = txdr_unsigned(len
);
1581 *tl
++ = txdr_unsigned(uiop
->uio_offset
);
1582 *tl
++ = txdr_unsigned(len
);
1585 FSDBG(536, vp
, uiop
->uio_offset
, len
, 0);
1586 nfsm_request(vp
, NFSPROC_READ
, uiop
->uio_procp
, cred
, &xid
);
1588 nfsm_postop_attr(vp
, attrflag
, &xid
);
1593 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1594 eof
= fxdr_unsigned(int, *(tl
+ 1));
1596 nfsm_loadattr(vp
, (struct vattr
*)0, &xid
);
1597 nfsm_strsiz(retlen
, nmrsize
);
1598 nfsm_mtouio(uiop
, retlen
);
1602 if (eof
|| retlen
== 0)
1604 } else if (retlen
< len
)
1608 FSDBG_BOT(536, vp
, eof
, uiop
->uio_resid
, error
);
1616 nfs_writerpc(vp
, uiop
, cred
, iomode
, must_commit
)
1617 register struct vnode
*vp
;
1618 register struct uio
*uiop
;
1620 int *iomode
, *must_commit
;
1622 register u_long
*tl
;
1623 register caddr_t cp
;
1624 register int t1
, t2
, backup
;
1625 caddr_t bpos
, dpos
, cp2
;
1626 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1627 struct nfsmount
*nmp
;
1628 int error
= 0, len
, tsiz
, wccflag
= NFSV3_WCCRATTR
, rlen
, commit
;
1629 int v3
, committed
= NFSV3WRITE_FILESYNC
;
1633 if (uiop
->uio_iovcnt
!= 1)
1634 panic("nfs_writerpc: iovcnt > 1");
1636 FSDBG_TOP(537, vp
, uiop
->uio_offset
, uiop
->uio_resid
, *iomode
);
1637 nmp
= VFSTONFS(vp
->v_mount
);
1642 tsiz
= uiop
->uio_resid
;
1643 if (((u_int64_t
)uiop
->uio_offset
+ (unsigned int)tsiz
> 0xffffffff) && !v3
) {
1644 FSDBG_BOT(537, vp
, uiop
->uio_offset
, uiop
->uio_resid
, EFBIG
);
1648 nmp
= VFSTONFS(vp
->v_mount
);
1653 nfsstats
.rpccnt
[NFSPROC_WRITE
]++;
1654 len
= (tsiz
> nmp
->nm_wsize
) ? nmp
->nm_wsize
: tsiz
;
1655 nfsm_reqhead(vp
, NFSPROC_WRITE
,
1656 NFSX_FH(v3
) + 5 * NFSX_UNSIGNED
+ nfsm_rndup(len
));
1659 nfsm_build(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1660 txdr_hyper(&uiop
->uio_offset
, tl
);
1662 *tl
++ = txdr_unsigned(len
);
1663 *tl
++ = txdr_unsigned(*iomode
);
1665 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1666 *++tl
= txdr_unsigned(uiop
->uio_offset
);
1669 *tl
= txdr_unsigned(len
);
1670 FSDBG(537, vp
, uiop
->uio_offset
, len
, 0);
1671 nfsm_uiotom(uiop
, len
);
1672 nfsm_request(vp
, NFSPROC_WRITE
, uiop
->uio_procp
, cred
, &xid
);
1673 nmp
= VFSTONFS(vp
->v_mount
);
1677 wccflag
= NFSV3_WCCCHK
;
1678 nfsm_wcc_data(vp
, wccflag
, &xid
);
1680 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
+
1682 rlen
= fxdr_unsigned(int, *tl
++);
1686 } else if (rlen
< len
) {
1687 backup
= len
- rlen
;
1688 uiop
->uio_iov
->iov_base
-= backup
;
1689 uiop
->uio_iov
->iov_len
+= backup
;
1690 uiop
->uio_offset
-= backup
;
1691 uiop
->uio_resid
+= backup
;
1694 commit
= fxdr_unsigned(int, *tl
++);
1697 * Return the lowest committment level
1698 * obtained by any of the RPCs.
1700 if (committed
== NFSV3WRITE_FILESYNC
)
1702 else if (committed
== NFSV3WRITE_DATASYNC
&&
1703 commit
== NFSV3WRITE_UNSTABLE
)
1705 if ((nmp
->nm_state
& NFSSTA_HASWRITEVERF
) == 0) {
1706 bcopy((caddr_t
)tl
, (caddr_t
)nmp
->nm_verf
,
1708 nmp
->nm_state
|= NFSSTA_HASWRITEVERF
;
1709 } else if (bcmp((caddr_t
)tl
,
1710 (caddr_t
)nmp
->nm_verf
, NFSX_V3WRITEVERF
)) {
1712 bcopy((caddr_t
)tl
, (caddr_t
)nmp
->nm_verf
,
1717 nfsm_loadattr(vp
, (struct vattr
*)0, &xid
);
1720 VTONFS(vp
)->n_mtime
= VTONFS(vp
)->n_vattr
.va_mtime
.tv_sec
;
1723 * we seem to have a case where we end up looping on shutdown
1724 * and taking down nfs servers. For V3, error cases, there is
1725 * no way to terminate loop, if the len was 0, meaning,
1726 * nmp->nm_wsize was trashed. FreeBSD has this fix in it.
1734 if (vp
->v_mount
&& (vp
->v_mount
->mnt_flag
& MNT_ASYNC
))
1735 committed
= NFSV3WRITE_FILESYNC
;
1736 *iomode
= committed
;
1738 uiop
->uio_resid
= tsiz
;
1739 FSDBG_BOT(537, vp
, committed
, uiop
->uio_resid
, error
);
1745 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1746 * mode set to specify the file type and the size field for rdev.
1749 nfs_mknodrpc(dvp
, vpp
, cnp
, vap
)
1750 register struct vnode
*dvp
;
1751 register struct vnode
**vpp
;
1752 register struct componentname
*cnp
;
1753 register struct vattr
*vap
;
1755 register struct nfsv2_sattr
*sp
;
1756 register struct nfsv3_sattr
*sp3
;
1757 register u_long
*tl
;
1758 register caddr_t cp
;
1759 register long t1
, t2
;
1760 struct vnode
*newvp
= (struct vnode
*)0;
1761 struct nfsnode
*np
= (struct nfsnode
*)0;
1765 int error
= 0, wccflag
= NFSV3_WCCRATTR
, gotvp
= 0;
1766 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1769 int v3
= NFS_ISV3(dvp
);
1771 if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
)
1772 rdev
= txdr_unsigned(vap
->va_rdev
);
1773 else if (vap
->va_type
== VFIFO
|| vap
->va_type
== VSOCK
)
1776 VOP_ABORTOP(dvp
, cnp
);
1778 return (EOPNOTSUPP
);
1780 if ((error
= VOP_GETATTR(dvp
, &vattr
, cnp
->cn_cred
, cnp
->cn_proc
))) {
1781 VOP_ABORTOP(dvp
, cnp
);
1785 nfsstats
.rpccnt
[NFSPROC_MKNOD
]++;
1786 nfsm_reqhead(dvp
, NFSPROC_MKNOD
, NFSX_FH(v3
) + 4 * NFSX_UNSIGNED
+
1787 + nfsm_rndup(cnp
->cn_namelen
) + NFSX_SATTR(v3
));
1788 nfsm_fhtom(dvp
, v3
);
1789 nfsm_strtom(cnp
->cn_nameptr
, cnp
->cn_namelen
, NFS_MAXNAMLEN
);
1791 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
+ NFSX_V3SRVSATTR
);
1792 *tl
++ = vtonfsv3_type(vap
->va_type
);
1793 sp3
= (struct nfsv3_sattr
*)tl
;
1794 nfsm_v3sattr(sp3
, vap
, cnp
->cn_cred
->cr_uid
, vattr
.va_gid
);
1795 if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
) {
1796 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1797 *tl
++ = txdr_unsigned(major(vap
->va_rdev
));
1798 *tl
= txdr_unsigned(minor(vap
->va_rdev
));
1801 nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1802 sp
->sa_mode
= vtonfsv2_mode(vap
->va_type
, vap
->va_mode
);
1803 sp
->sa_uid
= txdr_unsigned(cnp
->cn_cred
->cr_uid
);
1804 sp
->sa_gid
= txdr_unsigned(vattr
.va_gid
);
1806 txdr_nfsv2time(&vap
->va_atime
, &sp
->sa_atime
);
1807 txdr_nfsv2time(&vap
->va_mtime
, &sp
->sa_mtime
);
1809 nfsm_request(dvp
, NFSPROC_MKNOD
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
1811 nfsm_mtofh(dvp
, newvp
, v3
, gotvp
, &xid
);
1815 newvp
= (struct vnode
*)0;
1817 error
= nfs_lookitup(dvp
, cnp
->cn_nameptr
,
1818 cnp
->cn_namelen
, cnp
->cn_cred
, cnp
->cn_proc
, &np
);
1824 nfsm_wcc_data(dvp
, wccflag
, &xid
);
1830 if (cnp
->cn_flags
& MAKEENTRY
)
1831 cache_enter(dvp
, newvp
, cnp
);
1834 VTONFS(dvp
)->n_flag
|= NMODIFIED
;
1836 VTONFS(dvp
)->n_xid
= 0;
1838 NFS_FREE_PNBUF(cnp
);
1844 * just call nfs_mknodrpc() to do the work.
1849 struct vop_mknod_args
/* {
1850 struct vnode *a_dvp;
1851 struct vnode **a_vpp;
1852 struct componentname *a_cnp;
1853 struct vattr *a_vap;
1856 struct vnode
*newvp
;
1859 error
= nfs_mknodrpc(ap
->a_dvp
, &newvp
, ap
->a_cnp
, ap
->a_vap
);
1860 if (!error
&& newvp
)
1866 static u_long create_verf
;
1868 * nfs file create call
1872 struct vop_create_args
/* {
1873 struct vnode *a_dvp;
1874 struct vnode **a_vpp;
1875 struct componentname *a_cnp;
1876 struct vattr *a_vap;
1879 register struct vnode
*dvp
= ap
->a_dvp
;
1880 register struct vattr
*vap
= ap
->a_vap
;
1881 register struct componentname
*cnp
= ap
->a_cnp
;
1882 register struct nfsv2_sattr
*sp
;
1883 register struct nfsv3_sattr
*sp3
;
1884 register u_long
*tl
;
1885 register caddr_t cp
;
1886 register long t1
, t2
;
1887 struct nfsnode
*np
= (struct nfsnode
*)0;
1888 struct vnode
*newvp
= (struct vnode
*)0;
1889 caddr_t bpos
, dpos
, cp2
;
1890 int error
= 0, wccflag
= NFSV3_WCCRATTR
, gotvp
= 0, fmode
= 0;
1891 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
1893 int v3
= NFS_ISV3(dvp
);
1897 * Oops, not for me..
1899 if (vap
->va_type
== VSOCK
)
1900 return (nfs_mknodrpc(dvp
, ap
->a_vpp
, cnp
, vap
));
1902 if ((error
= VOP_GETATTR(dvp
, &vattr
, cnp
->cn_cred
, cnp
->cn_proc
))) {
1903 VOP_ABORTOP(dvp
, cnp
);
1907 if (vap
->va_vaflags
& VA_EXCLUSIVE
)
1910 nfsstats
.rpccnt
[NFSPROC_CREATE
]++;
1911 nfsm_reqhead(dvp
, NFSPROC_CREATE
, NFSX_FH(v3
) + 2 * NFSX_UNSIGNED
+
1912 nfsm_rndup(cnp
->cn_namelen
) + NFSX_SATTR(v3
));
1913 nfsm_fhtom(dvp
, v3
);
1914 nfsm_strtom(cnp
->cn_nameptr
, cnp
->cn_namelen
, NFS_MAXNAMLEN
);
1916 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
1917 if (fmode
& O_EXCL
) {
1918 *tl
= txdr_unsigned(NFSV3CREATE_EXCLUSIVE
);
1919 nfsm_build(tl
, u_long
*, NFSX_V3CREATEVERF
);
1920 if (!TAILQ_EMPTY(&in_ifaddrhead
))
1921 *tl
++ = IA_SIN(in_ifaddrhead
.tqh_first
)->sin_addr
.s_addr
;
1923 *tl
++ = create_verf
;
1924 *tl
= ++create_verf
;
1926 *tl
= txdr_unsigned(NFSV3CREATE_UNCHECKED
);
1927 nfsm_build(tl
, u_long
*, NFSX_V3SRVSATTR
);
1928 sp3
= (struct nfsv3_sattr
*)tl
;
1929 nfsm_v3sattr(sp3
, vap
, cnp
->cn_cred
->cr_uid
, vattr
.va_gid
);
1932 nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1933 sp
->sa_mode
= vtonfsv2_mode(vap
->va_type
, vap
->va_mode
);
1934 sp
->sa_uid
= txdr_unsigned(cnp
->cn_cred
->cr_uid
);
1935 sp
->sa_gid
= txdr_unsigned(vattr
.va_gid
);
1937 txdr_nfsv2time(&vap
->va_atime
, &sp
->sa_atime
);
1938 txdr_nfsv2time(&vap
->va_mtime
, &sp
->sa_mtime
);
1940 nfsm_request(dvp
, NFSPROC_CREATE
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
1942 nfsm_mtofh(dvp
, newvp
, v3
, gotvp
, &xid
);
1946 newvp
= (struct vnode
*)0;
1948 error
= nfs_lookitup(dvp
, cnp
->cn_nameptr
,
1949 cnp
->cn_namelen
, cnp
->cn_cred
, cnp
->cn_proc
, &np
);
1955 nfsm_wcc_data(dvp
, wccflag
, &xid
);
1958 if (v3
&& (fmode
& O_EXCL
) && error
== NFSERR_NOTSUPP
) {
1964 } else if (v3
&& (fmode
& O_EXCL
))
1965 error
= nfs_setattrrpc(newvp
, vap
, cnp
->cn_cred
, cnp
->cn_proc
);
1967 if (cnp
->cn_flags
& MAKEENTRY
)
1968 cache_enter(dvp
, newvp
, cnp
);
1971 VTONFS(dvp
)->n_flag
|= NMODIFIED
;
1973 VTONFS(dvp
)->n_xid
= 0;
1975 NFS_FREE_PNBUF(cnp
);
1980 * nfs file remove call
1981 * To try and make nfs semantics closer to ufs semantics, a file that has
1982 * other processes using the vnode is renamed instead of removed and then
1983 * removed later on the last close.
1984 * - If v_usecount > 1
1985 * If a rename is not already in the works
1986 * call nfs_sillyrename() to set it up
1992 struct vop_remove_args
/* {
1993 struct vnodeop_desc *a_desc;
1994 struct vnode * a_dvp;
1995 struct vnode * a_vp;
1996 struct componentname * a_cnp;
1999 register struct vnode
*vp
= ap
->a_vp
;
2000 register struct vnode
*dvp
= ap
->a_dvp
;
2001 register struct componentname
*cnp
= ap
->a_cnp
;
2002 register struct nfsnode
*np
= VTONFS(vp
);
2003 int error
= 0, gofree
= 0;
2007 if ((cnp
->cn_flags
& HASBUF
) == 0)
2008 panic("nfs_remove: no name");
2009 if (vp
->v_usecount
< 1)
2010 panic("nfs_remove: bad v_usecount");
2013 if (UBCISVALID(vp
)) {
2015 if (UBCINFOEXISTS(vp
))
2016 gofree
= (ubc_isinuse(vp
, 1)) ? 0 : 1;
2018 /* dead or dying vnode.With vnode locking panic instead of error */
2021 NFS_FREE_PNBUF(cnp
);
2025 /* UBC not in play */
2026 if (vp
->v_usecount
== 1)
2029 if ((ap
->a_cnp
->cn_flags
& NODELETEBUSY
) && !gofree
) {
2030 /* Caller requested Carbon delete semantics, but file is busy */
2033 NFS_FREE_PNBUF(cnp
);
2036 if (gofree
|| (np
->n_sillyrename
&&
2037 VOP_GETATTR(vp
, &vattr
, cnp
->cn_cred
, cnp
->cn_proc
) == 0 &&
2038 vattr
.va_nlink
> 1)) {
2040 * Purge the name cache so that the chance of a lookup for
2041 * the name succeeding while the remove is in progress is
2042 * minimized. Without node locking it can still happen, such
2043 * that an I/O op returns ESTALE, but since you get this if
2044 * another host removes the file..
2048 * throw away biocache buffers, mainly to avoid
2049 * unnecessary delayed writes later.
2051 error
= nfs_vinvalbuf(vp
, 0, cnp
->cn_cred
, cnp
->cn_proc
, 1);
2053 ubc_setsize(vp
, (off_t
)0); /* XXX check error */
2056 error
= nfs_removerpc(dvp
, cnp
->cn_nameptr
,
2057 cnp
->cn_namelen
, cnp
->cn_cred
, cnp
->cn_proc
);
2059 * Kludge City: If the first reply to the remove rpc is lost..
2060 * the reply to the retransmitted request will be ENOENT
2061 * since the file was in fact removed
2062 * Therefore, we cheat and return success.
2064 if (error
== ENOENT
)
2068 * remove nfsnode from hash now so we can't accidentally find it
2069 * again if another object gets created with the same filehandle
2070 * before this vnode gets reclaimed
2072 LIST_REMOVE(np
, n_hash
);
2073 np
->n_flag
&= ~NHASHED
;
2075 } else if (!np
->n_sillyrename
) {
2076 error
= nfs_sillyrename(dvp
, vp
, cnp
);
2081 VOP_UNLOCK(vp
, 0, cnp
->cn_proc
);
2082 NFS_FREE_PNBUF(cnp
);
2090 * nfs file remove rpc called from nfs_inactive
2094 register struct sillyrename
*sp
;
2097 return (nfs_removerpc(sp
->s_dvp
, sp
->s_name
, sp
->s_namlen
, sp
->s_cred
,
2102 * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
2105 nfs_removerpc(dvp
, name
, namelen
, cred
, proc
)
2106 register struct vnode
*dvp
;
2112 register u_long
*tl
;
2113 register caddr_t cp
;
2114 register long t1
, t2
;
2115 caddr_t bpos
, dpos
, cp2
;
2116 int error
= 0, wccflag
= NFSV3_WCCRATTR
;
2117 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2121 if (!VFSTONFS(dvp
->v_mount
))
2125 nfsstats
.rpccnt
[NFSPROC_REMOVE
]++;
2126 nfsm_reqhead(dvp
, NFSPROC_REMOVE
,
2127 NFSX_FH(v3
) + NFSX_UNSIGNED
+ nfsm_rndup(namelen
));
2128 nfsm_fhtom(dvp
, v3
);
2129 nfsm_strtom(name
, namelen
, NFS_MAXNAMLEN
);
2130 nfsm_request(dvp
, NFSPROC_REMOVE
, proc
, cred
, &xid
);
2132 nfsm_wcc_data(dvp
, wccflag
, &xid
);
2134 VTONFS(dvp
)->n_flag
|= NMODIFIED
;
2136 VTONFS(dvp
)->n_xid
= 0;
2141 * nfs file rename call
2145 struct vop_rename_args
/* {
2146 struct vnode *a_fdvp;
2147 struct vnode *a_fvp;
2148 struct componentname *a_fcnp;
2149 struct vnode *a_tdvp;
2150 struct vnode *a_tvp;
2151 struct componentname *a_tcnp;
2154 register struct vnode
*fvp
= ap
->a_fvp
;
2155 register struct vnode
*tvp
= ap
->a_tvp
;
2156 register struct vnode
*fdvp
= ap
->a_fdvp
;
2157 register struct vnode
*tdvp
= ap
->a_tdvp
;
2158 register struct componentname
*tcnp
= ap
->a_tcnp
;
2159 register struct componentname
*fcnp
= ap
->a_fcnp
;
2160 int error
, purged
=0, inuse
=0;
2163 if ((tcnp
->cn_flags
& HASBUF
) == 0 ||
2164 (fcnp
->cn_flags
& HASBUF
) == 0)
2165 panic("nfs_rename: no name");
2167 /* Check for cross-device rename */
2168 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
2169 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
2172 VOP_UNLOCK(tvp
, 0, tcnp
->cn_proc
);
2177 * If the tvp exists and is in use, sillyrename it before doing the
2178 * rename of the new file over it.
2179 * XXX Can't sillyrename a directory.
2180 * Don't sillyrename if source and target are same vnode (hard
2181 * links or case-variants)
2183 if (tvp
&& tvp
!= fvp
) {
2184 if (UBCISVALID(tvp
)) {
2186 if (UBCINFOEXISTS(tvp
))
2187 inuse
= (ubc_isinuse(tvp
, 1)) ? 1 : 0;
2189 /* dead or dying vnode.With vnode locking panic instead of error */
2191 VOP_UNLOCK(tvp
, 0, tcnp
->cn_proc
);
2195 /* UBC not in play */
2196 if (tvp
->v_usecount
> 1)
2200 if (inuse
&& !VTONFS(tvp
)->n_sillyrename
&& tvp
->v_type
!= VDIR
) {
2201 if (error
= nfs_sillyrename(tdvp
, tvp
, tcnp
)) {
2202 /* sillyrename failed. Instead of pressing on, return error */
2203 VOP_UNLOCK(tvp
, 0, tcnp
->cn_proc
);
2204 goto out
; /* should not be ENOENT. */
2206 /* sillyrename succeeded.*/
2207 VOP_UNLOCK(tvp
, 0, tcnp
->cn_proc
);
2208 ubc_uncache(tvp
); /* get the nfs turd file to disappear */
2214 error
= nfs_renamerpc(fdvp
, fcnp
->cn_nameptr
, fcnp
->cn_namelen
,
2215 tdvp
, tcnp
->cn_nameptr
, tcnp
->cn_namelen
, tcnp
->cn_cred
,
2218 if (!error
&& tvp
&& tvp
!= fvp
&& !VTONFS(tvp
)->n_sillyrename
) {
2220 * remove nfsnode from hash now so we can't accidentally find it
2221 * again if another object gets created with the same filehandle
2222 * before this vnode gets reclaimed
2224 LIST_REMOVE(VTONFS(tvp
), n_hash
);
2225 VTONFS(tvp
)->n_flag
&= ~NHASHED
;
2228 if (fvp
->v_type
== VDIR
) {
2229 if (tvp
!= NULL
&& tvp
->v_type
== VDIR
) {
2241 VOP_UNLOCK(tvp
, 0, tcnp
->cn_proc
);
2242 ubc_uncache(tvp
); /* get the nfs turd file to disappear */
2251 vrele(tvp
); /* already unlocked */
2255 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
2257 if (error
== ENOENT
)
2263 * nfs file rename rpc called from nfs_remove() above
2266 nfs_renameit(sdvp
, scnp
, sp
)
2268 struct componentname
*scnp
;
2269 register struct sillyrename
*sp
;
2271 return (nfs_renamerpc(sdvp
, scnp
->cn_nameptr
, scnp
->cn_namelen
,
2272 sdvp
, sp
->s_name
, sp
->s_namlen
, scnp
->cn_cred
, scnp
->cn_proc
));
2276 * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
2279 nfs_renamerpc(fdvp
, fnameptr
, fnamelen
, tdvp
, tnameptr
, tnamelen
, cred
, proc
)
2280 register struct vnode
*fdvp
;
2283 register struct vnode
*tdvp
;
2289 register u_long
*tl
;
2290 register caddr_t cp
;
2291 register long t1
, t2
;
2292 caddr_t bpos
, dpos
, cp2
;
2293 int error
= 0, fwccflag
= NFSV3_WCCRATTR
, twccflag
= NFSV3_WCCRATTR
;
2294 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2298 if (!VFSTONFS(fdvp
->v_mount
))
2300 v3
= NFS_ISV3(fdvp
);
2302 nfsstats
.rpccnt
[NFSPROC_RENAME
]++;
2303 nfsm_reqhead(fdvp
, NFSPROC_RENAME
,
2304 (NFSX_FH(v3
) + NFSX_UNSIGNED
)*2 + nfsm_rndup(fnamelen
) +
2305 nfsm_rndup(tnamelen
));
2306 nfsm_fhtom(fdvp
, v3
);
2307 nfsm_strtom(fnameptr
, fnamelen
, NFS_MAXNAMLEN
);
2308 nfsm_fhtom(tdvp
, v3
);
2309 nfsm_strtom(tnameptr
, tnamelen
, NFS_MAXNAMLEN
);
2310 nfsm_request(fdvp
, NFSPROC_RENAME
, proc
, cred
, &xid
);
2312 u_int64_t txid
= xid
;
2314 nfsm_wcc_data(fdvp
, fwccflag
, &xid
);
2315 nfsm_wcc_data(tdvp
, twccflag
, &txid
);
2318 VTONFS(fdvp
)->n_flag
|= NMODIFIED
;
2320 VTONFS(fdvp
)->n_xid
= 0;
2321 VTONFS(tdvp
)->n_flag
|= NMODIFIED
;
2323 VTONFS(tdvp
)->n_xid
= 0;
2328 * nfs hard link create call
2332 struct vop_link_args
/* {
2334 struct vnode *a_tdvp;
2335 struct componentname *a_cnp;
2338 register struct vnode
*vp
= ap
->a_vp
;
2339 register struct vnode
*tdvp
= ap
->a_tdvp
;
2340 register struct componentname
*cnp
= ap
->a_cnp
;
2341 register u_long
*tl
;
2342 register caddr_t cp
;
2343 register long t1
, t2
;
2344 caddr_t bpos
, dpos
, cp2
;
2345 int error
= 0, wccflag
= NFSV3_WCCRATTR
, attrflag
= 0;
2346 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2350 if (vp
->v_mount
!= tdvp
->v_mount
) {
2351 VOP_ABORTOP(vp
, cnp
);
2356 /* need to get vnode lock for vp before calling VOP_FSYNC() */
2357 if (error
= vn_lock(vp
, LK_EXCLUSIVE
, cnp
->cn_proc
)) {
2358 VOP_ABORTOP(vp
, cnp
);
2363 if (!VFSTONFS(vp
->v_mount
)) {
2364 VOP_UNLOCK(vp
, 0, cnp
->cn_proc
);
2365 VOP_ABORTOP(vp
, cnp
);
2372 * Push all writes to the server, so that the attribute cache
2373 * doesn't get "out of sync" with the server.
2374 * XXX There should be a better way!
2376 didhold
= ubc_hold(vp
);
2377 VOP_FSYNC(vp
, cnp
->cn_cred
, MNT_WAIT
, cnp
->cn_proc
);
2378 VOP_UNLOCK(vp
, 0, cnp
->cn_proc
);
2380 nfsstats
.rpccnt
[NFSPROC_LINK
]++;
2381 nfsm_reqhead(vp
, NFSPROC_LINK
,
2382 NFSX_FH(v3
)*2 + NFSX_UNSIGNED
+ nfsm_rndup(cnp
->cn_namelen
));
2384 nfsm_fhtom(tdvp
, v3
);
2385 nfsm_strtom(cnp
->cn_nameptr
, cnp
->cn_namelen
, NFS_MAXNAMLEN
);
2386 nfsm_request(vp
, NFSPROC_LINK
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
2388 u_int64_t txid
= xid
;
2390 nfsm_postop_attr(vp
, attrflag
, &xid
);
2391 nfsm_wcc_data(tdvp
, wccflag
, &txid
);
2395 VTONFS(tdvp
)->n_flag
|= NMODIFIED
;
2397 VTONFS(vp
)->n_xid
= 0;
2399 VTONFS(tdvp
)->n_xid
= 0;
2403 NFS_FREE_PNBUF(cnp
);
2405 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2407 if (error
== EEXIST
)
2413 * nfs symbolic link create call
2417 struct vop_symlink_args
/* {
2418 struct vnode *a_dvp;
2419 struct vnode **a_vpp;
2420 struct componentname *a_cnp;
2421 struct vattr *a_vap;
2425 register struct vnode
*dvp
= ap
->a_dvp
;
2426 register struct vattr
*vap
= ap
->a_vap
;
2427 register struct componentname
*cnp
= ap
->a_cnp
;
2428 register struct nfsv2_sattr
*sp
;
2429 register struct nfsv3_sattr
*sp3
;
2430 register u_long
*tl
;
2431 register caddr_t cp
;
2432 register long t1
, t2
;
2433 caddr_t bpos
, dpos
, cp2
;
2434 int slen
, error
= 0, wccflag
= NFSV3_WCCRATTR
, gotvp
;
2435 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2436 struct vnode
*newvp
= (struct vnode
*)0;
2437 int v3
= NFS_ISV3(dvp
);
2440 nfsstats
.rpccnt
[NFSPROC_SYMLINK
]++;
2441 slen
= strlen(ap
->a_target
);
2442 nfsm_reqhead(dvp
, NFSPROC_SYMLINK
, NFSX_FH(v3
) + 2*NFSX_UNSIGNED
+
2443 nfsm_rndup(cnp
->cn_namelen
) + nfsm_rndup(slen
) + NFSX_SATTR(v3
));
2444 nfsm_fhtom(dvp
, v3
);
2445 nfsm_strtom(cnp
->cn_nameptr
, cnp
->cn_namelen
, NFS_MAXNAMLEN
);
2447 nfsm_build(sp3
, struct nfsv3_sattr
*, NFSX_V3SRVSATTR
);
2448 nfsm_v3sattr(sp3
, vap
, cnp
->cn_cred
->cr_uid
,
2449 cnp
->cn_cred
->cr_gid
);
2451 nfsm_strtom(ap
->a_target
, slen
, NFS_MAXPATHLEN
);
2453 nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2454 sp
->sa_mode
= vtonfsv2_mode(VLNK
, vap
->va_mode
);
2455 sp
->sa_uid
= txdr_unsigned(cnp
->cn_cred
->cr_uid
);
2456 sp
->sa_gid
= txdr_unsigned(cnp
->cn_cred
->cr_gid
);
2458 txdr_nfsv2time(&vap
->va_atime
, &sp
->sa_atime
);
2459 txdr_nfsv2time(&vap
->va_mtime
, &sp
->sa_mtime
);
2461 nfsm_request(dvp
, NFSPROC_SYMLINK
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
2463 u_int64_t dxid
= xid
;
2466 nfsm_mtofh(dvp
, newvp
, v3
, gotvp
, &xid
);
2467 nfsm_wcc_data(dvp
, wccflag
, &dxid
);
2473 VTONFS(dvp
)->n_flag
|= NMODIFIED
;
2475 VTONFS(dvp
)->n_xid
= 0;
2477 NFS_FREE_PNBUF(cnp
);
2479 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
2481 if (error
== EEXIST
)
2491 struct vop_mkdir_args
/* {
2492 struct vnode *a_dvp;
2493 struct vnode **a_vpp;
2494 struct componentname *a_cnp;
2495 struct vattr *a_vap;
2498 register struct vnode
*dvp
= ap
->a_dvp
;
2499 register struct vattr
*vap
= ap
->a_vap
;
2500 register struct componentname
*cnp
= ap
->a_cnp
;
2501 register struct nfsv2_sattr
*sp
;
2502 register struct nfsv3_sattr
*sp3
;
2503 register u_long
*tl
;
2504 register caddr_t cp
;
2505 register long t1
, t2
;
2507 struct nfsnode
*np
= (struct nfsnode
*)0;
2508 struct vnode
*newvp
= (struct vnode
*)0;
2509 caddr_t bpos
, dpos
, cp2
;
2510 int error
= 0, wccflag
= NFSV3_WCCRATTR
;
2512 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2514 int v3
= NFS_ISV3(dvp
);
2515 u_int64_t xid
, dxid
;
2517 if ((error
= VOP_GETATTR(dvp
, &vattr
, cnp
->cn_cred
, cnp
->cn_proc
))) {
2518 VOP_ABORTOP(dvp
, cnp
);
2522 len
= cnp
->cn_namelen
;
2523 nfsstats
.rpccnt
[NFSPROC_MKDIR
]++;
2524 nfsm_reqhead(dvp
, NFSPROC_MKDIR
,
2525 NFSX_FH(v3
) + NFSX_UNSIGNED
+ nfsm_rndup(len
) + NFSX_SATTR(v3
));
2526 nfsm_fhtom(dvp
, v3
);
2527 nfsm_strtom(cnp
->cn_nameptr
, len
, NFS_MAXNAMLEN
);
2529 nfsm_build(sp3
, struct nfsv3_sattr
*, NFSX_V3SRVSATTR
);
2530 nfsm_v3sattr(sp3
, vap
, cnp
->cn_cred
->cr_uid
, vattr
.va_gid
);
2532 nfsm_build(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2533 sp
->sa_mode
= vtonfsv2_mode(VDIR
, vap
->va_mode
);
2534 sp
->sa_uid
= txdr_unsigned(cnp
->cn_cred
->cr_uid
);
2535 sp
->sa_gid
= txdr_unsigned(vattr
.va_gid
);
2537 txdr_nfsv2time(&vap
->va_atime
, &sp
->sa_atime
);
2538 txdr_nfsv2time(&vap
->va_mtime
, &sp
->sa_mtime
);
2540 nfsm_request(dvp
, NFSPROC_MKDIR
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
2543 nfsm_mtofh(dvp
, newvp
, v3
, gotvp
, &xid
);
2545 nfsm_wcc_data(dvp
, wccflag
, &dxid
);
2547 VTONFS(dvp
)->n_flag
|= NMODIFIED
;
2549 VTONFS(dvp
)->n_xid
= 0;
2551 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
2552 * if we can succeed in looking up the directory.
2554 if (error
== EEXIST
|| (!error
&& !gotvp
)) {
2557 newvp
= (struct vnode
*)0;
2559 error
= nfs_lookitup(dvp
, cnp
->cn_nameptr
, len
, cnp
->cn_cred
,
2563 if (newvp
->v_type
!= VDIR
)
2573 NFS_FREE_PNBUF(cnp
);
2578 * nfs remove directory call
2582 struct vop_rmdir_args
/* {
2583 struct vnode *a_dvp;
2585 struct componentname *a_cnp;
2588 register struct vnode
*vp
= ap
->a_vp
;
2589 register struct vnode
*dvp
= ap
->a_dvp
;
2590 register struct componentname
*cnp
= ap
->a_cnp
;
2591 register u_long
*tl
;
2592 register caddr_t cp
;
2593 register long t1
, t2
;
2594 caddr_t bpos
, dpos
, cp2
;
2595 int error
= 0, wccflag
= NFSV3_WCCRATTR
;
2596 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2597 int v3
= NFS_ISV3(dvp
);
2600 nfsstats
.rpccnt
[NFSPROC_RMDIR
]++;
2601 nfsm_reqhead(dvp
, NFSPROC_RMDIR
,
2602 NFSX_FH(v3
) + NFSX_UNSIGNED
+ nfsm_rndup(cnp
->cn_namelen
));
2603 nfsm_fhtom(dvp
, v3
);
2604 nfsm_strtom(cnp
->cn_nameptr
, cnp
->cn_namelen
, NFS_MAXNAMLEN
);
2605 nfsm_request(dvp
, NFSPROC_RMDIR
, cnp
->cn_proc
, cnp
->cn_cred
, &xid
);
2607 nfsm_wcc_data(dvp
, wccflag
, &xid
);
2609 VTONFS(dvp
)->n_flag
|= NMODIFIED
;
2611 VTONFS(dvp
)->n_xid
= 0;
2616 NFS_FREE_PNBUF(cnp
);
2618 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
2620 if (error
== ENOENT
)
2630 struct vop_readdir_args
/* {
2633 struct ucred *a_cred;
2636 register struct vnode
*vp
= ap
->a_vp
;
2637 register struct nfsnode
*np
= VTONFS(vp
);
2638 register struct uio
*uio
= ap
->a_uio
;
2642 if (vp
->v_type
!= VDIR
)
2645 * First, check for hit on the EOF offset cache
2647 if (np
->n_direofoffset
> 0 && uio
->uio_offset
>= np
->n_direofoffset
&&
2648 (np
->n_flag
& NMODIFIED
) == 0) {
2649 if (VFSTONFS(vp
->v_mount
)->nm_flag
& NFSMNT_NQNFS
) {
2650 if (NQNFS_CKCACHABLE(vp
, ND_READ
)) {
2651 nfsstats
.direofcache_hits
++;
2654 } else if (!VOP_GETATTR(vp
, &vattr
, ap
->a_cred
, uio
->uio_procp
)) {
2655 if (np
->n_mtime
== vattr
.va_mtime
.tv_sec
) {
2656 nfsstats
.direofcache_hits
++;
2659 /* directory changed, purge any name cache entries */
2665 * Call nfs_bioread() to do the real work.
2667 tresid
= uio
->uio_resid
;
2668 error
= nfs_bioread(vp
, uio
, 0, ap
->a_cred
, 0);
2670 if (!error
&& uio
->uio_resid
== tresid
)
2671 nfsstats
.direofcache_misses
++;
2677 * Called from below the buffer cache by nfs_doio().
2680 nfs_readdirrpc(vp
, uiop
, cred
)
2682 register struct uio
*uiop
;
2686 register int len
, left
;
2687 register struct dirent
*dp
;
2688 register u_long
*tl
;
2689 register caddr_t cp
;
2690 register long t1
, t2
;
2691 register nfsuint64
*cookiep
;
2692 caddr_t bpos
, dpos
, cp2
;
2693 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
2695 struct nfsmount
*nmp
;
2696 struct nfsnode
*dnp
= VTONFS(vp
);
2698 int error
= 0, tlen
, more_dirs
= 1, blksiz
= 0, bigenough
= 1;
2700 int v3
, nmreaddirsize
;
2704 dp
= (struct dirent
*)0;
2707 if (uiop
->uio_iovcnt
!= 1 || (uiop
->uio_offset
& (NFS_DIRBLKSIZ
- 1)) ||
2708 (uiop
->uio_resid
& (NFS_DIRBLKSIZ
- 1)))
2709 panic("nfs_readdirrpc: bad uio");
2711 nmp
= VFSTONFS(vp
->v_mount
);
2715 nmreaddirsize
= nmp
->nm_readdirsize
;
2718 * If there is no cookie, assume directory was stale.
2720 cookiep
= nfs_getcookie(dnp
, uiop
->uio_offset
, 0);
2724 return (NFSERR_BAD_COOKIE
);
2726 * Loop around doing readdir rpc's of size nm_readdirsize
2727 * truncated to a multiple of DIRBLKSIZ.
2728 * The stopping criteria is EOF or buffer full.
2730 while (more_dirs
&& bigenough
) {
2731 nfsstats
.rpccnt
[NFSPROC_READDIR
]++;
2732 nfsm_reqhead(vp
, NFSPROC_READDIR
, NFSX_FH(v3
) +
2736 nfsm_build(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
2737 *tl
++ = cookie
.nfsuquad
[0];
2738 *tl
++ = cookie
.nfsuquad
[1];
2739 *tl
++ = dnp
->n_cookieverf
.nfsuquad
[0];
2740 *tl
++ = dnp
->n_cookieverf
.nfsuquad
[1];
2742 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2743 *tl
++ = cookie
.nfsuquad
[0];
2745 *tl
= txdr_unsigned(nmreaddirsize
);
2746 nfsm_request(vp
, NFSPROC_READDIR
, uiop
->uio_procp
, cred
, &xid
);
2748 nfsm_postop_attr(vp
, attrflag
, &xid
);
2750 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2751 dnp
->n_cookieverf
.nfsuquad
[0] = *tl
++;
2752 dnp
->n_cookieverf
.nfsuquad
[1] = *tl
;
2758 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
2759 more_dirs
= fxdr_unsigned(int, *tl
);
2761 /* loop thru the dir entries, doctoring them to 4bsd form */
2762 while (more_dirs
&& bigenough
) {
2764 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
2765 fxdr_hyper(tl
, &fileno
);
2766 len
= fxdr_unsigned(int, *(tl
+ 2));
2768 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2769 fileno
= fxdr_unsigned(u_quad_t
, *tl
++);
2770 len
= fxdr_unsigned(int, *tl
);
2772 if (len
<= 0 || len
> NFS_MAXNAMLEN
) {
2777 tlen
= nfsm_rndup(len
);
2779 tlen
+= 4; /* To ensure null termination */
2780 left
= DIRBLKSIZ
- blksiz
;
2781 if ((tlen
+ DIRHDSIZ
) > left
) {
2782 dp
->d_reclen
+= left
;
2783 uiop
->uio_iov
->iov_base
+= left
;
2784 uiop
->uio_iov
->iov_len
-= left
;
2785 uiop
->uio_offset
+= left
;
2786 uiop
->uio_resid
-= left
;
2789 if ((tlen
+ DIRHDSIZ
) > uiop
->uio_resid
)
2792 dp
= (struct dirent
*)uiop
->uio_iov
->iov_base
;
2793 dp
->d_fileno
= (int)fileno
;
2795 dp
->d_reclen
= tlen
+ DIRHDSIZ
;
2796 dp
->d_type
= DT_UNKNOWN
;
2797 blksiz
+= dp
->d_reclen
;
2798 if (blksiz
== DIRBLKSIZ
)
2800 uiop
->uio_offset
+= DIRHDSIZ
;
2801 uiop
->uio_resid
-= DIRHDSIZ
;
2802 uiop
->uio_iov
->iov_base
+= DIRHDSIZ
;
2803 uiop
->uio_iov
->iov_len
-= DIRHDSIZ
;
2804 nfsm_mtouio(uiop
, len
);
2805 cp
= uiop
->uio_iov
->iov_base
;
2807 *cp
= '\0'; /* null terminate */
2808 uiop
->uio_iov
->iov_base
+= tlen
;
2809 uiop
->uio_iov
->iov_len
-= tlen
;
2810 uiop
->uio_offset
+= tlen
;
2811 uiop
->uio_resid
-= tlen
;
2813 nfsm_adv(nfsm_rndup(len
));
2815 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
2817 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2820 cookie
.nfsuquad
[0] = *tl
++;
2822 cookie
.nfsuquad
[1] = *tl
++;
2827 more_dirs
= fxdr_unsigned(int, *tl
);
2830 * If at end of rpc data, get the eof boolean
2833 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
2834 more_dirs
= (fxdr_unsigned(int, *tl
) == 0);
2839 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
2840 * by increasing d_reclen for the last record.
2843 left
= DIRBLKSIZ
- blksiz
;
2844 dp
->d_reclen
+= left
;
2845 uiop
->uio_iov
->iov_base
+= left
;
2846 uiop
->uio_iov
->iov_len
-= left
;
2847 uiop
->uio_offset
+= left
;
2848 uiop
->uio_resid
-= left
;
2852 * We are now either at the end of the directory or have filled the
2856 dnp
->n_direofoffset
= uiop
->uio_offset
;
2858 if (uiop
->uio_resid
> 0)
2859 printf("EEK! readdirrpc resid > 0\n");
2860 cookiep
= nfs_getcookie(dnp
, uiop
->uio_offset
, 1);
2868 * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
2871 nfs_readdirplusrpc(vp
, uiop
, cred
)
2873 register struct uio
*uiop
;
2876 register int len
, left
;
2877 register struct dirent
*dp
;
2878 register u_long
*tl
;
2879 register caddr_t cp
;
2880 register long t1
, t2
;
2881 register struct vnode
*newvp
;
2882 register nfsuint64
*cookiep
;
2883 caddr_t bpos
, dpos
, cp2
, dpossav1
, dpossav2
;
2884 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
, *mdsav1
, *mdsav2
;
2885 struct nameidata nami
, *ndp
= &nami
;
2886 struct componentname
*cnp
= &ndp
->ni_cnd
;
2888 struct nfsmount
*nmp
;
2889 struct nfsnode
*dnp
= VTONFS(vp
), *np
;
2892 int error
= 0, tlen
, more_dirs
= 1, blksiz
= 0, doit
, bigenough
= 1, i
;
2893 int attrflag
, fhsize
, nmreaddirsize
, nmrsize
;
2894 u_int64_t xid
, savexid
;
2897 dp
= (struct dirent
*)0;
2900 if (uiop
->uio_iovcnt
!= 1 || (uiop
->uio_offset
& (DIRBLKSIZ
- 1)) ||
2901 (uiop
->uio_resid
& (DIRBLKSIZ
- 1)))
2902 panic("nfs_readdirplusrpc: bad uio");
2904 nmp
= VFSTONFS(vp
->v_mount
);
2907 nmreaddirsize
= nmp
->nm_readdirsize
;
2908 nmrsize
= nmp
->nm_rsize
;
2914 * If there is no cookie, assume directory was stale.
2916 cookiep
= nfs_getcookie(dnp
, uiop
->uio_offset
, 0);
2920 return (NFSERR_BAD_COOKIE
);
2922 * Loop around doing readdir rpc's of size nm_readdirsize
2923 * truncated to a multiple of DIRBLKSIZ.
2924 * The stopping criteria is EOF or buffer full.
2926 while (more_dirs
&& bigenough
) {
2927 nfsstats
.rpccnt
[NFSPROC_READDIRPLUS
]++;
2928 nfsm_reqhead(vp
, NFSPROC_READDIRPLUS
,
2929 NFSX_FH(1) + 6 * NFSX_UNSIGNED
);
2931 nfsm_build(tl
, u_long
*, 6 * NFSX_UNSIGNED
);
2932 *tl
++ = cookie
.nfsuquad
[0];
2933 *tl
++ = cookie
.nfsuquad
[1];
2934 *tl
++ = dnp
->n_cookieverf
.nfsuquad
[0];
2935 *tl
++ = dnp
->n_cookieverf
.nfsuquad
[1];
2936 *tl
++ = txdr_unsigned(nmreaddirsize
);
2937 *tl
= txdr_unsigned(nmrsize
);
2938 nfsm_request(vp
, NFSPROC_READDIRPLUS
, uiop
->uio_procp
, cred
,
2941 nfsm_postop_attr(vp
, attrflag
, &xid
);
2946 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
2947 dnp
->n_cookieverf
.nfsuquad
[0] = *tl
++;
2948 dnp
->n_cookieverf
.nfsuquad
[1] = *tl
++;
2949 more_dirs
= fxdr_unsigned(int, *tl
);
2951 /* loop thru the dir entries, doctoring them to 4bsd form */
2952 while (more_dirs
&& bigenough
) {
2953 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
2954 fxdr_hyper(tl
, &fileno
);
2955 len
= fxdr_unsigned(int, *(tl
+ 2));
2956 if (len
<= 0 || len
> NFS_MAXNAMLEN
) {
2961 tlen
= nfsm_rndup(len
);
2963 tlen
+= 4; /* To ensure null termination*/
2964 left
= DIRBLKSIZ
- blksiz
;
2965 if ((tlen
+ DIRHDSIZ
) > left
) {
2966 dp
->d_reclen
+= left
;
2967 uiop
->uio_iov
->iov_base
+= left
;
2968 uiop
->uio_iov
->iov_len
-= left
;
2969 uiop
->uio_offset
+= left
;
2970 uiop
->uio_resid
-= left
;
2973 if ((tlen
+ DIRHDSIZ
) > uiop
->uio_resid
)
2976 dp
= (struct dirent
*)uiop
->uio_iov
->iov_base
;
2977 dp
->d_fileno
= (int)fileno
;
2979 dp
->d_reclen
= tlen
+ DIRHDSIZ
;
2980 dp
->d_type
= DT_UNKNOWN
;
2981 blksiz
+= dp
->d_reclen
;
2982 if (blksiz
== DIRBLKSIZ
)
2984 uiop
->uio_offset
+= DIRHDSIZ
;
2985 uiop
->uio_resid
-= DIRHDSIZ
;
2986 uiop
->uio_iov
->iov_base
+= DIRHDSIZ
;
2987 uiop
->uio_iov
->iov_len
-= DIRHDSIZ
;
2988 cnp
->cn_nameptr
= uiop
->uio_iov
->iov_base
;
2989 cnp
->cn_namelen
= len
;
2990 nfsm_mtouio(uiop
, len
);
2991 cp
= uiop
->uio_iov
->iov_base
;
2994 uiop
->uio_iov
->iov_base
+= tlen
;
2995 uiop
->uio_iov
->iov_len
-= tlen
;
2996 uiop
->uio_offset
+= tlen
;
2997 uiop
->uio_resid
-= tlen
;
2999 nfsm_adv(nfsm_rndup(len
));
3000 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
3002 cookie
.nfsuquad
[0] = *tl
++;
3003 cookie
.nfsuquad
[1] = *tl
++;
3008 * Since the attributes are before the file handle
3009 * (sigh), we must skip over the attributes and then
3010 * come back and get them.
3012 attrflag
= fxdr_unsigned(int, *tl
);
3016 nfsm_adv(NFSX_V3FATTR
);
3017 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
3018 doit
= fxdr_unsigned(int, *tl
);
3020 nfsm_getfh(fhp
, fhsize
, 1);
3021 if (NFS_CMPFH(dnp
, fhp
, fhsize
)) {
3025 } else if (!bigenough
||
3026 (cnp
->cn_namelen
== 2 &&
3027 cnp
->cn_nameptr
[1] == '.' &&
3028 cnp
->cn_nameptr
[0] == '.')) {
3030 * don't doit if we can't guarantee
3031 * that this entry is NOT ".." because
3032 * we would have to drop the lock on
3033 * the directory before getting the
3034 * (lock on) the ".." vnode... and we
3035 * don't want to drop the dvp lock in
3036 * the middle of a readdirplus.
3040 if ((error
= nfs_nget(vp
->v_mount
, fhp
,
3047 if (doit
&& bigenough
) {
3053 nfsm_loadattr(newvp
, (struct vattr
*)0, &xid
);
3057 IFTODT(VTTOIF(np
->n_vattr
.va_type
));
3060 for (cp
= cnp
->cn_nameptr
, i
= 1; i
<= len
;
3062 cnp
->cn_hash
+= (unsigned char)*cp
* i
;
3063 if (cnp
->cn_namelen
<= NCHNAMLEN
)
3064 cache_enter(ndp
->ni_dvp
, ndp
->ni_vp
, cnp
);
3067 /* Just skip over the file handle */
3068 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
3069 i
= fxdr_unsigned(int, *tl
);
3070 nfsm_adv(nfsm_rndup(i
));
3072 if (newvp
!= NULLVP
) {
3079 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
3080 more_dirs
= fxdr_unsigned(int, *tl
);
3083 * If at end of rpc data, get the eof boolean
3086 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
3087 more_dirs
= (fxdr_unsigned(int, *tl
) == 0);
3092 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
3093 * by increasing d_reclen for the last record.
3096 left
= DIRBLKSIZ
- blksiz
;
3097 dp
->d_reclen
+= left
;
3098 uiop
->uio_iov
->iov_base
+= left
;
3099 uiop
->uio_iov
->iov_len
-= left
;
3100 uiop
->uio_offset
+= left
;
3101 uiop
->uio_resid
-= left
;
3105 * We are now either at the end of the directory or have filled the
3109 dnp
->n_direofoffset
= uiop
->uio_offset
;
3111 if (uiop
->uio_resid
> 0)
3112 printf("EEK! readdirplusrpc resid > 0\n");
3113 cookiep
= nfs_getcookie(dnp
, uiop
->uio_offset
, 1);
3117 if (newvp
!= NULLVP
) {
3128 * Silly rename. To make the NFS filesystem that is stateless look a little
3129 * more like the "ufs" a remove of an active vnode is translated to a rename
3130 * to a funny looking filename that is removed by nfs_inactive on the
3131 * nfsnode. There is the potential for another process on a different client
3132 * to create the same funny name between the nfs_lookitup() fails and the
3133 * nfs_rename() completes, but...
3136 /* format of "random" names and next name to try */
3137 /* (note: shouldn't exceed size of sillyrename.s_name) */
3138 static char sillyrename_name
[] = ".nfsAAA%04x4.4";
3141 nfs_sillyrename(dvp
, vp
, cnp
)
3142 struct vnode
*dvp
, *vp
;
3143 struct componentname
*cnp
;
3145 register struct sillyrename
*sp
;
3155 if (vp
->v_type
== VDIR
)
3156 panic("nfs_sillyrename: dir");
3158 MALLOC_ZONE(sp
, struct sillyrename
*,
3159 sizeof (struct sillyrename
), M_NFSREQ
, M_WAITOK
);
3160 sp
->s_cred
= crdup(cnp
->cn_cred
);
3164 /* Fudge together a funny name */
3165 pid
= cnp
->cn_proc
->p_pid
;
3166 sp
->s_namlen
= sprintf(sp
->s_name
, sillyrename_name
, pid
);
3168 /* Try lookitups until we get one that isn't there */
3170 while (nfs_lookitup(dvp
, sp
->s_name
, sp
->s_namlen
, sp
->s_cred
,
3171 cnp
->cn_proc
, (struct nfsnode
**)0) == 0) {
3172 if (sp
->s_name
[4]++ >= 'z')
3173 sp
->s_name
[4] = 'A';
3174 if (++i
> ('z' - 'A' + 1)) {
3176 if (sp
->s_name
[5]++ >= 'z')
3177 sp
->s_name
[5] = 'A';
3178 if (++j
> ('z' - 'A' + 1)) {
3180 if (sp
->s_name
[6]++ >= 'z')
3181 sp
->s_name
[6] = 'A';
3182 if (++k
> ('z' - 'A' + 1)) {
3189 /* make note of next "random" name to try */
3190 if ((sillyrename_name
[4] = (sp
->s_name
[4] + 1)) > 'z') {
3191 sillyrename_name
[4] = 'A';
3192 if ((sillyrename_name
[5] = (sp
->s_name
[5] + 1)) > 'z') {
3193 sillyrename_name
[5] = 'A';
3194 if ((sillyrename_name
[6] = (sp
->s_name
[6] + 1)) > 'z')
3195 sillyrename_name
[6] = 'A';
3198 /* now, do the rename */
3199 if ((error
= nfs_renameit(dvp
, cnp
, sp
)))
3201 error
= nfs_lookitup(dvp
, sp
->s_name
, sp
->s_namlen
, sp
->s_cred
,
3204 kprintf("sillyrename: %s, vp=%x, np=%x, dvp=%x\n",
3205 &sp
->s_name
[0], (unsigned)vp
, (unsigned)np
, (unsigned)dvp
);
3207 np
->n_sillyrename
= sp
;
3212 sp
->s_cred
= NOCRED
;
3214 FREE_ZONE((caddr_t
)sp
, sizeof (struct sillyrename
), M_NFSREQ
);
3219 * Look up a file name and optionally either update the file handle or
3220 * allocate an nfsnode, depending on the value of npp.
3221 * npp == NULL --> just do the lookup
3222 * *npp == NULL --> allocate a new nfsnode and make sure attributes are
3224 * *npp != NULL --> update the file handle in the vnode
3227 nfs_lookitup(dvp
, name
, len
, cred
, procp
, npp
)
3228 register struct vnode
*dvp
;
3233 struct nfsnode
**npp
;
3235 register u_long
*tl
;
3236 register caddr_t cp
;
3237 register long t1
, t2
;
3238 struct vnode
*newvp
= (struct vnode
*)0;
3239 struct nfsnode
*np
, *dnp
= VTONFS(dvp
);
3240 caddr_t bpos
, dpos
, cp2
;
3241 int error
= 0, fhlen
, attrflag
;
3242 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
3247 if (!VFSTONFS(dvp
->v_mount
))
3251 nfsstats
.rpccnt
[NFSPROC_LOOKUP
]++;
3252 nfsm_reqhead(dvp
, NFSPROC_LOOKUP
,
3253 NFSX_FH(v3
) + NFSX_UNSIGNED
+ nfsm_rndup(len
));
3254 nfsm_fhtom(dvp
, v3
);
3255 nfsm_strtom(name
, len
, NFS_MAXNAMLEN
);
3256 nfsm_request(dvp
, NFSPROC_LOOKUP
, procp
, cred
, &xid
);
3257 if (npp
&& !error
) {
3258 nfsm_getfh(nfhp
, fhlen
, v3
);
3261 if (np
->n_fhsize
> NFS_SMALLFH
&& fhlen
<= NFS_SMALLFH
) {
3262 FREE_ZONE((caddr_t
)np
->n_fhp
,
3263 np
->n_fhsize
, M_NFSBIGFH
);
3264 np
->n_fhp
= &np
->n_fh
;
3265 } else if (np
->n_fhsize
<= NFS_SMALLFH
&& fhlen
>NFS_SMALLFH
)
3266 MALLOC_ZONE(np
->n_fhp
, nfsfh_t
*,
3267 fhlen
, M_NFSBIGFH
, M_WAITOK
);
3268 bcopy((caddr_t
)nfhp
, (caddr_t
)np
->n_fhp
, fhlen
);
3269 np
->n_fhsize
= fhlen
;
3271 } else if (NFS_CMPFH(dnp
, nfhp
, fhlen
)) {
3275 error
= nfs_nget(dvp
->v_mount
, nfhp
, fhlen
, &np
);
3283 nfsm_postop_attr(newvp
, attrflag
, &xid
);
3284 if (!attrflag
&& *npp
== NULL
) {
3293 nfsm_loadattr(newvp
, (struct vattr
*)0, &xid
);
3296 if (npp
&& *npp
== NULL
) {
3310 * Nfs Version 3 commit rpc
3313 nfs_commit(vp
, offset
, cnt
, cred
, procp
)
3314 register struct vnode
*vp
;
3320 register caddr_t cp
;
3321 register u_long
*tl
;
3322 register int t1
, t2
;
3323 register struct nfsmount
*nmp
= VFSTONFS(vp
->v_mount
);
3324 caddr_t bpos
, dpos
, cp2
;
3325 int error
= 0, wccflag
= NFSV3_WCCRATTR
;
3326 struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
3329 FSDBG(521, vp
, offset
, cnt
, nmp
->nm_state
);
3332 if ((nmp
->nm_state
& NFSSTA_HASWRITEVERF
) == 0)
3334 nfsstats
.rpccnt
[NFSPROC_COMMIT
]++;
3335 nfsm_reqhead(vp
, NFSPROC_COMMIT
, NFSX_FH(1));
3337 nfsm_build(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
3338 txdr_hyper(&offset
, tl
);
3340 *tl
= txdr_unsigned(cnt
);
3341 nfsm_request(vp
, NFSPROC_COMMIT
, procp
, cred
, &xid
);
3342 nfsm_wcc_data(vp
, wccflag
, &xid
);
3344 nfsm_dissect(tl
, u_long
*, NFSX_V3WRITEVERF
);
3345 if (bcmp((caddr_t
)nmp
->nm_verf
, (caddr_t
)tl
,
3346 NFSX_V3WRITEVERF
)) {
3347 bcopy((caddr_t
)tl
, (caddr_t
)nmp
->nm_verf
,
3349 error
= NFSERR_STALEWRITEVERF
;
3358 struct vop_bmap_args
/* {
3361 struct vnode **a_vpp;
3367 register struct vnode
*vp
= ap
->a_vp
;
3368 int devBlockSize
= DEV_BSIZE
;
3370 if (ap
->a_vpp
!= NULL
)
3372 if (ap
->a_bnp
!= NULL
) {
3375 *ap
->a_bnp
= ap
->a_bn
* btodb(vp
->v_mount
->mnt_stat
.f_iosize
,
3378 if (ap
->a_runp
!= NULL
)
3381 if (ap
->a_runb
!= NULL
)
3390 * NB Currently unsupported.
3395 struct vop_mmap_args
/* {
3398 struct ucred *a_cred;
3407 * fsync vnode op. Just call nfs_flush() with commit == 1.
3412 struct vop_fsync_args
/* {
3413 struct vnodeop_desc *a_desc;
3414 struct vnode * a_vp;
3415 struct ucred * a_cred;
3420 return (nfs_flush(ap
->a_vp
, ap
->a_cred
, ap
->a_waitfor
, ap
->a_p
, 1));
3424 nfs_flushcommits(struct vnode
*vp
, struct proc
*p
)
3426 struct nfsnode
*np
= VTONFS(vp
);
3427 struct nfsbuf
*bp
, *nbp
;
3428 int i
, s
, error
= 0, retv
, bvecpos
, wcred_set
;
3429 u_quad_t off
, endoff
, toff
;
3430 struct ucred
* wcred
;
3431 struct nfsbuf
**bvec
= NULL
;
3432 #define NFS_COMMITBVECSIZ 20
3433 #define NFS_MAXCOMMITBVECSIZ 1024
3434 struct nfsbuf
*bvec_on_stack
[NFS_COMMITBVECSIZ
];
3435 int bvecsize
= NFS_MAXCOMMITBVECSIZ
;
3437 FSDBG_TOP(557, vp
, np
, 0, 0);
3440 * A nb_flags == (NB_DELWRI | NB_NEEDCOMMIT) block has been written to the
3441 * server, but nas not been committed to stable storage on the server
3442 * yet. The byte range is worked out for as many nfsbufs as we can handle
3443 * and the commit rpc is done.
3445 if (np
->n_dirtyblkhd
.lh_first
)
3446 np
->n_flag
|= NMODIFIED
;
3453 if (!VFSTONFS(vp
->v_mount
)) {
3457 if (!NFS_ISV3(vp
)) {
3464 * Allocate space to remember the list of bufs to commit. It is
3465 * important to use M_NOWAIT here to avoid a race with nfs_write
3467 MALLOC(bvec
, struct nfsbuf
**,
3468 bvecsize
* sizeof(struct nfsbuf
*), M_TEMP
,
3471 bvec
= bvec_on_stack
;
3472 bvecsize
= NFS_COMMITBVECSIZ
;
3474 for (bp
= np
->n_dirtyblkhd
.lh_first
; bp
&& bvecpos
< bvecsize
; bp
= nbp
) {
3475 nbp
= bp
->nb_vnbufs
.le_next
;
3477 if (((bp
->nb_flags
& (NB_BUSY
| NB_DELWRI
| NB_NEEDCOMMIT
))
3478 != (NB_DELWRI
| NB_NEEDCOMMIT
)))
3481 nfs_buf_remfree(bp
);
3482 SET(bp
->nb_flags
, NB_BUSY
);
3484 * we need a upl to see if the page has been
3485 * dirtied (think mmap) since the unstable write, and
3486 * also to prevent vm from paging it during our commit rpc
3488 if (!ISSET(bp
->nb_flags
, NB_PAGELIST
)) {
3489 retv
= nfs_buf_upl_setup(bp
);
3491 /* unable to create upl */
3492 /* vm object must no longer exist */
3493 /* this could be fatal if we need */
3494 /* to write the data again, we'll see... */
3495 printf("nfs_flushcommits: upl create failed %d\n", retv
);
3496 bp
->nb_valid
= bp
->nb_dirty
= 0;
3499 nfs_buf_upl_check(bp
);
3501 FSDBG(557, bp
, bp
->nb_flags
, bp
->nb_valid
, bp
->nb_dirty
);
3502 FSDBG(557, bp
->nb_validoff
, bp
->nb_validend
,
3503 bp
->nb_dirtyoff
, bp
->nb_dirtyend
);
3506 * We used to check for dirty pages here; if there were any
3507 * we'd abort the commit and force the entire buffer to be
3510 * Instead of doing that, we now go ahead and commit the dirty
3511 * range, and then leave the buffer around with dirty pages
3512 * that will be written out later.
3515 /* in case blocking calls were made, re-evaluate nbp */
3516 nbp
= bp
->nb_vnbufs
.le_next
;
3519 * Work out if all buffers are using the same cred
3520 * so we can deal with them all with one commit.
3522 if (wcred_set
== 0) {
3523 wcred
= bp
->nb_wcred
;
3524 if (wcred
== NOCRED
)
3525 panic("nfs: needcommit w/out wcred");
3527 } else if ((wcred_set
== 1) && crcmp(wcred
, bp
->nb_wcred
)) {
3530 SET(bp
->nb_flags
, NB_WRITEINPROG
);
3533 * A list of these buffers is kept so that the
3534 * second loop knows which buffers have actually
3535 * been committed. This is necessary, since there
3536 * may be a race between the commit rpc and new
3537 * uncommitted writes on the file.
3539 bvec
[bvecpos
++] = bp
;
3540 toff
= NBOFF(bp
) + bp
->nb_dirtyoff
;
3543 toff
+= (u_quad_t
)(bp
->nb_dirtyend
- bp
->nb_dirtyoff
);
3555 * Commit data on the server, as required.
3556 * If all bufs are using the same wcred, then use that with
3557 * one call for all of them, otherwise commit each one
3561 retv
= nfs_commit(vp
, off
, (int)(endoff
- off
), wcred
, p
);
3565 for (i
= 0; i
< bvecpos
; i
++) {
3568 off
= NBOFF(bp
) + bp
->nb_dirtyoff
;
3569 size
= (u_quad_t
)(bp
->nb_dirtyend
- bp
->nb_dirtyoff
);
3570 retv
= nfs_commit(vp
, off
, (int)size
, bp
->nb_wcred
, p
);
3574 if (retv
== NFSERR_STALEWRITEVERF
)
3575 nfs_clearcommit(vp
->v_mount
);
3578 * Now, either mark the blocks I/O done or mark the
3579 * blocks dirty, depending on whether the commit
3582 for (i
= 0; i
< bvecpos
; i
++) {
3584 FSDBG(557, bp
, retv
, bp
->nb_flags
, bp
->nb_dirty
);
3586 CLR(bp
->nb_flags
, (NB_NEEDCOMMIT
| NB_WRITEINPROG
));
3588 np
->n_needcommitcnt
--;
3589 CHECK_NEEDCOMMITCNT(np
);
3592 nfs_buf_release(bp
);
3597 if (ISSET(bp
->nb_flags
, NB_DELWRI
)) {
3600 wakeup((caddr_t
)&nfs_nbdwrite
);
3602 CLR(bp
->nb_flags
, (NB_READ
|NB_DONE
|NB_ERROR
|NB_DELWRI
));
3603 /* if block still has dirty pages, we don't want it to */
3604 /* be released in nfs_buf_iodone(). So, don't set NB_ASYNC. */
3606 SET(bp
->nb_flags
, NB_ASYNC
);
3608 /* move to clean list */
3609 if (bp
->nb_vnbufs
.le_next
!= NFSNOLIST
)
3610 LIST_REMOVE(bp
, nb_vnbufs
);
3611 LIST_INSERT_HEAD(&VTONFS(vp
)->n_cleanblkhd
, bp
, nb_vnbufs
);
3613 bp
->nb_dirtyoff
= bp
->nb_dirtyend
= 0;
3618 /* throw it back in as a delayed write buffer */
3619 CLR(bp
->nb_flags
, NB_DONE
);
3620 nfs_buf_write_delayed(bp
);
3626 if (bvec
!= NULL
&& bvec
!= bvec_on_stack
)
3627 _FREE(bvec
, M_TEMP
);
3628 FSDBG_BOT(557, vp
, np
, 0, error
);
3633 * Flush all the blocks associated with a vnode.
3634 * Walk through the buffer pool and push any dirty pages
3635 * associated with the vnode.
3638 nfs_flush(vp
, cred
, waitfor
, p
, commit
)
3639 register struct vnode
*vp
;
3645 struct nfsnode
*np
= VTONFS(vp
);
3646 struct nfsbuf
*bp
, *nbp
;
3647 struct nfsmount
*nmp
= VFSTONFS(vp
->v_mount
);
3648 int i
, s
, error
= 0, error2
, slptimeo
= 0, slpflag
= 0;
3651 FSDBG_TOP(517, vp
, np
, waitfor
, commit
);
3657 if (nmp
->nm_flag
& NFSMNT_INT
)
3663 * On the first pass, commit all the bufs that can be.
3664 * On the second pass, nfs_buf_write() is called to do the job.
3667 FSDBG(518, np
->n_dirtyblkhd
.lh_first
, np
->n_flag
, 0, 0);
3668 if (np
->n_dirtyblkhd
.lh_first
)
3669 np
->n_flag
|= NMODIFIED
;
3670 if (!VFSTONFS(vp
->v_mount
)) {
3674 if (NFS_ISV3(vp
) && commit
) {
3675 /* loop while it looks like there are still buffers to be */
3676 /* commited and nfs_flushcommits() seems to be handling them. */
3677 while (np
->n_needcommitcnt
)
3678 if (nfs_flushcommits(vp
, p
))
3682 /* Start/do any write(s) that are required. */
3685 for (bp
= np
->n_dirtyblkhd
.lh_first
; bp
; bp
= nbp
) {
3686 nbp
= bp
->nb_vnbufs
.le_next
;
3687 if (ISSET(bp
->nb_flags
, NB_BUSY
)) {
3688 FSDBG(524, bp
, waitfor
, passone
, bp
->nb_flags
);
3689 if (waitfor
!= MNT_WAIT
|| passone
)
3691 SET(bp
->nb_flags
, NB_WANTED
);
3692 error
= tsleep((caddr_t
)bp
, slpflag
| (PRIBIO
+ 1),
3693 "nfsfsync", slptimeo
);
3696 error2
= nfs_sigintr(VFSTONFS(vp
->v_mount
),
3697 (struct nfsreq
*)0, p
);
3702 if (slpflag
== PCATCH
) {
3709 if (!ISSET(bp
->nb_flags
, NB_DELWRI
))
3710 panic("nfs_fsync: not dirty");
3711 FSDBG(525, bp
, passone
, commit
, bp
->nb_flags
);
3712 if ((passone
|| !commit
) && ISSET(bp
->nb_flags
, NB_NEEDCOMMIT
))
3714 nfs_buf_remfree(bp
);
3715 if (ISSET(bp
->nb_flags
, NB_ERROR
)) {
3716 np
->n_error
= bp
->nb_error
? bp
->nb_error
: EIO
;
3717 np
->n_flag
|= NWRITEERR
;
3718 nfs_buf_release(bp
);
3721 if (passone
|| !commit
)
3722 SET(bp
->nb_flags
, NB_BUSY
|NB_ASYNC
);
3724 /* the NB_STABLE forces this to be written FILESYNC */
3725 SET(bp
->nb_flags
, NB_BUSY
|NB_ASYNC
|NB_STABLE
);
3738 if (waitfor
== MNT_WAIT
) {
3739 while (vp
->v_numoutput
) {
3740 vp
->v_flag
|= VBWAIT
;
3741 error
= tsleep((caddr_t
)&vp
->v_numoutput
,
3742 slpflag
| (PRIBIO
+ 1), "nfsfsync", slptimeo
);
3744 error2
= nfs_sigintr(VFSTONFS(vp
->v_mount
),
3745 (struct nfsreq
*)0, p
);
3750 if (slpflag
== PCATCH
) {
3756 if (np
->n_dirtyblkhd
.lh_first
&& commit
) {
3760 FSDBG(526, np
->n_flag
, np
->n_error
, 0, 0);
3761 if (np
->n_flag
& NWRITEERR
) {
3762 error
= np
->n_error
;
3763 np
->n_flag
&= ~NWRITEERR
;
3766 FSDBG_BOT(517, vp
, np
, error
, 0);
3771 * Return POSIX pathconf information applicable to nfs.
3773 * The NFS V2 protocol doesn't support this, so just return EINVAL
3779 struct vop_pathconf_args
/* {
3790 * NFS advisory byte-level locks (client)
3794 struct vop_advlock_args
/* {
3802 return (nfs_dolock(ap
));
3806 * Print out the contents of an nfsnode.
3810 struct vop_print_args
/* {
3814 register struct vnode
*vp
= ap
->a_vp
;
3815 register struct nfsnode
*np
= VTONFS(vp
);
3817 printf("tag VT_NFS, fileid %ld fsid 0x%lx",
3818 np
->n_vattr
.va_fileid
, np
->n_vattr
.va_fsid
);
3819 if (vp
->v_type
== VFIFO
)
3826 * NFS directory offset lookup.
3827 * Currently unsupported.
3831 struct vop_blkatoff_args
/* {
3840 printf("nfs_blkatoff: unimplemented!!");
3842 return (EOPNOTSUPP
);
3846 * NFS flat namespace allocation.
3847 * Currently unsupported.
3851 struct vop_valloc_args
/* {
3852 struct vnode *a_pvp;
3854 struct ucred *a_cred;
3855 struct vnode **a_vpp;
3859 return (EOPNOTSUPP
);
3863 * NFS flat namespace free.
3864 * Currently unsupported.
3868 struct vop_vfree_args
/* {
3869 struct vnode *a_pvp;
3876 printf("nfs_vfree: unimplemented!!");
3878 return (EOPNOTSUPP
);
3882 * NFS file truncation.
3886 struct vop_truncate_args
/* {
3890 struct ucred *a_cred;
3895 /* Use nfs_setattr */
3897 printf("nfs_truncate: unimplemented!!");
3899 return (EOPNOTSUPP
);
3907 struct vop_update_args
/* {
3909 struct timeval *a_ta;
3910 struct timeval *a_tm;
3915 /* Use nfs_setattr */
3917 printf("nfs_update: unimplemented!!");
3919 return (EOPNOTSUPP
);
3923 * write (or commit) the given NFS buffer
3926 nfs_buf_write(struct nfsbuf
*bp
)
3929 int oldflags
= bp
->nb_flags
, rv
= 0;
3931 struct vnode
*vp
= bp
->nb_vp
;
3933 struct proc
*p
= current_proc();
3935 FSDBG_TOP(553, bp
, NBOFF(bp
), bp
->nb_flags
, 0);
3937 if (!ISSET(bp
->nb_flags
, NB_BUSY
))
3938 panic("nfs_buf_write: buffer is not busy???");
3941 CLR(bp
->nb_flags
, (NB_READ
|NB_DONE
|NB_ERROR
|NB_DELWRI
));
3942 if (ISSET(oldflags
, NB_DELWRI
)) {
3945 wakeup((caddr_t
)&nfs_nbdwrite
);
3948 /* move to clean list */
3949 if (ISSET(oldflags
, (NB_ASYNC
|NB_DELWRI
))) {
3950 if (bp
->nb_vnbufs
.le_next
!= NFSNOLIST
)
3951 LIST_REMOVE(bp
, nb_vnbufs
);
3952 LIST_INSERT_HEAD(&VTONFS(vp
)->n_cleanblkhd
, bp
, nb_vnbufs
);
3956 if (p
&& p
->p_stats
)
3957 p
->p_stats
->p_ru
.ru_oublock
++;
3961 * For async requests when nfsiod(s) are running, queue the request by
3962 * calling nfs_asyncio(), otherwise just all nfs_doio() to do the request.
3964 if (ISSET(bp
->nb_flags
, NB_ASYNC
))
3965 p
= (struct proc
*)0;
3966 if (ISSET(bp
->nb_flags
, NB_READ
))
3970 if (!ISSET(bp
->nb_flags
, NB_ASYNC
) || nfs_asyncio(bp
, NOCRED
))
3971 rv
= nfs_doio(bp
, cr
, p
);
3973 if ((oldflags
& NB_ASYNC
) == 0) {
3974 rv
= nfs_buf_iowait(bp
);
3975 /* move to clean list */
3976 if (oldflags
& NB_DELWRI
) {
3978 if (bp
->nb_vnbufs
.le_next
!= NFSNOLIST
)
3979 LIST_REMOVE(bp
, nb_vnbufs
);
3980 LIST_INSERT_HEAD(&VTONFS(vp
)->n_cleanblkhd
, bp
, nb_vnbufs
);
3983 FSDBG_BOT(553, bp
, NBOFF(bp
), bp
->nb_flags
, rv
);
3984 nfs_buf_release(bp
);
3988 FSDBG_BOT(553, bp
, NBOFF(bp
), bp
->nb_flags
, rv
);
3993 * nfs special file access vnode op.
3994 * Essentially just get vattr and then imitate iaccess() since the device is
3995 * local to the client.
3999 struct vop_access_args
/* {
4002 struct ucred *a_cred;
4006 register struct vattr
*vap
;
4008 register struct ucred
*cred
= ap
->a_cred
;
4009 struct vnode
*vp
= ap
->a_vp
;
4010 mode_t mode
= ap
->a_mode
;
4016 * Disallow write attempts on filesystems mounted read-only;
4017 * unless the file is a socket, fifo, or a block or character
4018 * device resident on the filesystem.
4020 if ((mode
& VWRITE
) && vp
->v_mount
&& (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
4021 switch (vp
->v_type
) {
4022 case VREG
: case VDIR
: case VLNK
:
4027 * If you're the super-user,
4028 * you always get access.
4030 if (cred
->cr_uid
== 0)
4033 error
= VOP_GETATTR(vp
, vap
, cred
, ap
->a_p
);
4037 * Access check is based on only one of owner, group, public.
4038 * If not owner, then check group. If not a member of the
4039 * group, then check public access.
4041 if (cred
->cr_uid
!= vap
->va_uid
) {
4043 gp
= cred
->cr_groups
;
4044 for (i
= 0; i
< cred
->cr_ngroups
; i
++, gp
++)
4045 if (vap
->va_gid
== *gp
)
4051 error
= (vap
->va_mode
& mode
) == mode
? 0 : EACCES
;
4056 * Read wrapper for special devices.
4060 struct vop_read_args
/* {
4064 struct ucred *a_cred;
4067 register struct nfsnode
*np
= VTONFS(ap
->a_vp
);
4075 np
->n_atim
.tv_sec
= now
.tv_sec
;
4076 np
->n_atim
.tv_nsec
= now
.tv_usec
* 1000;
4077 return (VOCALL(spec_vnodeop_p
, VOFFSET(vop_read
), ap
));
4081 * Write wrapper for special devices.
4085 struct vop_write_args
/* {
4089 struct ucred *a_cred;
4092 register struct nfsnode
*np
= VTONFS(ap
->a_vp
);
4100 np
->n_mtim
.tv_sec
= now
.tv_sec
;
4101 np
->n_mtim
.tv_nsec
= now
.tv_usec
* 1000;
4102 return (VOCALL(spec_vnodeop_p
, VOFFSET(vop_write
), ap
));
4106 * Close wrapper for special devices.
4108 * Update the times on the nfsnode then do device close.
4112 struct vop_close_args
/* {
4115 struct ucred *a_cred;
4119 register struct vnode
*vp
= ap
->a_vp
;
4120 register struct nfsnode
*np
= VTONFS(vp
);
4123 if (np
->n_flag
& (NACC
| NUPD
)) {
4125 if (vp
->v_usecount
== 1 && vp
->v_mount
&&
4126 (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) == 0) {
4128 if (np
->n_flag
& NACC
)
4129 vattr
.va_atime
= np
->n_atim
;
4130 if (np
->n_flag
& NUPD
)
4131 vattr
.va_mtime
= np
->n_mtim
;
4132 (void)VOP_SETATTR(vp
, &vattr
, ap
->a_cred
, ap
->a_p
);
4135 return (VOCALL(spec_vnodeop_p
, VOFFSET(vop_close
), ap
));
4139 * Read wrapper for fifos.
4143 struct vop_read_args
/* {
4147 struct ucred *a_cred;
4150 extern vop_t
**fifo_vnodeop_p
;
4151 register struct nfsnode
*np
= VTONFS(ap
->a_vp
);
4159 np
->n_atim
.tv_sec
= now
.tv_sec
;
4160 np
->n_atim
.tv_nsec
= now
.tv_usec
* 1000;
4161 return (VOCALL(fifo_vnodeop_p
, VOFFSET(vop_read
), ap
));
4165 * Write wrapper for fifos.
4169 struct vop_write_args
/* {
4173 struct ucred *a_cred;
4176 extern vop_t
**fifo_vnodeop_p
;
4177 register struct nfsnode
*np
= VTONFS(ap
->a_vp
);
4185 np
->n_mtim
.tv_sec
= now
.tv_sec
;
4186 np
->n_mtim
.tv_nsec
= now
.tv_usec
* 1000;
4187 return (VOCALL(fifo_vnodeop_p
, VOFFSET(vop_write
), ap
));
4191 * Close wrapper for fifos.
4193 * Update the times on the nfsnode then do fifo close.
4197 struct vop_close_args
/* {
4200 struct ucred *a_cred;
4204 register struct vnode
*vp
= ap
->a_vp
;
4205 register struct nfsnode
*np
= VTONFS(vp
);
4208 extern vop_t
**fifo_vnodeop_p
;
4210 if (np
->n_flag
& (NACC
| NUPD
)) {
4212 if (np
->n_flag
& NACC
) {
4213 np
->n_atim
.tv_sec
= now
.tv_sec
;
4214 np
->n_atim
.tv_nsec
= now
.tv_usec
* 1000;
4216 if (np
->n_flag
& NUPD
) {
4217 np
->n_mtim
.tv_sec
= now
.tv_sec
;
4218 np
->n_mtim
.tv_nsec
= now
.tv_usec
* 1000;
4221 if (vp
->v_usecount
== 1 && vp
->v_mount
&&
4222 (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) == 0) {
4224 if (np
->n_flag
& NACC
)
4225 vattr
.va_atime
= np
->n_atim
;
4226 if (np
->n_flag
& NUPD
)
4227 vattr
.va_mtime
= np
->n_mtim
;
4228 (void)VOP_SETATTR(vp
, &vattr
, ap
->a_cred
, ap
->a_p
);
4231 return (VOCALL(fifo_vnodeop_p
, VOFFSET(vop_close
), ap
));
4236 struct vop_ioctl_args
*ap
;
4240 * XXX we were once bogusly enoictl() which returned this (ENOTTY).
4241 * Probably we should return ENODEV.
4248 struct vop_select_args
*ap
;
4252 * We were once bogusly seltrue() which returns 1. Is this right?
4258 * Vnode op for pagein using getblk_pages
4259 * derived from nfs_bioread()
4260 * No read aheads are started from pagein operation
4264 struct vop_pagein_args
/* {
4267 vm_offset_t a_pl_offset,
4270 struct ucred *a_cred,
4274 register struct vnode
*vp
= ap
->a_vp
;
4275 upl_t pl
= ap
->a_pl
;
4276 size_t size
= ap
->a_size
;
4277 off_t f_offset
= ap
->a_f_offset
;
4278 vm_offset_t pl_offset
= ap
->a_pl_offset
;
4279 int flags
= ap
->a_flags
;
4281 struct nfsnode
*np
= VTONFS(vp
);
4282 int biosize
, xsize
, iosize
;
4284 struct proc
*p
= current_proc();
4285 struct nfsmount
*nmp
;
4290 struct uio
* uio
= &auio
;
4291 int nofreeupl
= flags
& UPL_NOCOMMIT
;
4292 upl_page_info_t
*plinfo
;
4294 FSDBG(322, vp
, f_offset
, size
, flags
);
4295 if (pl
== (upl_t
)NULL
)
4296 panic("nfs_pagein: no upl");
4298 if (UBCINVALID(vp
)) {
4299 printf("nfs_pagein: invalid vnode 0x%x", (int)vp
);
4301 (void) ubc_upl_abort(pl
, NULL
);
4304 UBCINFOCHECK("nfs_pagein", vp
);
4307 printf("nfs_pagein: invalid size %d", size
);
4309 (void) ubc_upl_abort(pl
, NULL
);
4312 if (f_offset
< 0 || f_offset
>= np
->n_size
|| (f_offset
& PAGE_MASK_64
)) {
4314 ubc_upl_abort_range(pl
, pl_offset
, size
,
4315 UPL_ABORT_ERROR
| UPL_ABORT_FREE_ON_EMPTY
);
4318 cred
= ubc_getcred(vp
);
4322 auio
.uio_offset
= f_offset
;
4323 auio
.uio_segflg
= UIO_SYSSPACE
;
4324 auio
.uio_rw
= UIO_READ
;
4325 auio
.uio_procp
= NULL
;
4327 nmp
= VFSTONFS(vp
->v_mount
);
4330 ubc_upl_abort_range(pl
, pl_offset
, size
,
4331 UPL_ABORT_ERROR
| UPL_ABORT_FREE_ON_EMPTY
);
4334 if ((nmp
->nm_flag
& NFSMNT_NFSV3
) && !(nmp
->nm_state
& NFSSTA_GOTFSINFO
))
4335 (void)nfs_fsinfo(nmp
, vp
, cred
, p
);
4336 biosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
4338 plinfo
= ubc_upl_pageinfo(pl
);
4339 ubc_upl_map(pl
, &ioaddr
);
4340 ioaddr
+= pl_offset
;
4345 * It would be nice to be able to issue all these requests
4346 * in parallel instead of waiting for each one to complete
4347 * before sending the next one.
4348 * XXX Should we align these requests to block boundaries?
4350 iosize
= min(biosize
, xsize
);
4351 uio
->uio_resid
= iosize
;
4352 aiov
.iov_len
= iosize
;
4353 aiov
.iov_base
= (caddr_t
)ioaddr
;
4354 auio
.uio_iov
= &aiov
;
4355 auio
.uio_iovcnt
= 1;
4357 FSDBG(322, uio
->uio_offset
, uio
->uio_resid
, ioaddr
, xsize
);
4358 // XXX #warning our nfs_pagein does not support NQNFS
4360 * With UBC we get here only when the file data is not in the VM
4361 * page cache, so go ahead and read in.
4364 upl_ubc_alias_set(pl
, current_act(), 2);
4365 #endif /* UBC_DEBUG */
4368 error
= nfs_readrpc(vp
, uio
, cred
);
4371 if (uio
->uio_resid
) {
4373 * If uio_resid > 0, there is a hole in the file
4374 * and no writes after the hole have been pushed
4375 * to the server yet... or we're at the EOF
4376 * Just zero fill the rest of the valid area.
4378 int zcnt
= uio
->uio_resid
;
4379 int zoff
= iosize
- zcnt
;
4380 bzero((char *)ioaddr
+ zoff
, zcnt
);
4382 FSDBG(324, uio
->uio_offset
, zoff
, zcnt
, ioaddr
);
4383 uio
->uio_offset
+= zcnt
;
4388 FSDBG(322, uio
->uio_offset
, uio
->uio_resid
, error
, -1);
4390 nmp
= VFSTONFS(vp
->v_mount
);
4391 if (p
&& (vp
->v_flag
& VTEXT
) && nmp
&&
4392 ((nmp
->nm_flag
& NFSMNT_NQNFS
&&
4393 NQNFS_CKINVALID(vp
, np
, ND_READ
) &&
4394 np
->n_lrev
!= np
->n_brev
) ||
4395 (!(nmp
->nm_flag
& NFSMNT_NQNFS
) &&
4396 np
->n_mtime
!= np
->n_vattr
.va_mtime
.tv_sec
))) {
4397 uprintf("Process killed due to text file modification\n");
4398 psignal(p
, SIGKILL
);
4399 p
->p_flag
|= P_NOSWAP
;
4402 } while (error
== 0 && xsize
> 0);
4408 ubc_upl_abort_range(pl
, pl_offset
, size
,
4410 UPL_ABORT_FREE_ON_EMPTY
);
4412 ubc_upl_commit_range(pl
, pl_offset
, size
,
4413 UPL_COMMIT_CLEAR_DIRTY
|
4414 UPL_COMMIT_FREE_ON_EMPTY
);
4421 * Vnode op for pageout using UPL
4422 * Derived from nfs_write()
4423 * File size changes are not permitted in pageout.
4427 struct vop_pageout_args
/* {
4430 vm_offset_t a_pl_offset,
4433 struct ucred *a_cred,
4437 register struct vnode
*vp
= ap
->a_vp
;
4438 upl_t pl
= ap
->a_pl
;
4439 size_t size
= ap
->a_size
;
4440 off_t f_offset
= ap
->a_f_offset
;
4441 vm_offset_t pl_offset
= ap
->a_pl_offset
;
4442 int flags
= ap
->a_flags
;
4443 int ioflag
= ap
->a_flags
;
4444 struct proc
*p
= current_proc();
4445 struct nfsnode
*np
= VTONFS(vp
);
4446 register struct ucred
*cred
;
4448 struct nfsmount
*nmp
= VFSTONFS(vp
->v_mount
);
4450 int n
= 0, on
, error
= 0, iomode
, must_commit
, s
;
4455 int nofreeupl
= flags
& UPL_NOCOMMIT
;
4456 int biosize
, iosize
, pgsize
, xsize
;
4458 FSDBG(323, f_offset
, size
, pl
, pl_offset
);
4460 if (pl
== (upl_t
)NULL
)
4461 panic("nfs_pageout: no upl");
4463 if (UBCINVALID(vp
)) {
4464 printf("nfs_pageout: invalid vnode 0x%x", (int)vp
);
4466 ubc_upl_abort(pl
, 0);
4469 UBCINFOCHECK("nfs_pageout", vp
);
4472 printf("nfs_pageout: invalid size %d", size
);
4474 ubc_upl_abort(pl
, 0);
4480 ubc_upl_abort(pl
, UPL_ABORT_DUMP_PAGES
|UPL_ABORT_FREE_ON_EMPTY
);
4483 biosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
4486 * Check to see whether the buffer is incore.
4487 * If incore and not busy, invalidate it from the cache.
4489 for (iosize
= 0; iosize
< size
; iosize
+= xsize
) {
4490 off
= f_offset
+ iosize
;
4491 /* need make sure we do things on block boundaries */
4492 xsize
= biosize
- (off
% biosize
);
4493 if (off
+ xsize
> f_offset
+ size
)
4494 xsize
= f_offset
+ size
- off
;
4495 lbn
= ubc_offtoblk(vp
, off
);
4497 if (bp
= nfs_buf_incore(vp
, lbn
)) {
4498 FSDBG(323, off
, 1, bp
, bp
->nb_flags
);
4499 if (ISSET(bp
->nb_flags
, NB_BUSY
)) {
4500 /* no panic. just tell vm we are busy */
4502 ubc_upl_abort(pl
, 0);
4505 if (bp
->nb_dirtyend
> 0) {
4507 * if there's a dirty range in the buffer, check to
4508 * see if it extends beyond the pageout region
4510 * if the dirty region lies completely within the
4511 * pageout region, we just invalidate the buffer
4512 * because it's all being written out now anyway.
4514 * if any of the dirty region lies outside the
4515 * pageout region, we'll try to clip the dirty
4516 * region to eliminate the portion that's being
4517 * paged out. If that's not possible, because
4518 * the dirty region extends before and after the
4519 * pageout region, then we'll just return EBUSY.
4521 off_t boff
, start
, end
;
4525 /* clip end to EOF */
4526 if (end
> np
->n_size
)
4530 if ((bp
->nb_dirtyoff
< start
) &&
4531 (bp
->nb_dirtyend
> end
)) {
4532 /* not gonna be able to clip the dirty region */
4533 FSDBG(323, vp
, bp
, 0xd00deebc, EBUSY
);
4535 ubc_upl_abort(pl
, 0);
4538 if ((bp
->nb_dirtyoff
< start
) ||
4539 (bp
->nb_dirtyend
> end
)) {
4540 /* clip dirty region, if necessary */
4541 if (bp
->nb_dirtyoff
< start
)
4542 bp
->nb_dirtyend
= min(bp
->nb_dirtyend
, start
);
4543 if (bp
->nb_dirtyend
> end
)
4544 bp
->nb_dirtyoff
= max(bp
->nb_dirtyoff
, end
);
4545 FSDBG(323, bp
, bp
->nb_dirtyoff
, bp
->nb_dirtyend
, 0xd00dee00);
4546 /* we're leaving this block dirty */
4550 nfs_buf_remfree(bp
);
4551 SET(bp
->nb_flags
, (NB_BUSY
| NB_INVAL
));
4552 if (ISSET(bp
->nb_flags
, NB_NEEDCOMMIT
)) {
4553 CLR(bp
->nb_flags
, NB_NEEDCOMMIT
);
4554 np
->n_needcommitcnt
--;
4555 CHECK_NEEDCOMMITCNT(np
);
4557 nfs_buf_release(bp
);
4562 cred
= ubc_getcred(vp
);
4566 if (np
->n_flag
& NWRITEERR
) {
4567 np
->n_flag
&= ~NWRITEERR
;
4569 ubc_upl_abort_range(pl
, pl_offset
, size
,
4570 UPL_ABORT_FREE_ON_EMPTY
);
4571 return (np
->n_error
);
4573 if ((nmp
->nm_flag
& NFSMNT_NFSV3
) &&
4574 !(nmp
->nm_state
& NFSSTA_GOTFSINFO
))
4575 (void)nfs_fsinfo(nmp
, vp
, cred
, p
);
4577 if (f_offset
< 0 || f_offset
>= np
->n_size
||
4578 f_offset
& PAGE_MASK_64
|| size
& PAGE_MASK_64
) {
4580 ubc_upl_abort_range(pl
, pl_offset
, size
,
4581 UPL_ABORT_FREE_ON_EMPTY
);
4585 ubc_upl_map(pl
, &ioaddr
);
4586 ioaddr
+= pl_offset
;
4588 if (f_offset
+ size
> np
->n_size
)
4589 xsize
= np
->n_size
- f_offset
;
4593 pgsize
= round_page_64(xsize
);
4594 if (size
> pgsize
) {
4596 ubc_upl_abort_range(pl
, pl_offset
+ pgsize
,
4598 UPL_ABORT_FREE_ON_EMPTY
);
4602 * check for partial page and clear the
4603 * contents past end of the file before
4604 * releasing it in the VM page cache
4606 if (f_offset
< np
->n_size
&& f_offset
+ size
> np
->n_size
) {
4607 size_t io
= np
->n_size
- f_offset
;
4608 bzero((caddr_t
)(ioaddr
+ io
), size
- io
);
4609 FSDBG(321, np
->n_size
, f_offset
, f_offset
+ io
, size
- io
);
4612 auio
.uio_offset
= f_offset
;
4613 auio
.uio_segflg
= UIO_SYSSPACE
;
4614 auio
.uio_rw
= UIO_READ
;
4615 auio
.uio_procp
= NULL
;
4619 * It would be nice to be able to issue all these requests
4620 * in parallel instead of waiting for each one to complete
4621 * before sending the next one.
4622 * XXX Should we align these requests to block boundaries?
4624 iosize
= min(biosize
, xsize
);
4625 auio
.uio_resid
= iosize
;
4626 aiov
.iov_len
= iosize
;
4627 aiov
.iov_base
= (caddr_t
)ioaddr
;
4628 auio
.uio_iov
= &aiov
;
4629 auio
.uio_iovcnt
= 1;
4631 FSDBG(323, auio
.uio_offset
, auio
.uio_resid
, ioaddr
, xsize
);
4632 // XXX #warning our nfs_pageout does not support NQNFS
4633 nfsstats
.pageouts
++;
4636 /* NMODIFIED would be set here if doing unstable writes */
4637 iomode
= NFSV3WRITE_FILESYNC
;
4638 error
= nfs_writerpc(vp
, &auio
, cred
, &iomode
, &must_commit
);
4640 nfs_clearcommit(vp
->v_mount
);
4644 /* Note: no need to check uio_resid, because */
4645 /* it'll only be set if there was an error. */
4648 } while (xsize
> 0);
4653 * We've had several different solutions on what to do when the pageout
4654 * gets an error. If we don't handle it, and return an error to the
4655 * caller, vm, it will retry . This can end in endless looping
4656 * between vm and here doing retries of the same page. Doing a dump
4657 * back to vm, will get it out of vm's knowledge and we lose whatever
4658 * data existed. This is risky, but in some cases necessary. For
4659 * example, the initial fix here was to do that for ESTALE. In that case
4660 * the server is telling us that the file is no longer the same. We
4661 * would not want to keep paging out to that. We also saw some 151
4662 * errors from Auspex server and NFSv3 can return errors higher than
4663 * ELAST. Those along with NFS known server errors we will "dump" from
4664 * vm. Errors we don't expect to occur, we dump and log for further
4665 * analysis. Errors that could be transient, networking ones,
4666 * we let vm "retry". Lastly, errors that we retry, but may have potential
4667 * to storm the network, we "retrywithsleep". "sever" will be used in
4668 * in the future to dump all pages of object for cases like ESTALE.
4669 * All this is the basis for the states returned and first guesses on
4670 * error handling. Tweaking expected as more statistics are gathered.
4671 * Note, in the long run we may need another more robust solution to
4672 * have some kind of persistant store when the vm cannot dump nor keep
4673 * retrying as a solution, but this would be a file architectural change
4676 if (!nofreeupl
) { /* otherwise stacked file system has to handle this */
4679 short action
= nfs_pageouterrorhandler(error
);
4683 abortflags
= UPL_ABORT_DUMP_PAGES
|UPL_ABORT_FREE_ON_EMPTY
;
4686 abortflags
= UPL_ABORT_DUMP_PAGES
|UPL_ABORT_FREE_ON_EMPTY
;
4687 if (error
<= ELAST
&&
4688 (errorcount
[error
] % 100 == 0))
4689 printf("nfs_pageout: unexpected error %d. dumping vm page\n", error
);
4690 errorcount
[error
]++;
4693 abortflags
= UPL_ABORT_FREE_ON_EMPTY
;
4695 case RETRYWITHSLEEP
:
4696 abortflags
= UPL_ABORT_FREE_ON_EMPTY
;
4697 /* pri unused. PSOCK for placeholder. */
4698 (void) tsleep(&lbolt
, PSOCK
,
4701 case SEVER
: /* not implemented */
4703 printf("nfs_pageout: action %d not expected\n", action
);
4707 ubc_upl_abort_range(pl
, pl_offset
, size
, abortflags
);
4708 /* return error in all cases above */
4711 ubc_upl_commit_range(pl
, pl_offset
, pgsize
,
4712 UPL_COMMIT_CLEAR_DIRTY
|
4713 UPL_COMMIT_FREE_ON_EMPTY
);
4718 /* Blktooff derives file offset given a logical block number */
4721 struct vop_blktooff_args
/* {
4728 register struct vnode
*vp
= ap
->a_vp
;
4733 biosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
4735 *ap
->a_offset
= (off_t
)ap
->a_lblkno
* biosize
;
4742 struct vop_offtoblk_args
/* {
4749 register struct vnode
*vp
= ap
->a_vp
;
4754 biosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
4756 *ap
->a_lblkno
= (daddr_t
)(ap
->a_offset
/ biosize
);
4762 struct vop_cmap_args
/* {
4771 return (EOPNOTSUPP
);