]> git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_vnops.c
xnu-1699.32.7.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_vnops.c
1 /*
2 * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29 /*
30 * Copyright (c) 1989, 1993
31 * The Regents of the University of California. All rights reserved.
32 *
33 * This code is derived from software contributed to Berkeley by
34 * Rick Macklem at The University of Guelph.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
65 * FreeBSD-Id: nfs_vnops.c,v 1.72 1997/11/07 09:20:48 phk Exp $
66 */
67
68
69 /*
70 * vnode op calls for Sun NFS version 2 and 3
71 */
72 #include <sys/param.h>
73 #include <sys/kernel.h>
74 #include <sys/systm.h>
75 #include <sys/resourcevar.h>
76 #include <sys/proc_internal.h>
77 #include <sys/kauth.h>
78 #include <sys/mount_internal.h>
79 #include <sys/malloc.h>
80 #include <sys/kpi_mbuf.h>
81 #include <sys/conf.h>
82 #include <sys/vnode_internal.h>
83 #include <sys/dirent.h>
84 #include <sys/fcntl.h>
85 #include <sys/lockf.h>
86 #include <sys/ubc_internal.h>
87 #include <sys/attr.h>
88 #include <sys/signalvar.h>
89 #include <sys/uio_internal.h>
90
91 #include <vfs/vfs_support.h>
92
93 #include <sys/vm.h>
94
95 #include <sys/time.h>
96 #include <kern/clock.h>
97 #include <libkern/OSAtomic.h>
98
99 #include <miscfs/fifofs/fifo.h>
100 #include <miscfs/specfs/specdev.h>
101
102 #include <nfs/rpcv2.h>
103 #include <nfs/nfsproto.h>
104 #include <nfs/nfs.h>
105 #include <nfs/nfsnode.h>
106 #include <nfs/nfs_gss.h>
107 #include <nfs/nfsmount.h>
108 #include <nfs/nfs_lock.h>
109 #include <nfs/xdr_subs.h>
110 #include <nfs/nfsm_subs.h>
111
112 #include <net/if.h>
113 #include <netinet/in.h>
114 #include <netinet/in_var.h>
115
116 #include <vm/vm_kern.h>
117 #include <vm/vm_pageout.h>
118
119 #include <kern/task.h>
120 #include <kern/sched_prim.h>
121
122 /*
123 * NFS vnode ops
124 */
125 int nfs_vnop_lookup(struct vnop_lookup_args *);
126 int nfsspec_vnop_read(struct vnop_read_args *);
127 int nfsspec_vnop_write(struct vnop_write_args *);
128 int nfsspec_vnop_close(struct vnop_close_args *);
129 #if FIFO
130 int nfsfifo_vnop_read(struct vnop_read_args *);
131 int nfsfifo_vnop_write(struct vnop_write_args *);
132 int nfsfifo_vnop_close(struct vnop_close_args *);
133 #endif
134 int nfs_vnop_ioctl(struct vnop_ioctl_args *);
135 int nfs_vnop_select(struct vnop_select_args *);
136 int nfs_vnop_setattr(struct vnop_setattr_args *);
137 int nfs_vnop_fsync(struct vnop_fsync_args *);
138 int nfs_vnop_rename(struct vnop_rename_args *);
139 int nfs_vnop_readdir(struct vnop_readdir_args *);
140 int nfs_vnop_readlink(struct vnop_readlink_args *);
141 int nfs_vnop_pathconf(struct vnop_pathconf_args *);
142 int nfs_vnop_pagein(struct vnop_pagein_args *);
143 int nfs_vnop_pageout(struct vnop_pageout_args *);
144 int nfs_vnop_blktooff(struct vnop_blktooff_args *);
145 int nfs_vnop_offtoblk(struct vnop_offtoblk_args *);
146 int nfs_vnop_blockmap(struct vnop_blockmap_args *);
147 int nfs_vnop_monitor(struct vnop_monitor_args *);
148
149 int nfs3_vnop_create(struct vnop_create_args *);
150 int nfs3_vnop_mknod(struct vnop_mknod_args *);
151 int nfs3_vnop_getattr(struct vnop_getattr_args *);
152 int nfs3_vnop_link(struct vnop_link_args *);
153 int nfs3_vnop_mkdir(struct vnop_mkdir_args *);
154 int nfs3_vnop_rmdir(struct vnop_rmdir_args *);
155 int nfs3_vnop_symlink(struct vnop_symlink_args *);
156
157 vnop_t **nfsv2_vnodeop_p;
158 static struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
159 { &vnop_default_desc, (vnop_t *)vn_default_error },
160 { &vnop_lookup_desc, (vnop_t *)nfs_vnop_lookup }, /* lookup */
161 { &vnop_create_desc, (vnop_t *)nfs3_vnop_create }, /* create */
162 { &vnop_mknod_desc, (vnop_t *)nfs3_vnop_mknod }, /* mknod */
163 { &vnop_open_desc, (vnop_t *)nfs_vnop_open }, /* open */
164 { &vnop_close_desc, (vnop_t *)nfs_vnop_close }, /* close */
165 { &vnop_access_desc, (vnop_t *)nfs_vnop_access }, /* access */
166 { &vnop_getattr_desc, (vnop_t *)nfs3_vnop_getattr }, /* getattr */
167 { &vnop_setattr_desc, (vnop_t *)nfs_vnop_setattr }, /* setattr */
168 { &vnop_read_desc, (vnop_t *)nfs_vnop_read }, /* read */
169 { &vnop_write_desc, (vnop_t *)nfs_vnop_write }, /* write */
170 { &vnop_ioctl_desc, (vnop_t *)nfs_vnop_ioctl }, /* ioctl */
171 { &vnop_select_desc, (vnop_t *)nfs_vnop_select }, /* select */
172 { &vnop_revoke_desc, (vnop_t *)nfs_vnop_revoke }, /* revoke */
173 { &vnop_mmap_desc, (vnop_t *)nfs_vnop_mmap }, /* mmap */
174 { &vnop_mnomap_desc, (vnop_t *)nfs_vnop_mnomap }, /* mnomap */
175 { &vnop_fsync_desc, (vnop_t *)nfs_vnop_fsync }, /* fsync */
176 { &vnop_remove_desc, (vnop_t *)nfs_vnop_remove }, /* remove */
177 { &vnop_link_desc, (vnop_t *)nfs3_vnop_link }, /* link */
178 { &vnop_rename_desc, (vnop_t *)nfs_vnop_rename }, /* rename */
179 { &vnop_mkdir_desc, (vnop_t *)nfs3_vnop_mkdir }, /* mkdir */
180 { &vnop_rmdir_desc, (vnop_t *)nfs3_vnop_rmdir }, /* rmdir */
181 { &vnop_symlink_desc, (vnop_t *)nfs3_vnop_symlink }, /* symlink */
182 { &vnop_readdir_desc, (vnop_t *)nfs_vnop_readdir }, /* readdir */
183 { &vnop_readlink_desc, (vnop_t *)nfs_vnop_readlink }, /* readlink */
184 { &vnop_inactive_desc, (vnop_t *)nfs_vnop_inactive }, /* inactive */
185 { &vnop_reclaim_desc, (vnop_t *)nfs_vnop_reclaim }, /* reclaim */
186 { &vnop_strategy_desc, (vnop_t *)err_strategy }, /* strategy */
187 { &vnop_pathconf_desc, (vnop_t *)nfs_vnop_pathconf }, /* pathconf */
188 { &vnop_advlock_desc, (vnop_t *)nfs_vnop_advlock }, /* advlock */
189 { &vnop_bwrite_desc, (vnop_t *)err_bwrite }, /* bwrite */
190 { &vnop_pagein_desc, (vnop_t *)nfs_vnop_pagein }, /* Pagein */
191 { &vnop_pageout_desc, (vnop_t *)nfs_vnop_pageout }, /* Pageout */
192 { &vnop_copyfile_desc, (vnop_t *)err_copyfile }, /* Copyfile */
193 { &vnop_blktooff_desc, (vnop_t *)nfs_vnop_blktooff }, /* blktooff */
194 { &vnop_offtoblk_desc, (vnop_t *)nfs_vnop_offtoblk }, /* offtoblk */
195 { &vnop_blockmap_desc, (vnop_t *)nfs_vnop_blockmap }, /* blockmap */
196 { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor }, /* monitor */
197 { NULL, NULL }
198 };
199 struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
200 { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
201
202 vnop_t **nfsv4_vnodeop_p;
203 static struct vnodeopv_entry_desc nfsv4_vnodeop_entries[] = {
204 { &vnop_default_desc, (vnop_t *)vn_default_error },
205 { &vnop_lookup_desc, (vnop_t *)nfs_vnop_lookup }, /* lookup */
206 { &vnop_create_desc, (vnop_t *)nfs4_vnop_create }, /* create */
207 { &vnop_mknod_desc, (vnop_t *)nfs4_vnop_mknod }, /* mknod */
208 { &vnop_open_desc, (vnop_t *)nfs_vnop_open }, /* open */
209 { &vnop_close_desc, (vnop_t *)nfs_vnop_close }, /* close */
210 { &vnop_access_desc, (vnop_t *)nfs_vnop_access }, /* access */
211 { &vnop_getattr_desc, (vnop_t *)nfs4_vnop_getattr }, /* getattr */
212 { &vnop_setattr_desc, (vnop_t *)nfs_vnop_setattr }, /* setattr */
213 { &vnop_read_desc, (vnop_t *)nfs_vnop_read }, /* read */
214 { &vnop_write_desc, (vnop_t *)nfs_vnop_write }, /* write */
215 { &vnop_ioctl_desc, (vnop_t *)nfs_vnop_ioctl }, /* ioctl */
216 { &vnop_select_desc, (vnop_t *)nfs_vnop_select }, /* select */
217 { &vnop_revoke_desc, (vnop_t *)nfs_vnop_revoke }, /* revoke */
218 { &vnop_mmap_desc, (vnop_t *)nfs_vnop_mmap }, /* mmap */
219 { &vnop_mnomap_desc, (vnop_t *)nfs_vnop_mnomap }, /* mnomap */
220 { &vnop_fsync_desc, (vnop_t *)nfs_vnop_fsync }, /* fsync */
221 { &vnop_remove_desc, (vnop_t *)nfs_vnop_remove }, /* remove */
222 { &vnop_link_desc, (vnop_t *)nfs4_vnop_link }, /* link */
223 { &vnop_rename_desc, (vnop_t *)nfs_vnop_rename }, /* rename */
224 { &vnop_mkdir_desc, (vnop_t *)nfs4_vnop_mkdir }, /* mkdir */
225 { &vnop_rmdir_desc, (vnop_t *)nfs4_vnop_rmdir }, /* rmdir */
226 { &vnop_symlink_desc, (vnop_t *)nfs4_vnop_symlink }, /* symlink */
227 { &vnop_readdir_desc, (vnop_t *)nfs_vnop_readdir }, /* readdir */
228 { &vnop_readlink_desc, (vnop_t *)nfs_vnop_readlink }, /* readlink */
229 { &vnop_inactive_desc, (vnop_t *)nfs_vnop_inactive }, /* inactive */
230 { &vnop_reclaim_desc, (vnop_t *)nfs_vnop_reclaim }, /* reclaim */
231 { &vnop_strategy_desc, (vnop_t *)err_strategy }, /* strategy */
232 { &vnop_pathconf_desc, (vnop_t *)nfs_vnop_pathconf }, /* pathconf */
233 { &vnop_advlock_desc, (vnop_t *)nfs_vnop_advlock }, /* advlock */
234 { &vnop_bwrite_desc, (vnop_t *)err_bwrite }, /* bwrite */
235 { &vnop_pagein_desc, (vnop_t *)nfs_vnop_pagein }, /* Pagein */
236 { &vnop_pageout_desc, (vnop_t *)nfs_vnop_pageout }, /* Pageout */
237 { &vnop_copyfile_desc, (vnop_t *)err_copyfile }, /* Copyfile */
238 { &vnop_blktooff_desc, (vnop_t *)nfs_vnop_blktooff }, /* blktooff */
239 { &vnop_offtoblk_desc, (vnop_t *)nfs_vnop_offtoblk }, /* offtoblk */
240 { &vnop_blockmap_desc, (vnop_t *)nfs_vnop_blockmap }, /* blockmap */
241 { &vnop_getxattr_desc, (vnop_t *)nfs4_vnop_getxattr }, /* getxattr */
242 { &vnop_setxattr_desc, (vnop_t *)nfs4_vnop_setxattr }, /* setxattr */
243 { &vnop_removexattr_desc, (vnop_t *)nfs4_vnop_removexattr },/* removexattr */
244 { &vnop_listxattr_desc, (vnop_t *)nfs4_vnop_listxattr },/* listxattr */
245 #if NAMEDSTREAMS
246 { &vnop_getnamedstream_desc, (vnop_t *)nfs4_vnop_getnamedstream }, /* getnamedstream */
247 { &vnop_makenamedstream_desc, (vnop_t *)nfs4_vnop_makenamedstream }, /* makenamedstream */
248 { &vnop_removenamedstream_desc, (vnop_t *)nfs4_vnop_removenamedstream },/* removenamedstream */
249 #endif
250 { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor }, /* monitor */
251 { NULL, NULL }
252 };
253 struct vnodeopv_desc nfsv4_vnodeop_opv_desc =
254 { &nfsv4_vnodeop_p, nfsv4_vnodeop_entries };
255
256 /*
257 * Special device vnode ops
258 */
259 vnop_t **spec_nfsv2nodeop_p;
260 static struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
261 { &vnop_default_desc, (vnop_t *)vn_default_error },
262 { &vnop_lookup_desc, (vnop_t *)spec_lookup }, /* lookup */
263 { &vnop_create_desc, (vnop_t *)spec_create }, /* create */
264 { &vnop_mknod_desc, (vnop_t *)spec_mknod }, /* mknod */
265 { &vnop_open_desc, (vnop_t *)spec_open }, /* open */
266 { &vnop_close_desc, (vnop_t *)nfsspec_vnop_close }, /* close */
267 { &vnop_getattr_desc, (vnop_t *)nfs3_vnop_getattr }, /* getattr */
268 { &vnop_setattr_desc, (vnop_t *)nfs_vnop_setattr }, /* setattr */
269 { &vnop_read_desc, (vnop_t *)nfsspec_vnop_read }, /* read */
270 { &vnop_write_desc, (vnop_t *)nfsspec_vnop_write }, /* write */
271 { &vnop_ioctl_desc, (vnop_t *)spec_ioctl }, /* ioctl */
272 { &vnop_select_desc, (vnop_t *)spec_select }, /* select */
273 { &vnop_revoke_desc, (vnop_t *)spec_revoke }, /* revoke */
274 { &vnop_mmap_desc, (vnop_t *)spec_mmap }, /* mmap */
275 { &vnop_fsync_desc, (vnop_t *)nfs_vnop_fsync }, /* fsync */
276 { &vnop_remove_desc, (vnop_t *)spec_remove }, /* remove */
277 { &vnop_link_desc, (vnop_t *)spec_link }, /* link */
278 { &vnop_rename_desc, (vnop_t *)spec_rename }, /* rename */
279 { &vnop_mkdir_desc, (vnop_t *)spec_mkdir }, /* mkdir */
280 { &vnop_rmdir_desc, (vnop_t *)spec_rmdir }, /* rmdir */
281 { &vnop_symlink_desc, (vnop_t *)spec_symlink }, /* symlink */
282 { &vnop_readdir_desc, (vnop_t *)spec_readdir }, /* readdir */
283 { &vnop_readlink_desc, (vnop_t *)spec_readlink }, /* readlink */
284 { &vnop_inactive_desc, (vnop_t *)nfs_vnop_inactive }, /* inactive */
285 { &vnop_reclaim_desc, (vnop_t *)nfs_vnop_reclaim }, /* reclaim */
286 { &vnop_strategy_desc, (vnop_t *)spec_strategy }, /* strategy */
287 { &vnop_pathconf_desc, (vnop_t *)spec_pathconf }, /* pathconf */
288 { &vnop_advlock_desc, (vnop_t *)spec_advlock }, /* advlock */
289 { &vnop_bwrite_desc, (vnop_t *)vn_bwrite }, /* bwrite */
290 { &vnop_pagein_desc, (vnop_t *)nfs_vnop_pagein }, /* Pagein */
291 { &vnop_pageout_desc, (vnop_t *)nfs_vnop_pageout }, /* Pageout */
292 { &vnop_blktooff_desc, (vnop_t *)nfs_vnop_blktooff }, /* blktooff */
293 { &vnop_offtoblk_desc, (vnop_t *)nfs_vnop_offtoblk }, /* offtoblk */
294 { &vnop_blockmap_desc, (vnop_t *)nfs_vnop_blockmap }, /* blockmap */
295 { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor }, /* monitor */
296 { NULL, NULL }
297 };
298 struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
299 { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
300 vnop_t **spec_nfsv4nodeop_p;
301 static struct vnodeopv_entry_desc spec_nfsv4nodeop_entries[] = {
302 { &vnop_default_desc, (vnop_t *)vn_default_error },
303 { &vnop_lookup_desc, (vnop_t *)spec_lookup }, /* lookup */
304 { &vnop_create_desc, (vnop_t *)spec_create }, /* create */
305 { &vnop_mknod_desc, (vnop_t *)spec_mknod }, /* mknod */
306 { &vnop_open_desc, (vnop_t *)spec_open }, /* open */
307 { &vnop_close_desc, (vnop_t *)nfsspec_vnop_close }, /* close */
308 { &vnop_getattr_desc, (vnop_t *)nfs4_vnop_getattr }, /* getattr */
309 { &vnop_setattr_desc, (vnop_t *)nfs_vnop_setattr }, /* setattr */
310 { &vnop_read_desc, (vnop_t *)nfsspec_vnop_read }, /* read */
311 { &vnop_write_desc, (vnop_t *)nfsspec_vnop_write }, /* write */
312 { &vnop_ioctl_desc, (vnop_t *)spec_ioctl }, /* ioctl */
313 { &vnop_select_desc, (vnop_t *)spec_select }, /* select */
314 { &vnop_revoke_desc, (vnop_t *)spec_revoke }, /* revoke */
315 { &vnop_mmap_desc, (vnop_t *)spec_mmap }, /* mmap */
316 { &vnop_fsync_desc, (vnop_t *)nfs_vnop_fsync }, /* fsync */
317 { &vnop_remove_desc, (vnop_t *)spec_remove }, /* remove */
318 { &vnop_link_desc, (vnop_t *)spec_link }, /* link */
319 { &vnop_rename_desc, (vnop_t *)spec_rename }, /* rename */
320 { &vnop_mkdir_desc, (vnop_t *)spec_mkdir }, /* mkdir */
321 { &vnop_rmdir_desc, (vnop_t *)spec_rmdir }, /* rmdir */
322 { &vnop_symlink_desc, (vnop_t *)spec_symlink }, /* symlink */
323 { &vnop_readdir_desc, (vnop_t *)spec_readdir }, /* readdir */
324 { &vnop_readlink_desc, (vnop_t *)spec_readlink }, /* readlink */
325 { &vnop_inactive_desc, (vnop_t *)nfs_vnop_inactive }, /* inactive */
326 { &vnop_reclaim_desc, (vnop_t *)nfs_vnop_reclaim }, /* reclaim */
327 { &vnop_strategy_desc, (vnop_t *)spec_strategy }, /* strategy */
328 { &vnop_pathconf_desc, (vnop_t *)spec_pathconf }, /* pathconf */
329 { &vnop_advlock_desc, (vnop_t *)spec_advlock }, /* advlock */
330 { &vnop_bwrite_desc, (vnop_t *)vn_bwrite }, /* bwrite */
331 { &vnop_pagein_desc, (vnop_t *)nfs_vnop_pagein }, /* Pagein */
332 { &vnop_pageout_desc, (vnop_t *)nfs_vnop_pageout }, /* Pageout */
333 { &vnop_blktooff_desc, (vnop_t *)nfs_vnop_blktooff }, /* blktooff */
334 { &vnop_offtoblk_desc, (vnop_t *)nfs_vnop_offtoblk }, /* offtoblk */
335 { &vnop_blockmap_desc, (vnop_t *)nfs_vnop_blockmap }, /* blockmap */
336 { &vnop_getxattr_desc, (vnop_t *)nfs4_vnop_getxattr }, /* getxattr */
337 { &vnop_setxattr_desc, (vnop_t *)nfs4_vnop_setxattr }, /* setxattr */
338 { &vnop_removexattr_desc, (vnop_t *)nfs4_vnop_removexattr },/* removexattr */
339 { &vnop_listxattr_desc, (vnop_t *)nfs4_vnop_listxattr },/* listxattr */
340 #if NAMEDSTREAMS
341 { &vnop_getnamedstream_desc, (vnop_t *)nfs4_vnop_getnamedstream }, /* getnamedstream */
342 { &vnop_makenamedstream_desc, (vnop_t *)nfs4_vnop_makenamedstream }, /* makenamedstream */
343 { &vnop_removenamedstream_desc, (vnop_t *)nfs4_vnop_removenamedstream },/* removenamedstream */
344 #endif
345 { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor }, /* monitor */
346 { NULL, NULL }
347 };
348 struct vnodeopv_desc spec_nfsv4nodeop_opv_desc =
349 { &spec_nfsv4nodeop_p, spec_nfsv4nodeop_entries };
350
351 #if FIFO
352 vnop_t **fifo_nfsv2nodeop_p;
353 static struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
354 { &vnop_default_desc, (vnop_t *)vn_default_error },
355 { &vnop_lookup_desc, (vnop_t *)fifo_lookup }, /* lookup */
356 { &vnop_create_desc, (vnop_t *)fifo_create }, /* create */
357 { &vnop_mknod_desc, (vnop_t *)fifo_mknod }, /* mknod */
358 { &vnop_open_desc, (vnop_t *)fifo_open }, /* open */
359 { &vnop_close_desc, (vnop_t *)nfsfifo_vnop_close }, /* close */
360 { &vnop_getattr_desc, (vnop_t *)nfs3_vnop_getattr }, /* getattr */
361 { &vnop_setattr_desc, (vnop_t *)nfs_vnop_setattr }, /* setattr */
362 { &vnop_read_desc, (vnop_t *)nfsfifo_vnop_read }, /* read */
363 { &vnop_write_desc, (vnop_t *)nfsfifo_vnop_write }, /* write */
364 { &vnop_ioctl_desc, (vnop_t *)fifo_ioctl }, /* ioctl */
365 { &vnop_select_desc, (vnop_t *)fifo_select }, /* select */
366 { &vnop_revoke_desc, (vnop_t *)fifo_revoke }, /* revoke */
367 { &vnop_mmap_desc, (vnop_t *)fifo_mmap }, /* mmap */
368 { &vnop_fsync_desc, (vnop_t *)nfs_vnop_fsync }, /* fsync */
369 { &vnop_remove_desc, (vnop_t *)fifo_remove }, /* remove */
370 { &vnop_link_desc, (vnop_t *)fifo_link }, /* link */
371 { &vnop_rename_desc, (vnop_t *)fifo_rename }, /* rename */
372 { &vnop_mkdir_desc, (vnop_t *)fifo_mkdir }, /* mkdir */
373 { &vnop_rmdir_desc, (vnop_t *)fifo_rmdir }, /* rmdir */
374 { &vnop_symlink_desc, (vnop_t *)fifo_symlink }, /* symlink */
375 { &vnop_readdir_desc, (vnop_t *)fifo_readdir }, /* readdir */
376 { &vnop_readlink_desc, (vnop_t *)fifo_readlink }, /* readlink */
377 { &vnop_inactive_desc, (vnop_t *)nfs_vnop_inactive }, /* inactive */
378 { &vnop_reclaim_desc, (vnop_t *)nfs_vnop_reclaim }, /* reclaim */
379 { &vnop_strategy_desc, (vnop_t *)fifo_strategy }, /* strategy */
380 { &vnop_pathconf_desc, (vnop_t *)fifo_pathconf }, /* pathconf */
381 { &vnop_advlock_desc, (vnop_t *)fifo_advlock }, /* advlock */
382 { &vnop_bwrite_desc, (vnop_t *)vn_bwrite }, /* bwrite */
383 { &vnop_pagein_desc, (vnop_t *)nfs_vnop_pagein }, /* Pagein */
384 { &vnop_pageout_desc, (vnop_t *)nfs_vnop_pageout }, /* Pageout */
385 { &vnop_blktooff_desc, (vnop_t *)nfs_vnop_blktooff }, /* blktooff */
386 { &vnop_offtoblk_desc, (vnop_t *)nfs_vnop_offtoblk }, /* offtoblk */
387 { &vnop_blockmap_desc, (vnop_t *)nfs_vnop_blockmap }, /* blockmap */
388 { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor }, /* monitor */
389 { NULL, NULL }
390 };
391 struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
392 { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
393
394 vnop_t **fifo_nfsv4nodeop_p;
395 static struct vnodeopv_entry_desc fifo_nfsv4nodeop_entries[] = {
396 { &vnop_default_desc, (vnop_t *)vn_default_error },
397 { &vnop_lookup_desc, (vnop_t *)fifo_lookup }, /* lookup */
398 { &vnop_create_desc, (vnop_t *)fifo_create }, /* create */
399 { &vnop_mknod_desc, (vnop_t *)fifo_mknod }, /* mknod */
400 { &vnop_open_desc, (vnop_t *)fifo_open }, /* open */
401 { &vnop_close_desc, (vnop_t *)nfsfifo_vnop_close }, /* close */
402 { &vnop_getattr_desc, (vnop_t *)nfs4_vnop_getattr }, /* getattr */
403 { &vnop_setattr_desc, (vnop_t *)nfs_vnop_setattr }, /* setattr */
404 { &vnop_read_desc, (vnop_t *)nfsfifo_vnop_read }, /* read */
405 { &vnop_write_desc, (vnop_t *)nfsfifo_vnop_write }, /* write */
406 { &vnop_ioctl_desc, (vnop_t *)fifo_ioctl }, /* ioctl */
407 { &vnop_select_desc, (vnop_t *)fifo_select }, /* select */
408 { &vnop_revoke_desc, (vnop_t *)fifo_revoke }, /* revoke */
409 { &vnop_mmap_desc, (vnop_t *)fifo_mmap }, /* mmap */
410 { &vnop_fsync_desc, (vnop_t *)nfs_vnop_fsync }, /* fsync */
411 { &vnop_remove_desc, (vnop_t *)fifo_remove }, /* remove */
412 { &vnop_link_desc, (vnop_t *)fifo_link }, /* link */
413 { &vnop_rename_desc, (vnop_t *)fifo_rename }, /* rename */
414 { &vnop_mkdir_desc, (vnop_t *)fifo_mkdir }, /* mkdir */
415 { &vnop_rmdir_desc, (vnop_t *)fifo_rmdir }, /* rmdir */
416 { &vnop_symlink_desc, (vnop_t *)fifo_symlink }, /* symlink */
417 { &vnop_readdir_desc, (vnop_t *)fifo_readdir }, /* readdir */
418 { &vnop_readlink_desc, (vnop_t *)fifo_readlink }, /* readlink */
419 { &vnop_inactive_desc, (vnop_t *)nfs_vnop_inactive }, /* inactive */
420 { &vnop_reclaim_desc, (vnop_t *)nfs_vnop_reclaim }, /* reclaim */
421 { &vnop_strategy_desc, (vnop_t *)fifo_strategy }, /* strategy */
422 { &vnop_pathconf_desc, (vnop_t *)fifo_pathconf }, /* pathconf */
423 { &vnop_advlock_desc, (vnop_t *)fifo_advlock }, /* advlock */
424 { &vnop_bwrite_desc, (vnop_t *)vn_bwrite }, /* bwrite */
425 { &vnop_pagein_desc, (vnop_t *)nfs_vnop_pagein }, /* Pagein */
426 { &vnop_pageout_desc, (vnop_t *)nfs_vnop_pageout }, /* Pageout */
427 { &vnop_blktooff_desc, (vnop_t *)nfs_vnop_blktooff }, /* blktooff */
428 { &vnop_offtoblk_desc, (vnop_t *)nfs_vnop_offtoblk }, /* offtoblk */
429 { &vnop_blockmap_desc, (vnop_t *)nfs_vnop_blockmap }, /* blockmap */
430 { &vnop_getxattr_desc, (vnop_t *)nfs4_vnop_getxattr }, /* getxattr */
431 { &vnop_setxattr_desc, (vnop_t *)nfs4_vnop_setxattr }, /* setxattr */
432 { &vnop_removexattr_desc, (vnop_t *)nfs4_vnop_removexattr },/* removexattr */
433 { &vnop_listxattr_desc, (vnop_t *)nfs4_vnop_listxattr },/* listxattr */
434 #if NAMEDSTREAMS
435 { &vnop_getnamedstream_desc, (vnop_t *)nfs4_vnop_getnamedstream }, /* getnamedstream */
436 { &vnop_makenamedstream_desc, (vnop_t *)nfs4_vnop_makenamedstream }, /* makenamedstream */
437 { &vnop_removenamedstream_desc, (vnop_t *)nfs4_vnop_removenamedstream },/* removenamedstream */
438 #endif
439 { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor }, /* monitor */
440 { NULL, NULL }
441 };
442 struct vnodeopv_desc fifo_nfsv4nodeop_opv_desc =
443 { &fifo_nfsv4nodeop_p, fifo_nfsv4nodeop_entries };
444 #endif /* FIFO */
445
446
447 int nfs_sillyrename(nfsnode_t,nfsnode_t,struct componentname *,vfs_context_t);
448
449 /*
450 * Find the slot in the access cache for this UID.
451 * If adding and no existing slot is found, reuse slots in FIFO order.
452 * The index of the next slot to use is kept in the last entry of the n_access array.
453 */
454 int
455 nfs_node_access_slot(nfsnode_t np, uid_t uid, int add)
456 {
457 int slot;
458
459 for (slot=0; slot < NFS_ACCESS_CACHE_SIZE; slot++)
460 if (np->n_accessuid[slot] == uid)
461 break;
462 if (slot == NFS_ACCESS_CACHE_SIZE) {
463 if (!add)
464 return (-1);
465 slot = np->n_access[NFS_ACCESS_CACHE_SIZE];
466 np->n_access[NFS_ACCESS_CACHE_SIZE] = (slot + 1) % NFS_ACCESS_CACHE_SIZE;
467 }
468 return (slot);
469 }
470
471 int
472 nfs3_access_rpc(nfsnode_t np, u_int32_t *access, vfs_context_t ctx)
473 {
474 int error = 0, lockerror = ENOENT, status, slot;
475 uint32_t access_result = 0;
476 u_int64_t xid;
477 struct nfsm_chain nmreq, nmrep;
478 struct timeval now;
479 uid_t uid;
480
481 nfsm_chain_null(&nmreq);
482 nfsm_chain_null(&nmrep);
483
484 nfsm_chain_build_alloc_init(error, &nmreq, NFSX_FH(NFS_VER3) + NFSX_UNSIGNED);
485 nfsm_chain_add_fh(error, &nmreq, NFS_VER3, np->n_fhp, np->n_fhsize);
486 nfsm_chain_add_32(error, &nmreq, *access);
487 nfsm_chain_build_done(error, &nmreq);
488 nfsmout_if(error);
489 error = nfs_request(np, NULL, &nmreq, NFSPROC_ACCESS, ctx, NULL, &nmrep, &xid, &status);
490 if ((lockerror = nfs_node_lock(np)))
491 error = lockerror;
492 nfsm_chain_postop_attr_update(error, &nmrep, np, &xid);
493 if (!error)
494 error = status;
495 nfsm_chain_get_32(error, &nmrep, access_result);
496 nfsmout_if(error);
497
498 uid = kauth_cred_getuid(vfs_context_ucred(ctx));
499 slot = nfs_node_access_slot(np, uid, 1);
500 np->n_accessuid[slot] = uid;
501 microuptime(&now);
502 np->n_accessstamp[slot] = now.tv_sec;
503 np->n_access[slot] = access_result;
504
505 /*
506 * If we asked for DELETE but didn't get it, the server
507 * may simply not support returning that bit (possible
508 * on UNIX systems). So, we'll assume that it is OK,
509 * and just let any subsequent delete action fail if it
510 * really isn't deletable.
511 */
512 if ((*access & NFS_ACCESS_DELETE) &&
513 !(np->n_access[slot] & NFS_ACCESS_DELETE))
514 np->n_access[slot] |= NFS_ACCESS_DELETE;
515 /* ".zfs" subdirectories may erroneously give a denied answer for add/remove */
516 if (nfs_access_dotzfs && (np->n_flag & NISDOTZFSCHILD))
517 np->n_access[slot] |= (NFS_ACCESS_MODIFY|NFS_ACCESS_EXTEND|NFS_ACCESS_DELETE);
518 /* pass back the access returned with this request */
519 *access = np->n_access[slot];
520 nfsmout:
521 if (!lockerror)
522 nfs_node_unlock(np);
523 nfsm_chain_cleanup(&nmreq);
524 nfsm_chain_cleanup(&nmrep);
525 return (error);
526 }
527
528 /*
529 * NFS access vnode op.
530 * For NFS version 2, just return ok. File accesses may fail later.
531 * For NFS version 3+, use the access RPC to check accessibility. If file
532 * permissions are changed on the server, accesses might still fail later.
533 */
534 int
535 nfs_vnop_access(
536 struct vnop_access_args /* {
537 struct vnodeop_desc *a_desc;
538 vnode_t a_vp;
539 int a_action;
540 vfs_context_t a_context;
541 } */ *ap)
542 {
543 vfs_context_t ctx = ap->a_context;
544 vnode_t vp = ap->a_vp;
545 int error = 0, slot, dorpc;
546 u_int32_t access, waccess;
547 nfsnode_t np = VTONFS(vp);
548 struct nfsmount *nmp;
549 int nfsvers;
550 struct timeval now;
551 uid_t uid;
552
553 nmp = VTONMP(vp);
554 if (!nmp)
555 return (ENXIO);
556 nfsvers = nmp->nm_vers;
557
558 if (nfsvers == NFS_VER2) {
559 if ((ap->a_action & KAUTH_VNODE_WRITE_RIGHTS) &&
560 vfs_isrdonly(vnode_mount(vp)))
561 return (EROFS);
562 return (0);
563 }
564
565 /*
566 * For NFS v3, do an access rpc, otherwise you are stuck emulating
567 * ufs_access() locally using the vattr. This may not be correct,
568 * since the server may apply other access criteria such as
569 * client uid-->server uid mapping that we do not know about, but
570 * this is better than just returning anything that is lying about
571 * in the cache.
572 */
573
574 /*
575 * Convert KAUTH primitives to NFS access rights.
576 */
577 access = 0;
578 if (vnode_isdir(vp)) {
579 /* directory */
580 if (ap->a_action &
581 (KAUTH_VNODE_LIST_DIRECTORY |
582 KAUTH_VNODE_READ_EXTATTRIBUTES))
583 access |= NFS_ACCESS_READ;
584 if (ap->a_action & KAUTH_VNODE_SEARCH)
585 access |= NFS_ACCESS_LOOKUP;
586 if (ap->a_action &
587 (KAUTH_VNODE_ADD_FILE |
588 KAUTH_VNODE_ADD_SUBDIRECTORY))
589 access |= NFS_ACCESS_MODIFY | NFS_ACCESS_EXTEND;
590 if (ap->a_action & KAUTH_VNODE_DELETE_CHILD)
591 access |= NFS_ACCESS_MODIFY;
592 } else {
593 /* file */
594 if (ap->a_action &
595 (KAUTH_VNODE_READ_DATA |
596 KAUTH_VNODE_READ_EXTATTRIBUTES))
597 access |= NFS_ACCESS_READ;
598 if (ap->a_action & KAUTH_VNODE_WRITE_DATA)
599 access |= NFS_ACCESS_MODIFY | NFS_ACCESS_EXTEND;
600 if (ap->a_action & KAUTH_VNODE_APPEND_DATA)
601 access |= NFS_ACCESS_EXTEND;
602 if (ap->a_action & KAUTH_VNODE_EXECUTE)
603 access |= NFS_ACCESS_EXECUTE;
604 }
605 /* common */
606 if (ap->a_action & KAUTH_VNODE_DELETE)
607 access |= NFS_ACCESS_DELETE;
608 if (ap->a_action &
609 (KAUTH_VNODE_WRITE_ATTRIBUTES |
610 KAUTH_VNODE_WRITE_EXTATTRIBUTES |
611 KAUTH_VNODE_WRITE_SECURITY))
612 access |= NFS_ACCESS_MODIFY;
613 /* XXX this is pretty dubious */
614 if (ap->a_action & KAUTH_VNODE_CHANGE_OWNER)
615 access |= NFS_ACCESS_MODIFY;
616
617 /* if caching, always ask for every right */
618 if (nfs_access_cache_timeout > 0) {
619 waccess = NFS_ACCESS_READ | NFS_ACCESS_MODIFY |
620 NFS_ACCESS_EXTEND | NFS_ACCESS_EXECUTE |
621 NFS_ACCESS_DELETE | NFS_ACCESS_LOOKUP;
622 } else {
623 waccess = access;
624 }
625
626 if ((error = nfs_node_lock(np)))
627 return (error);
628
629 /*
630 * Does our cached result allow us to give a definite yes to
631 * this request?
632 */
633 uid = kauth_cred_getuid(vfs_context_ucred(ctx));
634 slot = nfs_node_access_slot(np, uid, 0);
635 dorpc = 1;
636 if (access == 0) {
637 /* not asking for any rights understood by NFS, so don't bother doing an RPC */
638 /* OSAddAtomic(1, &nfsstats.accesscache_hits); */
639 dorpc = 0;
640 waccess = 0;
641 } else if (NACCESSVALID(np, slot)) {
642 microuptime(&now);
643 if ((now.tv_sec < (np->n_accessstamp[slot] + nfs_access_cache_timeout)) &&
644 ((np->n_access[slot] & access) == access)) {
645 /* OSAddAtomic(1, &nfsstats.accesscache_hits); */
646 dorpc = 0;
647 waccess = np->n_access[slot];
648 }
649 }
650 nfs_node_unlock(np);
651 if (dorpc) {
652 /* Either a no, or a don't know. Go to the wire. */
653 /* OSAddAtomic(1, &nfsstats.accesscache_misses); */
654 error = nmp->nm_funcs->nf_access_rpc(np, &waccess, ctx);
655 }
656 if (!error && ((waccess & access) != access))
657 error = EACCES;
658
659 return (error);
660 }
661
662
663 /*
664 * NFS open vnode op
665 *
666 * Perform various update/invalidation checks and then add the
667 * open to the node. Regular files will have an open file structure
668 * on the node and, for NFSv4, perform an OPEN request on the server.
669 */
670 int
671 nfs_vnop_open(
672 struct vnop_open_args /* {
673 struct vnodeop_desc *a_desc;
674 vnode_t a_vp;
675 int a_mode;
676 vfs_context_t a_context;
677 } */ *ap)
678 {
679 vfs_context_t ctx = ap->a_context;
680 vnode_t vp = ap->a_vp;
681 nfsnode_t np = VTONFS(vp);
682 struct nfsmount *nmp;
683 int error, accessMode, denyMode, opened = 0;
684 struct nfs_open_owner *noop = NULL;
685 struct nfs_open_file *nofp = NULL;
686 enum vtype vtype;
687
688 if (!(ap->a_mode & (FREAD|FWRITE)))
689 return (EINVAL);
690
691 nmp = VTONMP(vp);
692 if (!nmp)
693 return (ENXIO);
694 if (np->n_flag & NREVOKE)
695 return (EIO);
696
697 vtype = vnode_vtype(vp);
698 if ((vtype != VREG) && (vtype != VDIR) && (vtype != VLNK))
699 return (EACCES);
700
701 /* First, check if we need to update/invalidate */
702 if (ISSET(np->n_flag, NUPDATESIZE))
703 nfs_data_update_size(np, 0);
704 if ((error = nfs_node_lock(np)))
705 return (error);
706 if (np->n_flag & NNEEDINVALIDATE) {
707 np->n_flag &= ~NNEEDINVALIDATE;
708 if (vtype == VDIR)
709 nfs_invaldir(np);
710 nfs_node_unlock(np);
711 nfs_vinvalbuf(vp, V_SAVE|V_IGNORE_WRITEERR, ctx, 1);
712 if ((error = nfs_node_lock(np)))
713 return (error);
714 }
715 if (vtype == VREG)
716 np->n_lastrahead = -1;
717 if (np->n_flag & NMODIFIED) {
718 if (vtype == VDIR)
719 nfs_invaldir(np);
720 nfs_node_unlock(np);
721 if ((error = nfs_vinvalbuf(vp, V_SAVE|V_IGNORE_WRITEERR, ctx, 1)))
722 return (error);
723 } else {
724 nfs_node_unlock(np);
725 }
726
727 /* nfs_getattr() will check changed and purge caches */
728 if ((error = nfs_getattr(np, NULL, ctx, NGA_UNCACHED)))
729 return (error);
730
731 if (vtype != VREG) {
732 /* Just mark that it was opened */
733 lck_mtx_lock(&np->n_openlock);
734 np->n_openrefcnt++;
735 lck_mtx_unlock(&np->n_openlock);
736 return (0);
737 }
738
739 /* mode contains some combination of: FREAD, FWRITE, O_SHLOCK, O_EXLOCK */
740 accessMode = 0;
741 if (ap->a_mode & FREAD)
742 accessMode |= NFS_OPEN_SHARE_ACCESS_READ;
743 if (ap->a_mode & FWRITE)
744 accessMode |= NFS_OPEN_SHARE_ACCESS_WRITE;
745 if (ap->a_mode & O_EXLOCK)
746 denyMode = NFS_OPEN_SHARE_DENY_BOTH;
747 else if (ap->a_mode & O_SHLOCK)
748 denyMode = NFS_OPEN_SHARE_DENY_WRITE;
749 else
750 denyMode = NFS_OPEN_SHARE_DENY_NONE;
751 // XXX don't do deny modes just yet (and never do it for !v4)
752 denyMode = NFS_OPEN_SHARE_DENY_NONE;
753
754 noop = nfs_open_owner_find(nmp, vfs_context_ucred(ctx), 1);
755 if (!noop)
756 return (ENOMEM);
757
758 restart:
759 error = nfs_mount_state_in_use_start(nmp, vfs_context_thread(ctx));
760 if (error) {
761 nfs_open_owner_rele(noop);
762 return (error);
763 }
764 if (np->n_flag & NREVOKE) {
765 error = EIO;
766 nfs_mount_state_in_use_end(nmp, 0);
767 nfs_open_owner_rele(noop);
768 return (error);
769 }
770
771 error = nfs_open_file_find(np, noop, &nofp, accessMode, denyMode, 1);
772 if (!error && (nofp->nof_flags & NFS_OPEN_FILE_LOST)) {
773 NP(np, "nfs_vnop_open: LOST %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
774 error = EIO;
775 }
776 if (!error && (nofp->nof_flags & NFS_OPEN_FILE_REOPEN)) {
777 nfs_mount_state_in_use_end(nmp, 0);
778 error = nfs4_reopen(nofp, vfs_context_thread(ctx));
779 nofp = NULL;
780 if (!error)
781 goto restart;
782 }
783 if (!error)
784 error = nfs_open_file_set_busy(nofp, vfs_context_thread(ctx));
785 if (error) {
786 nofp = NULL;
787 goto out;
788 }
789
790 if (nmp->nm_vers < NFS_VER4) {
791 /*
792 * NFS v2/v3 opens are always allowed - so just add it.
793 */
794 nfs_open_file_add_open(nofp, accessMode, denyMode, 0);
795 goto out;
796 }
797
798 /*
799 * If we just created the file and the modes match, then we simply use
800 * the open performed in the create. Otherwise, send the request.
801 */
802 if ((nofp->nof_flags & NFS_OPEN_FILE_CREATE) &&
803 (nofp->nof_creator == current_thread()) &&
804 (accessMode == NFS_OPEN_SHARE_ACCESS_BOTH) &&
805 (denyMode == NFS_OPEN_SHARE_DENY_NONE)) {
806 nofp->nof_flags &= ~NFS_OPEN_FILE_CREATE;
807 nofp->nof_creator = NULL;
808 } else {
809 if (!opened)
810 error = nfs4_open(np, nofp, accessMode, denyMode, ctx);
811 if ((error == EACCES) && (nofp->nof_flags & NFS_OPEN_FILE_CREATE) &&
812 (nofp->nof_creator == current_thread())) {
813 /*
814 * Ugh. This can happen if we just created the file with read-only
815 * perms and we're trying to open it for real with different modes
816 * (e.g. write-only or with a deny mode) and the server decides to
817 * not allow the second open because of the read-only perms.
818 * The best we can do is to just use the create's open.
819 * We may have access we don't need or we may not have a requested
820 * deny mode. We may log complaints later, but we'll try to avoid it.
821 */
822 if (denyMode != NFS_OPEN_SHARE_DENY_NONE)
823 NP(np, "nfs_vnop_open: deny mode foregone on create, %d", kauth_cred_getuid(nofp->nof_owner->noo_cred));
824 nofp->nof_creator = NULL;
825 error = 0;
826 }
827 if (error)
828 goto out;
829 opened = 1;
830 /*
831 * If we had just created the file, we already had it open.
832 * If the actual open mode is less than what we grabbed at
833 * create time, then we'll downgrade the open here.
834 */
835 if ((nofp->nof_flags & NFS_OPEN_FILE_CREATE) &&
836 (nofp->nof_creator == current_thread())) {
837 error = nfs_close(np, nofp, NFS_OPEN_SHARE_ACCESS_BOTH, NFS_OPEN_SHARE_DENY_NONE, ctx);
838 if (error)
839 NP(np, "nfs_vnop_open: create close error %d, %d", error, kauth_cred_getuid(nofp->nof_owner->noo_cred));
840 if (!nfs_mount_state_error_should_restart(error)) {
841 error = 0;
842 nofp->nof_flags &= ~NFS_OPEN_FILE_CREATE;
843 }
844 }
845 }
846
847 out:
848 if (nofp)
849 nfs_open_file_clear_busy(nofp);
850 if (nfs_mount_state_in_use_end(nmp, error)) {
851 nofp = NULL;
852 goto restart;
853 }
854 if (error)
855 NP(np, "nfs_vnop_open: error %d, %d", error, kauth_cred_getuid(noop->noo_cred));
856 if (noop)
857 nfs_open_owner_rele(noop);
858 return (error);
859 }
860
861
862 /*
863 * NFS close vnode op
864 *
865 * What an NFS client should do upon close after writing is a debatable issue.
866 * Most NFS clients push delayed writes to the server upon close, basically for
867 * two reasons:
868 * 1 - So that any write errors may be reported back to the client process
869 * doing the close system call. By far the two most likely errors are
870 * NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure.
871 * 2 - To put a worst case upper bound on cache inconsistency between
872 * multiple clients for the file.
873 * There is also a consistency problem for Version 2 of the protocol w.r.t.
874 * not being able to tell if other clients are writing a file concurrently,
875 * since there is no way of knowing if the changed modify time in the reply
876 * is only due to the write for this client.
877 * (NFS Version 3 provides weak cache consistency data in the reply that
878 * should be sufficient to detect and handle this case.)
879 *
880 * The current code does the following:
881 * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
882 * for NFS Version 3 - flush dirty buffers to the server but don't invalidate them.
883 * for NFS Version 4 - basically the same as NFSv3
884 */
885 int
886 nfs_vnop_close(
887 struct vnop_close_args /* {
888 struct vnodeop_desc *a_desc;
889 vnode_t a_vp;
890 int a_fflag;
891 vfs_context_t a_context;
892 } */ *ap)
893 {
894 vfs_context_t ctx = ap->a_context;
895 vnode_t vp = ap->a_vp;
896 nfsnode_t np = VTONFS(vp);
897 struct nfsmount *nmp;
898 int error = 0, error1, nfsvers;
899 int fflag = ap->a_fflag;
900 enum vtype vtype;
901 int accessMode, denyMode;
902 struct nfs_open_owner *noop = NULL;
903 struct nfs_open_file *nofp = NULL;
904
905 nmp = VTONMP(vp);
906 if (!nmp)
907 return (ENXIO);
908 nfsvers = nmp->nm_vers;
909 vtype = vnode_vtype(vp);
910
911 /* First, check if we need to update/flush/invalidate */
912 if (ISSET(np->n_flag, NUPDATESIZE))
913 nfs_data_update_size(np, 0);
914 nfs_node_lock_force(np);
915 if (np->n_flag & NNEEDINVALIDATE) {
916 np->n_flag &= ~NNEEDINVALIDATE;
917 nfs_node_unlock(np);
918 nfs_vinvalbuf(vp, V_SAVE|V_IGNORE_WRITEERR, ctx, 1);
919 nfs_node_lock_force(np);
920 }
921 if ((vtype == VREG) && (np->n_flag & NMODIFIED) && (fflag & FWRITE)) {
922 /* we're closing an open for write and the file is modified, so flush it */
923 nfs_node_unlock(np);
924 if (nfsvers != NFS_VER2)
925 error = nfs_flush(np, MNT_WAIT, vfs_context_thread(ctx), 0);
926 else
927 error = nfs_vinvalbuf(vp, V_SAVE, ctx, 1);
928 nfs_node_lock_force(np);
929 NATTRINVALIDATE(np);
930 }
931 if (np->n_flag & NWRITEERR) {
932 np->n_flag &= ~NWRITEERR;
933 error = np->n_error;
934 }
935 nfs_node_unlock(np);
936
937 if (vtype != VREG) {
938 /* Just mark that it was closed */
939 lck_mtx_lock(&np->n_openlock);
940 if (np->n_openrefcnt == 0) {
941 if (fflag & (FREAD|FWRITE)) {
942 NP(np, "nfs_vnop_close: open reference underrun");
943 error = EINVAL;
944 }
945 } else if (fflag & (FREAD|FWRITE)) {
946 np->n_openrefcnt--;
947 } else {
948 /* No FREAD/FWRITE set - probably the final close */
949 np->n_openrefcnt = 0;
950 }
951 lck_mtx_unlock(&np->n_openlock);
952 return (error);
953 }
954 error1 = error;
955
956 /* fflag should contain some combination of: FREAD, FWRITE, FHASLOCK */
957 accessMode = 0;
958 if (fflag & FREAD)
959 accessMode |= NFS_OPEN_SHARE_ACCESS_READ;
960 if (fflag & FWRITE)
961 accessMode |= NFS_OPEN_SHARE_ACCESS_WRITE;
962 // XXX It would be nice if we still had the O_EXLOCK/O_SHLOCK flags that were on the open
963 // if (fflag & O_EXLOCK)
964 // denyMode = NFS_OPEN_SHARE_DENY_BOTH;
965 // else if (fflag & O_SHLOCK)
966 // denyMode = NFS_OPEN_SHARE_DENY_WRITE;
967 // else
968 // denyMode = NFS_OPEN_SHARE_DENY_NONE;
969 #if 0 // Not yet
970 if (fflag & FHASLOCK) {
971 /* XXX assume FHASLOCK is for the deny mode and not flock */
972 /* FHASLOCK flock will be unlocked in the close path, but the flag is not cleared. */
973 if (nofp->nof_deny & NFS_OPEN_SHARE_DENY_READ)
974 denyMode = NFS_OPEN_SHARE_DENY_BOTH;
975 else if (nofp->nof_deny & NFS_OPEN_SHARE_DENY_WRITE)
976 denyMode = NFS_OPEN_SHARE_DENY_WRITE;
977 else
978 denyMode = NFS_OPEN_SHARE_DENY_NONE;
979 } else {
980 denyMode = NFS_OPEN_SHARE_DENY_NONE;
981 }
982 #else
983 // XXX don't do deny modes just yet (and never do it for !v4)
984 denyMode = NFS_OPEN_SHARE_DENY_NONE;
985 #endif
986
987 if (!accessMode) {
988 /*
989 * No mode given to close?
990 * Guess this is the final close.
991 * We should unlock all locks and close all opens.
992 */
993 mount_t mp = vnode_mount(vp);
994 int force = (!mp || (mp->mnt_kern_flag & MNTK_FRCUNMOUNT));
995 nfs_release_open_state_for_node(np, force);
996 return (error);
997 }
998
999 noop = nfs_open_owner_find(nmp, vfs_context_ucred(ctx), 0);
1000 if (!noop) {
1001 // printf("nfs_vnop_close: can't get open owner!\n");
1002 return (EIO);
1003 }
1004
1005 restart:
1006 error = nfs_mount_state_in_use_start(nmp, NULL);
1007 if (error) {
1008 nfs_open_owner_rele(noop);
1009 return (error);
1010 }
1011
1012 error = nfs_open_file_find(np, noop, &nofp, 0, 0, 0);
1013 if (!error && (nofp->nof_flags & NFS_OPEN_FILE_REOPEN)) {
1014 nfs_mount_state_in_use_end(nmp, 0);
1015 error = nfs4_reopen(nofp, NULL);
1016 nofp = NULL;
1017 if (!error)
1018 goto restart;
1019 }
1020 if (error) {
1021 NP(np, "nfs_vnop_close: no open file for owner, error %d, %d", error, kauth_cred_getuid(noop->noo_cred));
1022 error = EBADF;
1023 goto out;
1024 }
1025 error = nfs_open_file_set_busy(nofp, NULL);
1026 if (error) {
1027 nofp = NULL;
1028 goto out;
1029 }
1030
1031 error = nfs_close(np, nofp, accessMode, denyMode, ctx);
1032 if (error)
1033 NP(np, "nfs_vnop_close: close error %d, %d", error, kauth_cred_getuid(noop->noo_cred));
1034
1035 out:
1036 if (nofp)
1037 nfs_open_file_clear_busy(nofp);
1038 if (nfs_mount_state_in_use_end(nmp, error)) {
1039 nofp = NULL;
1040 goto restart;
1041 }
1042 if (!error)
1043 error = error1;
1044 if (error)
1045 NP(np, "nfs_vnop_close: error %d, %d", error, kauth_cred_getuid(noop->noo_cred));
1046 if (noop)
1047 nfs_open_owner_rele(noop);
1048 return (error);
1049 }
1050
1051 /*
1052 * nfs_close(): common function that does all the heavy lifting of file closure
1053 *
1054 * Takes an open file structure and a set of access/deny modes and figures out how
1055 * to update the open file structure (and the state on the server) appropriately.
1056 */
1057 int
1058 nfs_close(
1059 nfsnode_t np,
1060 struct nfs_open_file *nofp,
1061 uint32_t accessMode,
1062 uint32_t denyMode,
1063 vfs_context_t ctx)
1064 {
1065 struct nfs_lock_owner *nlop;
1066 int error = 0, changed = 0, delegated = 0, closed = 0, downgrade = 0;
1067 uint32_t newAccessMode, newDenyMode;
1068
1069 /* warn if modes don't match current state */
1070 if (((accessMode & nofp->nof_access) != accessMode) || ((denyMode & nofp->nof_deny) != denyMode))
1071 NP(np, "nfs_close: mode mismatch %d %d, current %d %d, %d",
1072 accessMode, denyMode, nofp->nof_access, nofp->nof_deny,
1073 kauth_cred_getuid(nofp->nof_owner->noo_cred));
1074
1075 /*
1076 * If we're closing a write-only open, we may not have a write-only count
1077 * if we also grabbed read access. So, check the read-write count.
1078 */
1079 if (denyMode == NFS_OPEN_SHARE_DENY_NONE) {
1080 if ((accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) &&
1081 (nofp->nof_w == 0) && (nofp->nof_d_w == 0) &&
1082 (nofp->nof_rw || nofp->nof_d_rw))
1083 accessMode = NFS_OPEN_SHARE_ACCESS_BOTH;
1084 } else if (denyMode == NFS_OPEN_SHARE_DENY_WRITE) {
1085 if ((accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) &&
1086 (nofp->nof_w_dw == 0) && (nofp->nof_d_w_dw == 0) &&
1087 (nofp->nof_rw_dw || nofp->nof_d_rw_dw))
1088 accessMode = NFS_OPEN_SHARE_ACCESS_BOTH;
1089 } else { /* NFS_OPEN_SHARE_DENY_BOTH */
1090 if ((accessMode == NFS_OPEN_SHARE_ACCESS_WRITE) &&
1091 (nofp->nof_w_drw == 0) && (nofp->nof_d_w_drw == 0) &&
1092 (nofp->nof_rw_drw || nofp->nof_d_rw_drw))
1093 accessMode = NFS_OPEN_SHARE_ACCESS_BOTH;
1094 }
1095
1096 nfs_open_file_remove_open_find(nofp, accessMode, denyMode, &newAccessMode, &newDenyMode, &delegated);
1097 if ((newAccessMode != nofp->nof_access) || (newDenyMode != nofp->nof_deny))
1098 changed = 1;
1099 else
1100 changed = 0;
1101
1102 if (NFSTONMP(np)->nm_vers < NFS_VER4) /* NFS v2/v3 closes simply need to remove the open. */
1103 goto v3close;
1104
1105 if ((newAccessMode == 0) || (nofp->nof_opencnt == 1)) {
1106 /*
1107 * No more access after this close, so clean up and close it.
1108 * Don't send a close RPC if we're closing a delegated open.
1109 */
1110 nfs_wait_bufs(np);
1111 closed = 1;
1112 if (!delegated && !(nofp->nof_flags & NFS_OPEN_FILE_LOST))
1113 error = nfs4_close_rpc(np, nofp, vfs_context_thread(ctx), vfs_context_ucred(ctx), 0);
1114 if (error == NFSERR_LOCKS_HELD) {
1115 /*
1116 * Hmm... the server says we have locks we need to release first
1117 * Find the lock owner and try to unlock everything.
1118 */
1119 nlop = nfs_lock_owner_find(np, vfs_context_proc(ctx), 0);
1120 if (nlop) {
1121 nfs4_unlock_rpc(np, nlop, F_WRLCK, 0, UINT64_MAX,
1122 0, vfs_context_thread(ctx), vfs_context_ucred(ctx));
1123 nfs_lock_owner_rele(nlop);
1124 }
1125 error = nfs4_close_rpc(np, nofp, vfs_context_thread(ctx), vfs_context_ucred(ctx), 0);
1126 }
1127 } else if (changed) {
1128 /*
1129 * File is still open but with less access, so downgrade the open.
1130 * Don't send a downgrade RPC if we're closing a delegated open.
1131 */
1132 if (!delegated && !(nofp->nof_flags & NFS_OPEN_FILE_LOST)) {
1133 downgrade = 1;
1134 /*
1135 * If we have delegated opens, we should probably claim them before sending
1136 * the downgrade because the server may not know the open we are downgrading to.
1137 */
1138 if (nofp->nof_d_rw_drw || nofp->nof_d_w_drw || nofp->nof_d_r_drw ||
1139 nofp->nof_d_rw_dw || nofp->nof_d_w_dw || nofp->nof_d_r_dw ||
1140 nofp->nof_d_rw || nofp->nof_d_w || nofp->nof_d_r)
1141 nfs4_claim_delegated_state_for_open_file(nofp, 0);
1142 /* need to remove the open before sending the downgrade */
1143 nfs_open_file_remove_open(nofp, accessMode, denyMode);
1144 error = nfs4_open_downgrade_rpc(np, nofp, ctx);
1145 if (error) /* Hmm.. that didn't work. Add the open back in. */
1146 nfs_open_file_add_open(nofp, accessMode, denyMode, delegated);
1147 }
1148 }
1149
1150 if (error) {
1151 NP(np, "nfs_close: error %d, %d", error, kauth_cred_getuid(nofp->nof_owner->noo_cred));
1152 return (error);
1153 }
1154
1155 v3close:
1156 if (!downgrade)
1157 nfs_open_file_remove_open(nofp, accessMode, denyMode);
1158
1159 if (closed) {
1160 lck_mtx_lock(&nofp->nof_lock);
1161 if (nofp->nof_r || nofp->nof_d_r || nofp->nof_w || nofp->nof_d_w || nofp->nof_d_rw ||
1162 (nofp->nof_rw && !((nofp->nof_flags & NFS_OPEN_FILE_CREATE) && !nofp->nof_creator && (nofp->nof_rw == 1))) ||
1163 nofp->nof_r_dw || nofp->nof_d_r_dw || nofp->nof_w_dw || nofp->nof_d_w_dw ||
1164 nofp->nof_rw_dw || nofp->nof_d_rw_dw || nofp->nof_r_drw || nofp->nof_d_r_drw ||
1165 nofp->nof_w_drw || nofp->nof_d_w_drw || nofp->nof_rw_drw || nofp->nof_d_rw_drw)
1166 NP(np, "nfs_close: unexpected count: %u.%u %u.%u %u.%u dw %u.%u %u.%u %u.%u drw %u.%u %u.%u %u.%u flags 0x%x, %d",
1167 nofp->nof_r, nofp->nof_d_r, nofp->nof_w, nofp->nof_d_w,
1168 nofp->nof_rw, nofp->nof_d_rw, nofp->nof_r_dw, nofp->nof_d_r_dw,
1169 nofp->nof_w_dw, nofp->nof_d_w_dw, nofp->nof_rw_dw, nofp->nof_d_rw_dw,
1170 nofp->nof_r_drw, nofp->nof_d_r_drw, nofp->nof_w_drw, nofp->nof_d_w_drw,
1171 nofp->nof_rw_drw, nofp->nof_d_rw_drw, nofp->nof_flags,
1172 kauth_cred_getuid(nofp->nof_owner->noo_cred));
1173 /* clear out all open info, just to be safe */
1174 nofp->nof_access = nofp->nof_deny = 0;
1175 nofp->nof_mmap_access = nofp->nof_mmap_deny = 0;
1176 nofp->nof_r = nofp->nof_d_r = 0;
1177 nofp->nof_w = nofp->nof_d_w = 0;
1178 nofp->nof_rw = nofp->nof_d_rw = 0;
1179 nofp->nof_r_dw = nofp->nof_d_r_dw = 0;
1180 nofp->nof_w_dw = nofp->nof_d_w_dw = 0;
1181 nofp->nof_rw_dw = nofp->nof_d_rw_dw = 0;
1182 nofp->nof_r_drw = nofp->nof_d_r_drw = 0;
1183 nofp->nof_w_drw = nofp->nof_d_w_drw = 0;
1184 nofp->nof_rw_drw = nofp->nof_d_rw_drw = 0;
1185 nofp->nof_flags &= ~NFS_OPEN_FILE_CREATE;
1186 lck_mtx_unlock(&nofp->nof_lock);
1187 /* XXX we may potentially want to clean up idle/unused open file structures */
1188 }
1189 if (nofp->nof_flags & NFS_OPEN_FILE_LOST) {
1190 error = EIO;
1191 NP(np, "nfs_close: LOST%s, %d", !nofp->nof_opencnt ? " (last)" : "",
1192 kauth_cred_getuid(nofp->nof_owner->noo_cred));
1193 }
1194 return (error);
1195 }
1196
1197
1198
1199
1200 int
1201 nfs3_getattr_rpc(
1202 nfsnode_t np,
1203 mount_t mp,
1204 u_char *fhp,
1205 size_t fhsize,
1206 int flags,
1207 vfs_context_t ctx,
1208 struct nfs_vattr *nvap,
1209 u_int64_t *xidp)
1210 {
1211 struct nfsmount *nmp = mp ? VFSTONFS(mp) : NFSTONMP(np);
1212 int error = 0, status, nfsvers, rpcflags = 0;
1213 struct nfsm_chain nmreq, nmrep;
1214
1215 if (!nmp)
1216 return (ENXIO);
1217 nfsvers = nmp->nm_vers;
1218
1219 if (flags & NGA_MONITOR) /* vnode monitor requests should be soft */
1220 rpcflags = R_RECOVER;
1221
1222 nfsm_chain_null(&nmreq);
1223 nfsm_chain_null(&nmrep);
1224
1225 nfsm_chain_build_alloc_init(error, &nmreq, NFSX_FH(nfsvers));
1226 if (nfsvers != NFS_VER2)
1227 nfsm_chain_add_32(error, &nmreq, fhsize);
1228 nfsm_chain_add_opaque(error, &nmreq, fhp, fhsize);
1229 nfsm_chain_build_done(error, &nmreq);
1230 nfsmout_if(error);
1231 error = nfs_request2(np, mp, &nmreq, NFSPROC_GETATTR,
1232 vfs_context_thread(ctx), vfs_context_ucred(ctx),
1233 NULL, rpcflags, &nmrep, xidp, &status);
1234 if (!error)
1235 error = status;
1236 nfsmout_if(error);
1237 error = nfs_parsefattr(&nmrep, nfsvers, nvap);
1238 nfsmout:
1239 nfsm_chain_cleanup(&nmreq);
1240 nfsm_chain_cleanup(&nmrep);
1241 return (error);
1242 }
1243
1244
1245 int
1246 nfs_getattr(nfsnode_t np, struct nfs_vattr *nvap, vfs_context_t ctx, int flags)
1247 {
1248 struct nfsmount *nmp;
1249 int error = 0, nfsvers, inprogset = 0, wanted = 0, avoidfloods;
1250 struct nfs_vattr nvattr;
1251 struct timespec ts = { 2, 0 };
1252 u_int64_t xid;
1253
1254 FSDBG_TOP(513, np->n_size, np, np->n_vattr.nva_size, np->n_flag);
1255
1256 if (!(nmp = NFSTONMP(np)))
1257 return (ENXIO);
1258 nfsvers = nmp->nm_vers;
1259
1260 if (!nvap)
1261 nvap = &nvattr;
1262 NVATTR_INIT(nvap);
1263
1264 /* Update local times for special files. */
1265 if (np->n_flag & (NACC | NUPD)) {
1266 nfs_node_lock_force(np);
1267 np->n_flag |= NCHG;
1268 nfs_node_unlock(np);
1269 }
1270 /* Update size, if necessary */
1271 if (ISSET(np->n_flag, NUPDATESIZE))
1272 nfs_data_update_size(np, 0);
1273
1274 error = nfs_node_lock(np);
1275 nfsmout_if(error);
1276 if (!(flags & (NGA_UNCACHED|NGA_MONITOR)) || ((nfsvers >= NFS_VER4) && (np->n_openflags & N_DELEG_MASK))) {
1277 /*
1278 * Use the cache or wait for any getattr in progress if:
1279 * - it's a cached request, or
1280 * - we have a delegation
1281 */
1282 while (1) {
1283 error = nfs_getattrcache(np, nvap, flags);
1284 if (!error || (error != ENOENT)) {
1285 nfs_node_unlock(np);
1286 goto nfsmout;
1287 }
1288 error = 0;
1289 if (!ISSET(np->n_flag, NGETATTRINPROG))
1290 break;
1291 if (flags & NGA_MONITOR) {
1292 /* no need to wait if a request is pending */
1293 error = EINPROGRESS;
1294 nfs_node_unlock(np);
1295 goto nfsmout;
1296 }
1297 SET(np->n_flag, NGETATTRWANT);
1298 msleep(np, &np->n_lock, PZERO-1, "nfsgetattrwant", &ts);
1299 if ((error = nfs_sigintr(NFSTONMP(np), NULL, vfs_context_thread(ctx), 0))) {
1300 nfs_node_unlock(np);
1301 goto nfsmout;
1302 }
1303 }
1304 SET(np->n_flag, NGETATTRINPROG);
1305 inprogset = 1;
1306 } else if (!ISSET(np->n_flag, NGETATTRINPROG)) {
1307 SET(np->n_flag, NGETATTRINPROG);
1308 inprogset = 1;
1309 } else if (flags & NGA_MONITOR) {
1310 /* no need to make a request if one is pending */
1311 error = EINPROGRESS;
1312 }
1313 nfs_node_unlock(np);
1314
1315 nmp = NFSTONMP(np);
1316 if (!nmp)
1317 error = ENXIO;
1318 if (error)
1319 goto nfsmout;
1320
1321 /*
1322 * We might want to try to get both the attributes and access info by
1323 * making an ACCESS call and seeing if it returns updated attributes.
1324 * But don't bother if we aren't caching access info or if the
1325 * attributes returned wouldn't be cached.
1326 */
1327 if (!(flags & NGA_ACL) && (nfsvers != NFS_VER2) && nfs_access_for_getattr && (nfs_access_cache_timeout > 0)) {
1328 if (nfs_attrcachetimeout(np) > 0) {
1329 /* OSAddAtomic(1, &nfsstats.accesscache_misses); */
1330 u_int32_t access = NFS_ACCESS_ALL;
1331 error = nmp->nm_funcs->nf_access_rpc(np, &access, ctx);
1332 if (error)
1333 goto nfsmout;
1334 nfs_node_lock_force(np);
1335 error = nfs_getattrcache(np, nvap, flags);
1336 nfs_node_unlock(np);
1337 if (!error || (error != ENOENT))
1338 goto nfsmout;
1339 /* Well, that didn't work... just do a getattr... */
1340 error = 0;
1341 }
1342 }
1343
1344 avoidfloods = 0;
1345 tryagain:
1346 error = nmp->nm_funcs->nf_getattr_rpc(np, NULL, np->n_fhp, np->n_fhsize, flags, ctx, nvap, &xid);
1347 if (!error) {
1348 nfs_node_lock_force(np);
1349 error = nfs_loadattrcache(np, nvap, &xid, 0);
1350 nfs_node_unlock(np);
1351 }
1352 nfsmout_if(error);
1353 if (!xid) { /* out-of-order rpc - attributes were dropped */
1354 FSDBG(513, -1, np, np->n_xid >> 32, np->n_xid);
1355 if (avoidfloods++ < 20)
1356 goto tryagain;
1357 /* avoidfloods>1 is bizarre. at 20 pull the plug */
1358 /* just return the last attributes we got */
1359 }
1360 nfsmout:
1361 nfs_node_lock_force(np);
1362 if (inprogset) {
1363 wanted = ISSET(np->n_flag, NGETATTRWANT);
1364 CLR(np->n_flag, (NGETATTRINPROG | NGETATTRWANT));
1365 }
1366 if (!error) {
1367 /* check if the node changed on us */
1368 vnode_t vp = NFSTOV(np);
1369 enum vtype vtype = vnode_vtype(vp);
1370 if ((vtype == VDIR) && NFS_CHANGED_NC(nfsvers, np, nvap)) {
1371 FSDBG(513, -1, np, 0, np);
1372 np->n_flag &= ~NNEGNCENTRIES;
1373 cache_purge(vp);
1374 np->n_ncgen++;
1375 NFS_CHANGED_UPDATE_NC(nfsvers, np, nvap);
1376 }
1377 if (NFS_CHANGED(nfsvers, np, nvap)) {
1378 FSDBG(513, -1, np, -1, np);
1379 if (vtype == VDIR)
1380 nfs_invaldir(np);
1381 nfs_node_unlock(np);
1382 if (wanted)
1383 wakeup(np);
1384 error = nfs_vinvalbuf(vp, V_SAVE, ctx, 1);
1385 FSDBG(513, -1, np, -2, error);
1386 if (!error) {
1387 nfs_node_lock_force(np);
1388 NFS_CHANGED_UPDATE(nfsvers, np, nvap);
1389 nfs_node_unlock(np);
1390 }
1391 } else {
1392 nfs_node_unlock(np);
1393 if (wanted)
1394 wakeup(np);
1395 }
1396 } else {
1397 nfs_node_unlock(np);
1398 if (wanted)
1399 wakeup(np);
1400 }
1401
1402 if (nvap == &nvattr) {
1403 NVATTR_CLEANUP(nvap);
1404 } else if (!(flags & NGA_ACL)) {
1405 /* make sure we don't return an ACL if it wasn't asked for */
1406 NFS_BITMAP_CLR(nvap->nva_bitmap, NFS_FATTR_ACL);
1407 if (nvap->nva_acl) {
1408 kauth_acl_free(nvap->nva_acl);
1409 nvap->nva_acl = NULL;
1410 }
1411 }
1412 FSDBG_BOT(513, np->n_size, error, np->n_vattr.nva_size, np->n_flag);
1413 return (error);
1414 }
1415
1416 /*
1417 * NFS getattr call from vfs.
1418 */
1419 int
1420 nfs3_vnop_getattr(
1421 struct vnop_getattr_args /* {
1422 struct vnodeop_desc *a_desc;
1423 vnode_t a_vp;
1424 struct vnode_attr *a_vap;
1425 vfs_context_t a_context;
1426 } */ *ap)
1427 {
1428 int error;
1429 struct nfs_vattr nva;
1430 struct vnode_attr *vap = ap->a_vap;
1431 dev_t rdev;
1432
1433 error = nfs_getattr(VTONFS(ap->a_vp), &nva, ap->a_context, NGA_CACHED);
1434 if (error)
1435 return (error);
1436
1437 /* copy nva to *a_vap */
1438 VATTR_RETURN(vap, va_type, nva.nva_type);
1439 VATTR_RETURN(vap, va_mode, nva.nva_mode);
1440 rdev = makedev(nva.nva_rawdev.specdata1, nva.nva_rawdev.specdata2);
1441 VATTR_RETURN(vap, va_rdev, rdev);
1442 VATTR_RETURN(vap, va_uid, nva.nva_uid);
1443 VATTR_RETURN(vap, va_gid, nva.nva_gid);
1444 VATTR_RETURN(vap, va_nlink, nva.nva_nlink);
1445 VATTR_RETURN(vap, va_fileid, nva.nva_fileid);
1446 VATTR_RETURN(vap, va_data_size, nva.nva_size);
1447 VATTR_RETURN(vap, va_data_alloc, nva.nva_bytes);
1448 VATTR_RETURN(vap, va_iosize, nfs_iosize);
1449 vap->va_access_time.tv_sec = nva.nva_timesec[NFSTIME_ACCESS];
1450 vap->va_access_time.tv_nsec = nva.nva_timensec[NFSTIME_ACCESS];
1451 VATTR_SET_SUPPORTED(vap, va_access_time);
1452 vap->va_modify_time.tv_sec = nva.nva_timesec[NFSTIME_MODIFY];
1453 vap->va_modify_time.tv_nsec = nva.nva_timensec[NFSTIME_MODIFY];
1454 VATTR_SET_SUPPORTED(vap, va_modify_time);
1455 vap->va_change_time.tv_sec = nva.nva_timesec[NFSTIME_CHANGE];
1456 vap->va_change_time.tv_nsec = nva.nva_timensec[NFSTIME_CHANGE];
1457 VATTR_SET_SUPPORTED(vap, va_change_time);
1458
1459 // VATTR_RETURN(vap, va_encoding, 0xffff /* kTextEncodingUnknown */);
1460 return (error);
1461 }
1462
1463 /*
1464 * NFS setattr call.
1465 */
1466 int
1467 nfs_vnop_setattr(
1468 struct vnop_setattr_args /* {
1469 struct vnodeop_desc *a_desc;
1470 vnode_t a_vp;
1471 struct vnode_attr *a_vap;
1472 vfs_context_t a_context;
1473 } */ *ap)
1474 {
1475 vfs_context_t ctx = ap->a_context;
1476 vnode_t vp = ap->a_vp;
1477 nfsnode_t np = VTONFS(vp);
1478 struct nfsmount *nmp;
1479 struct vnode_attr *vap = ap->a_vap;
1480 int error = 0;
1481 int biosize, nfsvers, namedattrs;
1482 u_quad_t origsize, vapsize;
1483 struct nfs_dulookup dul;
1484 nfsnode_t dnp = NULL;
1485 vnode_t dvp = NULL;
1486 const char *vname = NULL;
1487 struct nfs_open_owner *noop = NULL;
1488 struct nfs_open_file *nofp = NULL;
1489
1490 nmp = VTONMP(vp);
1491 if (!nmp)
1492 return (ENXIO);
1493 nfsvers = nmp->nm_vers;
1494 namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR);
1495 biosize = nmp->nm_biosize;
1496
1497 /* Disallow write attempts if the filesystem is mounted read-only. */
1498 if (vnode_vfsisrdonly(vp))
1499 return (EROFS);
1500
1501 origsize = np->n_size;
1502 if (VATTR_IS_ACTIVE(vap, va_data_size)) {
1503 switch (vnode_vtype(vp)) {
1504 case VDIR:
1505 return (EISDIR);
1506 case VCHR:
1507 case VBLK:
1508 case VSOCK:
1509 case VFIFO:
1510 if (!VATTR_IS_ACTIVE(vap, va_modify_time) &&
1511 !VATTR_IS_ACTIVE(vap, va_access_time) &&
1512 !VATTR_IS_ACTIVE(vap, va_mode) &&
1513 !VATTR_IS_ACTIVE(vap, va_uid) &&
1514 !VATTR_IS_ACTIVE(vap, va_gid)) {
1515 return (0);
1516 }
1517 VATTR_CLEAR_ACTIVE(vap, va_data_size);
1518 break;
1519 default:
1520 /*
1521 * Disallow write attempts if the filesystem is
1522 * mounted read-only.
1523 */
1524 if (vnode_vfsisrdonly(vp))
1525 return (EROFS);
1526 FSDBG_TOP(512, np->n_size, vap->va_data_size,
1527 np->n_vattr.nva_size, np->n_flag);
1528 /* clear NNEEDINVALIDATE, if set */
1529 if ((error = nfs_node_lock(np)))
1530 return (error);
1531 if (np->n_flag & NNEEDINVALIDATE)
1532 np->n_flag &= ~NNEEDINVALIDATE;
1533 nfs_node_unlock(np);
1534 /* flush everything */
1535 error = nfs_vinvalbuf(vp, (vap->va_data_size ? V_SAVE : 0) , ctx, 1);
1536 if (error) {
1537 NP(np, "nfs_setattr: nfs_vinvalbuf %d", error);
1538 FSDBG_BOT(512, np->n_size, vap->va_data_size, np->n_vattr.nva_size, -1);
1539 return (error);
1540 }
1541 if (nfsvers >= NFS_VER4) {
1542 /* setting file size requires having the file open for write access */
1543 if (np->n_flag & NREVOKE)
1544 return (EIO);
1545 noop = nfs_open_owner_find(nmp, vfs_context_ucred(ctx), 1);
1546 if (!noop)
1547 return (ENOMEM);
1548 restart:
1549 error = nfs_mount_state_in_use_start(nmp, vfs_context_thread(ctx));
1550 if (error)
1551 return (error);
1552 if (np->n_flag & NREVOKE) {
1553 nfs_mount_state_in_use_end(nmp, 0);
1554 return (EIO);
1555 }
1556 error = nfs_open_file_find(np, noop, &nofp, 0, 0, 1);
1557 if (!error && (nofp->nof_flags & NFS_OPEN_FILE_LOST))
1558 error = EIO;
1559 if (!error && (nofp->nof_flags & NFS_OPEN_FILE_REOPEN)) {
1560 nfs_mount_state_in_use_end(nmp, 0);
1561 error = nfs4_reopen(nofp, vfs_context_thread(ctx));
1562 nofp = NULL;
1563 if (!error)
1564 goto restart;
1565 }
1566 if (!error)
1567 error = nfs_open_file_set_busy(nofp, vfs_context_thread(ctx));
1568 if (error) {
1569 nfs_open_owner_rele(noop);
1570 return (error);
1571 }
1572 if (!(nofp->nof_access & NFS_OPEN_SHARE_ACCESS_WRITE)) {
1573 /* we don't have the file open for write access, so open it */
1574 error = nfs4_open(np, nofp, NFS_OPEN_SHARE_ACCESS_WRITE, NFS_OPEN_SHARE_DENY_NONE, ctx);
1575 if (!error)
1576 nofp->nof_flags |= NFS_OPEN_FILE_SETATTR;
1577 if (nfs_mount_state_error_should_restart(error)) {
1578 nfs_open_file_clear_busy(nofp);
1579 nofp = NULL;
1580 if (nfs_mount_state_in_use_end(nmp, error))
1581 goto restart;
1582 }
1583 }
1584 }
1585 nfs_data_lock(np, NFS_DATA_LOCK_EXCLUSIVE);
1586 if (np->n_size > vap->va_data_size) { /* shrinking? */
1587 daddr64_t obn, bn;
1588 int neweofoff, mustwrite;
1589 struct nfsbuf *bp;
1590
1591 obn = (np->n_size - 1) / biosize;
1592 bn = vap->va_data_size / biosize;
1593 for ( ; obn >= bn; obn--) {
1594 if (!nfs_buf_is_incore(np, obn))
1595 continue;
1596 error = nfs_buf_get(np, obn, biosize, NULL, NBLK_READ, &bp);
1597 if (error)
1598 continue;
1599 if (obn != bn) {
1600 FSDBG(512, bp, bp->nb_flags, 0, obn);
1601 SET(bp->nb_flags, NB_INVAL);
1602 nfs_buf_release(bp, 1);
1603 continue;
1604 }
1605 mustwrite = 0;
1606 neweofoff = vap->va_data_size - NBOFF(bp);
1607 /* check for any dirty data before the new EOF */
1608 if ((bp->nb_dirtyend > 0) && (bp->nb_dirtyoff < neweofoff)) {
1609 /* clip dirty range to EOF */
1610 if (bp->nb_dirtyend > neweofoff) {
1611 bp->nb_dirtyend = neweofoff;
1612 if (bp->nb_dirtyoff >= bp->nb_dirtyend)
1613 bp->nb_dirtyoff = bp->nb_dirtyend = 0;
1614 }
1615 if ((bp->nb_dirtyend > 0) && (bp->nb_dirtyoff < neweofoff))
1616 mustwrite++;
1617 }
1618 bp->nb_dirty &= (1 << round_page_32(neweofoff)/PAGE_SIZE) - 1;
1619 if (bp->nb_dirty)
1620 mustwrite++;
1621 if (!mustwrite) {
1622 FSDBG(512, bp, bp->nb_flags, 0, obn);
1623 SET(bp->nb_flags, NB_INVAL);
1624 nfs_buf_release(bp, 1);
1625 continue;
1626 }
1627 /* gotta write out dirty data before invalidating */
1628 /* (NB_STABLE indicates that data writes should be FILESYNC) */
1629 /* (NB_NOCACHE indicates buffer should be discarded) */
1630 CLR(bp->nb_flags, (NB_DONE | NB_ERROR | NB_INVAL | NB_ASYNC | NB_READ));
1631 SET(bp->nb_flags, NB_STABLE | NB_NOCACHE);
1632 if (!IS_VALID_CRED(bp->nb_wcred)) {
1633 kauth_cred_t cred = vfs_context_ucred(ctx);
1634 kauth_cred_ref(cred);
1635 bp->nb_wcred = cred;
1636 }
1637 error = nfs_buf_write(bp);
1638 // Note: bp has been released
1639 if (error) {
1640 FSDBG(512, bp, 0xd00dee, 0xbad, error);
1641 nfs_node_lock_force(np);
1642 np->n_error = error;
1643 np->n_flag |= NWRITEERR;
1644 /*
1645 * There was a write error and we need to
1646 * invalidate attrs and flush buffers in
1647 * order to sync up with the server.
1648 * (if this write was extending the file,
1649 * we may no longer know the correct size)
1650 */
1651 NATTRINVALIDATE(np);
1652 nfs_node_unlock(np);
1653 nfs_data_unlock(np);
1654 nfs_vinvalbuf(vp, V_SAVE|V_IGNORE_WRITEERR, ctx, 1);
1655 nfs_data_lock(np, NFS_DATA_LOCK_EXCLUSIVE);
1656 error = 0;
1657 }
1658 }
1659 }
1660 if (vap->va_data_size != np->n_size)
1661 ubc_setsize(vp, (off_t)vap->va_data_size); /* XXX error? */
1662 origsize = np->n_size;
1663 np->n_size = np->n_vattr.nva_size = vap->va_data_size;
1664 nfs_node_lock_force(np);
1665 CLR(np->n_flag, NUPDATESIZE);
1666 nfs_node_unlock(np);
1667 FSDBG(512, np, np->n_size, np->n_vattr.nva_size, 0xf00d0001);
1668 }
1669 } else if (VATTR_IS_ACTIVE(vap, va_modify_time) ||
1670 VATTR_IS_ACTIVE(vap, va_access_time) ||
1671 (vap->va_vaflags & VA_UTIMES_NULL)) {
1672 if ((error = nfs_node_lock(np)))
1673 return (error);
1674 if ((np->n_flag & NMODIFIED) && (vnode_vtype(vp) == VREG)) {
1675 nfs_node_unlock(np);
1676 error = nfs_vinvalbuf(vp, V_SAVE, ctx, 1);
1677 if (error == EINTR)
1678 return (error);
1679 } else {
1680 nfs_node_unlock(np);
1681 }
1682 }
1683 if ((VATTR_IS_ACTIVE(vap, va_mode) || VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid) ||
1684 VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_uuuid) || VATTR_IS_ACTIVE(vap, va_guuid)) &&
1685 !(error = nfs_node_lock(np))) {
1686 NACCESSINVALIDATE(np);
1687 nfs_node_unlock(np);
1688 if (!namedattrs) {
1689 dvp = vnode_getparent(vp);
1690 vname = vnode_getname(vp);
1691 dnp = (dvp && vname) ? VTONFS(dvp) : NULL;
1692 if (dnp) {
1693 error = nfs_node_set_busy(dnp, vfs_context_thread(ctx));
1694 if (error) {
1695 dnp = NULL;
1696 error = 0;
1697 }
1698 }
1699 if (dnp) {
1700 nfs_dulookup_init(&dul, dnp, vname, strlen(vname), ctx);
1701 nfs_dulookup_start(&dul, dnp, ctx);
1702 }
1703 }
1704 }
1705
1706 if (!error)
1707 error = nmp->nm_funcs->nf_setattr_rpc(np, vap, ctx);
1708
1709 if (VATTR_IS_ACTIVE(vap, va_mode) || VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid) ||
1710 VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_uuuid) || VATTR_IS_ACTIVE(vap, va_guuid)) {
1711 if (!namedattrs) {
1712 if (dnp) {
1713 nfs_dulookup_finish(&dul, dnp, ctx);
1714 nfs_node_clear_busy(dnp);
1715 }
1716 if (dvp != NULLVP)
1717 vnode_put(dvp);
1718 if (vname != NULL)
1719 vnode_putname(vname);
1720 }
1721 }
1722
1723 FSDBG_BOT(512, np->n_size, vap->va_data_size, np->n_vattr.nva_size, error);
1724 if (VATTR_IS_ACTIVE(vap, va_data_size)) {
1725 if (error && (origsize != np->n_size) &&
1726 ((nfsvers < NFS_VER4) || !nfs_mount_state_error_should_restart(error))) {
1727 /* make every effort to resync file size w/ server... */
1728 /* (don't bother if we'll be restarting the operation) */
1729 int err; /* preserve "error" for return */
1730 np->n_size = np->n_vattr.nva_size = origsize;
1731 nfs_node_lock_force(np);
1732 CLR(np->n_flag, NUPDATESIZE);
1733 nfs_node_unlock(np);
1734 FSDBG(512, np, np->n_size, np->n_vattr.nva_size, 0xf00d0002);
1735 ubc_setsize(vp, (off_t)np->n_size); /* XXX check error */
1736 vapsize = vap->va_data_size;
1737 vap->va_data_size = origsize;
1738 err = nmp->nm_funcs->nf_setattr_rpc(np, vap, ctx);
1739 if (err)
1740 NP(np, "nfs_vnop_setattr: nfs%d_setattr_rpc %d %d", nfsvers, error, err);
1741 vap->va_data_size = vapsize;
1742 }
1743 nfs_node_lock_force(np);
1744 /*
1745 * The size was just set. If the size is already marked for update, don't
1746 * trust the newsize (it may have been set while the setattr was in progress).
1747 * Clear the update flag and make sure we fetch new attributes so we are sure
1748 * we have the latest size.
1749 */
1750 if (ISSET(np->n_flag, NUPDATESIZE)) {
1751 CLR(np->n_flag, NUPDATESIZE);
1752 NATTRINVALIDATE(np);
1753 nfs_node_unlock(np);
1754 nfs_getattr(np, NULL, ctx, NGA_UNCACHED);
1755 } else {
1756 nfs_node_unlock(np);
1757 }
1758 nfs_data_unlock(np);
1759 if (nfsvers >= NFS_VER4) {
1760 if (nofp) {
1761 /* don't close our setattr open if we'll be restarting... */
1762 if (!nfs_mount_state_error_should_restart(error) &&
1763 (nofp->nof_flags & NFS_OPEN_FILE_SETATTR)) {
1764 int err = nfs_close(np, nofp, NFS_OPEN_SHARE_ACCESS_WRITE, NFS_OPEN_SHARE_DENY_NONE, ctx);
1765 if (err)
1766 NP(np, "nfs_vnop_setattr: close error: %d", err);
1767 nofp->nof_flags &= ~NFS_OPEN_FILE_SETATTR;
1768 }
1769 nfs_open_file_clear_busy(nofp);
1770 nofp = NULL;
1771 }
1772 if (nfs_mount_state_in_use_end(nmp, error))
1773 goto restart;
1774 nfs_open_owner_rele(noop);
1775 }
1776 }
1777 return (error);
1778 }
1779
1780 /*
1781 * Do an NFS setattr RPC.
1782 */
1783 int
1784 nfs3_setattr_rpc(
1785 nfsnode_t np,
1786 struct vnode_attr *vap,
1787 vfs_context_t ctx)
1788 {
1789 struct nfsmount *nmp = NFSTONMP(np);
1790 int error = 0, lockerror = ENOENT, status, wccpostattr = 0, nfsvers;
1791 u_int64_t xid, nextxid;
1792 struct nfsm_chain nmreq, nmrep;
1793
1794 if (!nmp)
1795 return (ENXIO);
1796 nfsvers = nmp->nm_vers;
1797
1798 VATTR_SET_SUPPORTED(vap, va_mode);
1799 VATTR_SET_SUPPORTED(vap, va_uid);
1800 VATTR_SET_SUPPORTED(vap, va_gid);
1801 VATTR_SET_SUPPORTED(vap, va_data_size);
1802 VATTR_SET_SUPPORTED(vap, va_access_time);
1803 VATTR_SET_SUPPORTED(vap, va_modify_time);
1804
1805 if (VATTR_IS_ACTIVE(vap, va_flags)) {
1806 if (vap->va_flags) { /* we don't support setting flags */
1807 if (vap->va_active & ~VNODE_ATTR_va_flags)
1808 return (EINVAL); /* return EINVAL if other attributes also set */
1809 else
1810 return (ENOTSUP); /* return ENOTSUP for chflags(2) */
1811 }
1812 /* no flags set, so we'll just ignore it */
1813 if (!(vap->va_active & ~VNODE_ATTR_va_flags))
1814 return (0); /* no (other) attributes to set, so nothing to do */
1815 }
1816
1817 nfsm_chain_null(&nmreq);
1818 nfsm_chain_null(&nmrep);
1819
1820 nfsm_chain_build_alloc_init(error, &nmreq,
1821 NFSX_FH(nfsvers) + NFSX_SATTR(nfsvers));
1822 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
1823 if (nfsvers == NFS_VER3) {
1824 if (VATTR_IS_ACTIVE(vap, va_mode)) {
1825 nfsm_chain_add_32(error, &nmreq, TRUE);
1826 nfsm_chain_add_32(error, &nmreq, vap->va_mode);
1827 } else {
1828 nfsm_chain_add_32(error, &nmreq, FALSE);
1829 }
1830 if (VATTR_IS_ACTIVE(vap, va_uid)) {
1831 nfsm_chain_add_32(error, &nmreq, TRUE);
1832 nfsm_chain_add_32(error, &nmreq, vap->va_uid);
1833 } else {
1834 nfsm_chain_add_32(error, &nmreq, FALSE);
1835 }
1836 if (VATTR_IS_ACTIVE(vap, va_gid)) {
1837 nfsm_chain_add_32(error, &nmreq, TRUE);
1838 nfsm_chain_add_32(error, &nmreq, vap->va_gid);
1839 } else {
1840 nfsm_chain_add_32(error, &nmreq, FALSE);
1841 }
1842 if (VATTR_IS_ACTIVE(vap, va_data_size)) {
1843 nfsm_chain_add_32(error, &nmreq, TRUE);
1844 nfsm_chain_add_64(error, &nmreq, vap->va_data_size);
1845 } else {
1846 nfsm_chain_add_32(error, &nmreq, FALSE);
1847 }
1848 if (vap->va_vaflags & VA_UTIMES_NULL) {
1849 nfsm_chain_add_32(error, &nmreq, NFS_TIME_SET_TO_SERVER);
1850 nfsm_chain_add_32(error, &nmreq, NFS_TIME_SET_TO_SERVER);
1851 } else {
1852 if (VATTR_IS_ACTIVE(vap, va_access_time)) {
1853 nfsm_chain_add_32(error, &nmreq, NFS_TIME_SET_TO_CLIENT);
1854 nfsm_chain_add_32(error, &nmreq, vap->va_access_time.tv_sec);
1855 nfsm_chain_add_32(error, &nmreq, vap->va_access_time.tv_nsec);
1856 } else {
1857 nfsm_chain_add_32(error, &nmreq, NFS_TIME_DONT_CHANGE);
1858 }
1859 if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
1860 nfsm_chain_add_32(error, &nmreq, NFS_TIME_SET_TO_CLIENT);
1861 nfsm_chain_add_32(error, &nmreq, vap->va_modify_time.tv_sec);
1862 nfsm_chain_add_32(error, &nmreq, vap->va_modify_time.tv_nsec);
1863 } else {
1864 nfsm_chain_add_32(error, &nmreq, NFS_TIME_DONT_CHANGE);
1865 }
1866 }
1867 nfsm_chain_add_32(error, &nmreq, FALSE);
1868 } else {
1869 nfsm_chain_add_32(error, &nmreq, VATTR_IS_ACTIVE(vap, va_mode) ?
1870 vtonfsv2_mode(vnode_vtype(NFSTOV(np)), vap->va_mode) : -1);
1871 nfsm_chain_add_32(error, &nmreq, VATTR_IS_ACTIVE(vap, va_uid) ?
1872 vap->va_uid : (uint32_t)-1);
1873 nfsm_chain_add_32(error, &nmreq, VATTR_IS_ACTIVE(vap, va_gid) ?
1874 vap->va_gid : (uint32_t)-1);
1875 nfsm_chain_add_32(error, &nmreq, VATTR_IS_ACTIVE(vap, va_data_size) ?
1876 vap->va_data_size : (uint32_t)-1);
1877 if (VATTR_IS_ACTIVE(vap, va_access_time)) {
1878 nfsm_chain_add_32(error, &nmreq, vap->va_access_time.tv_sec);
1879 nfsm_chain_add_32(error, &nmreq, (vap->va_access_time.tv_nsec != -1) ?
1880 ((uint32_t)vap->va_access_time.tv_nsec / 1000) : 0xffffffff);
1881 } else {
1882 nfsm_chain_add_32(error, &nmreq, -1);
1883 nfsm_chain_add_32(error, &nmreq, -1);
1884 }
1885 if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
1886 nfsm_chain_add_32(error, &nmreq, vap->va_modify_time.tv_sec);
1887 nfsm_chain_add_32(error, &nmreq, (vap->va_modify_time.tv_nsec != -1) ?
1888 ((uint32_t)vap->va_modify_time.tv_nsec / 1000) : 0xffffffff);
1889 } else {
1890 nfsm_chain_add_32(error, &nmreq, -1);
1891 nfsm_chain_add_32(error, &nmreq, -1);
1892 }
1893 }
1894 nfsm_chain_build_done(error, &nmreq);
1895 nfsmout_if(error);
1896 error = nfs_request(np, NULL, &nmreq, NFSPROC_SETATTR, ctx, NULL, &nmrep, &xid, &status);
1897 if ((lockerror = nfs_node_lock(np)))
1898 error = lockerror;
1899 if (nfsvers == NFS_VER3) {
1900 struct timespec premtime = { 0, 0 };
1901 nfsm_chain_get_wcc_data(error, &nmrep, np, &premtime, &wccpostattr, &xid);
1902 nfsmout_if(error);
1903 /* if file hadn't changed, update cached mtime */
1904 if (nfstimespeccmp(&np->n_mtime, &premtime, ==))
1905 NFS_CHANGED_UPDATE(nfsvers, np, &np->n_vattr);
1906 /* if directory hadn't changed, update namecache mtime */
1907 if ((vnode_vtype(NFSTOV(np)) == VDIR) &&
1908 nfstimespeccmp(&np->n_ncmtime, &premtime, ==))
1909 NFS_CHANGED_UPDATE_NC(nfsvers, np, &np->n_vattr);
1910 if (!wccpostattr)
1911 NATTRINVALIDATE(np);
1912 error = status;
1913 } else {
1914 if (!error)
1915 error = status;
1916 nfsm_chain_loadattr(error, &nmrep, np, nfsvers, &xid);
1917 }
1918 /*
1919 * We just changed the attributes and we want to make sure that we
1920 * see the latest attributes. Get the next XID. If it's not the
1921 * next XID after the SETATTR XID, then it's possible that another
1922 * RPC was in flight at the same time and it might put stale attributes
1923 * in the cache. In that case, we invalidate the attributes and set
1924 * the attribute cache XID to guarantee that newer attributes will
1925 * get loaded next.
1926 */
1927 nextxid = 0;
1928 nfs_get_xid(&nextxid);
1929 if (nextxid != (xid + 1)) {
1930 np->n_xid = nextxid;
1931 NATTRINVALIDATE(np);
1932 }
1933 nfsmout:
1934 if (!lockerror)
1935 nfs_node_unlock(np);
1936 nfsm_chain_cleanup(&nmreq);
1937 nfsm_chain_cleanup(&nmrep);
1938 return (error);
1939 }
1940
1941 /*
1942 * NFS lookup call, one step at a time...
1943 * First look in cache
1944 * If not found, unlock the directory nfsnode and do the RPC
1945 */
1946 int
1947 nfs_vnop_lookup(
1948 struct vnop_lookup_args /* {
1949 struct vnodeop_desc *a_desc;
1950 vnode_t a_dvp;
1951 vnode_t *a_vpp;
1952 struct componentname *a_cnp;
1953 vfs_context_t a_context;
1954 } */ *ap)
1955 {
1956 vfs_context_t ctx = ap->a_context;
1957 struct componentname *cnp = ap->a_cnp;
1958 vnode_t dvp = ap->a_dvp;
1959 vnode_t *vpp = ap->a_vpp;
1960 int flags = cnp->cn_flags;
1961 vnode_t newvp;
1962 nfsnode_t dnp, np;
1963 struct nfsmount *nmp;
1964 mount_t mp;
1965 int nfsvers, error, busyerror = ENOENT, isdot, isdotdot, negnamecache;
1966 u_int64_t xid;
1967 struct nfs_vattr nvattr;
1968 int ngflags;
1969 struct vnop_access_args naa;
1970 fhandle_t fh;
1971 struct nfsreq rq, *req = &rq;
1972
1973 *vpp = NULLVP;
1974
1975 dnp = VTONFS(dvp);
1976 NVATTR_INIT(&nvattr);
1977
1978 mp = vnode_mount(dvp);
1979 nmp = VFSTONFS(mp);
1980 if (!nmp) {
1981 error = ENXIO;
1982 goto error_return;
1983 }
1984 nfsvers = nmp->nm_vers;
1985 negnamecache = !NMFLAG(nmp, NONEGNAMECACHE);
1986
1987 if ((error = busyerror = nfs_node_set_busy(dnp, vfs_context_thread(ctx))))
1988 goto error_return;
1989 /* nfs_getattr() will check changed and purge caches */
1990 if ((error = nfs_getattr(dnp, NULL, ctx, NGA_CACHED)))
1991 goto error_return;
1992
1993 error = cache_lookup(dvp, vpp, cnp);
1994 switch (error) {
1995 case ENOENT:
1996 /* negative cache entry */
1997 goto error_return;
1998 case 0:
1999 /* cache miss */
2000 if ((nfsvers > NFS_VER2) && NMFLAG(nmp, RDIRPLUS)) {
2001 /* if rdirplus, try dir buf cache lookup */
2002 error = nfs_dir_buf_cache_lookup(dnp, &np, cnp, ctx, 0);
2003 if (!error && np) {
2004 /* dir buf cache hit */
2005 *vpp = NFSTOV(np);
2006 error = -1;
2007 }
2008 }
2009 if (error != -1) /* cache miss */
2010 break;
2011 /* FALLTHROUGH */
2012 case -1:
2013 /* cache hit, not really an error */
2014 OSAddAtomic(1, &nfsstats.lookupcache_hits);
2015
2016 nfs_node_clear_busy(dnp);
2017 busyerror = ENOENT;
2018
2019 /* check for directory access */
2020 naa.a_desc = &vnop_access_desc;
2021 naa.a_vp = dvp;
2022 naa.a_action = KAUTH_VNODE_SEARCH;
2023 naa.a_context = ctx;
2024
2025 /* compute actual success/failure based on accessibility */
2026 error = nfs_vnop_access(&naa);
2027 /* FALLTHROUGH */
2028 default:
2029 /* unexpected error from cache_lookup */
2030 goto error_return;
2031 }
2032
2033 /* skip lookup, if we know who we are: "." or ".." */
2034 isdot = isdotdot = 0;
2035 if (cnp->cn_nameptr[0] == '.') {
2036 if (cnp->cn_namelen == 1)
2037 isdot = 1;
2038 if ((cnp->cn_namelen == 2) && (cnp->cn_nameptr[1] == '.'))
2039 isdotdot = 1;
2040 }
2041 if (isdotdot || isdot) {
2042 fh.fh_len = 0;
2043 goto found;
2044 }
2045 if ((nfsvers >= NFS_VER4) && (dnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER)) {
2046 /* we should never be looking things up in a trigger directory, return nothing */
2047 error = ENOENT;
2048 goto error_return;
2049 }
2050
2051 /* do we know this name is too long? */
2052 nmp = VTONMP(dvp);
2053 if (!nmp) {
2054 error = ENXIO;
2055 goto error_return;
2056 }
2057 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXNAME) &&
2058 (cnp->cn_namelen > (int)nmp->nm_fsattr.nfsa_maxname)) {
2059 error = ENAMETOOLONG;
2060 goto error_return;
2061 }
2062
2063 error = 0;
2064 newvp = NULLVP;
2065
2066 OSAddAtomic(1, &nfsstats.lookupcache_misses);
2067
2068 error = nmp->nm_funcs->nf_lookup_rpc_async(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &req);
2069 nfsmout_if(error);
2070 error = nmp->nm_funcs->nf_lookup_rpc_async_finish(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, req, &xid, &fh, &nvattr);
2071 nfsmout_if(error);
2072
2073 /* is the file handle the same as this directory's file handle? */
2074 isdot = NFS_CMPFH(dnp, fh.fh_data, fh.fh_len);
2075
2076 found:
2077 if (flags & ISLASTCN) {
2078 switch (cnp->cn_nameiop) {
2079 case DELETE:
2080 cnp->cn_flags &= ~MAKEENTRY;
2081 break;
2082 case RENAME:
2083 cnp->cn_flags &= ~MAKEENTRY;
2084 if (isdot) {
2085 error = EISDIR;
2086 goto error_return;
2087 }
2088 break;
2089 }
2090 }
2091
2092 if (isdotdot) {
2093 newvp = vnode_getparent(dvp);
2094 if (!newvp) {
2095 error = ENOENT;
2096 goto error_return;
2097 }
2098 } else if (isdot) {
2099 error = vnode_get(dvp);
2100 if (error)
2101 goto error_return;
2102 newvp = dvp;
2103 nfs_node_lock_force(dnp);
2104 if (fh.fh_len && (dnp->n_xid <= xid))
2105 nfs_loadattrcache(dnp, &nvattr, &xid, 0);
2106 nfs_node_unlock(dnp);
2107 } else {
2108 ngflags = (cnp->cn_flags & MAKEENTRY) ? NG_MAKEENTRY : 0;
2109 error = nfs_nget(mp, dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, rq.r_auth, ngflags, &np);
2110 if (error)
2111 goto error_return;
2112 newvp = NFSTOV(np);
2113 nfs_node_unlock(np);
2114 }
2115 *vpp = newvp;
2116
2117 nfsmout:
2118 if (error) {
2119 if (((cnp->cn_nameiop == CREATE) || (cnp->cn_nameiop == RENAME)) &&
2120 (flags & ISLASTCN) && (error == ENOENT)) {
2121 if (vnode_mount(dvp) && vnode_vfsisrdonly(dvp))
2122 error = EROFS;
2123 else
2124 error = EJUSTRETURN;
2125 }
2126 }
2127 if ((error == ENOENT) && (cnp->cn_flags & MAKEENTRY) &&
2128 (cnp->cn_nameiop != CREATE) && negnamecache) {
2129 /* add a negative entry in the name cache */
2130 nfs_node_lock_force(dnp);
2131 cache_enter(dvp, NULL, cnp);
2132 dnp->n_flag |= NNEGNCENTRIES;
2133 nfs_node_unlock(dnp);
2134 }
2135 error_return:
2136 NVATTR_CLEANUP(&nvattr);
2137 if (!busyerror)
2138 nfs_node_clear_busy(dnp);
2139 if (error && *vpp) {
2140 vnode_put(*vpp);
2141 *vpp = NULLVP;
2142 }
2143 return (error);
2144 }
2145
2146 /*
2147 * NFS readlink call
2148 */
2149 int
2150 nfs_vnop_readlink(
2151 struct vnop_readlink_args /* {
2152 struct vnodeop_desc *a_desc;
2153 vnode_t a_vp;
2154 struct uio *a_uio;
2155 vfs_context_t a_context;
2156 } */ *ap)
2157 {
2158 vfs_context_t ctx = ap->a_context;
2159 nfsnode_t np = VTONFS(ap->a_vp);
2160 struct nfsmount *nmp;
2161 int error = 0, nfsvers;
2162 uint32_t buflen;
2163 uio_t uio = ap->a_uio;
2164 struct nfsbuf *bp = NULL;
2165
2166 if (vnode_vtype(ap->a_vp) != VLNK)
2167 return (EPERM);
2168
2169 if (uio_resid(uio) == 0)
2170 return (0);
2171 if (uio_offset(uio) < 0)
2172 return (EINVAL);
2173
2174 nmp = VTONMP(ap->a_vp);
2175 if (!nmp)
2176 return (ENXIO);
2177 nfsvers = nmp->nm_vers;
2178
2179 /* nfs_getattr() will check changed and purge caches */
2180 if ((error = nfs_getattr(np, NULL, ctx, NGA_CACHED))) {
2181 FSDBG(531, np, 0xd1e0001, 0, error);
2182 return (error);
2183 }
2184
2185 OSAddAtomic(1, &nfsstats.biocache_readlinks);
2186 error = nfs_buf_get(np, 0, NFS_MAXPATHLEN, vfs_context_thread(ctx), NBLK_READ, &bp);
2187 if (error) {
2188 FSDBG(531, np, 0xd1e0002, 0, error);
2189 return (error);
2190 }
2191 if (!ISSET(bp->nb_flags, NB_CACHE)) {
2192 OSAddAtomic(1, &nfsstats.readlink_bios);
2193 buflen = bp->nb_bufsize;
2194 error = nmp->nm_funcs->nf_readlink_rpc(np, bp->nb_data, &buflen, ctx);
2195 if (error) {
2196 SET(bp->nb_flags, NB_ERROR);
2197 bp->nb_error = error;
2198 } else {
2199 bp->nb_validoff = 0;
2200 bp->nb_validend = buflen;
2201 }
2202 }
2203 if (!error && (bp->nb_validend > 0))
2204 error = uiomove(bp->nb_data, bp->nb_validend, uio);
2205 FSDBG(531, np, bp->nb_validend, 0, error);
2206 nfs_buf_release(bp, 1);
2207 return (error);
2208 }
2209
2210 /*
2211 * Do a readlink RPC.
2212 */
2213 int
2214 nfs3_readlink_rpc(nfsnode_t np, char *buf, uint32_t *buflenp, vfs_context_t ctx)
2215 {
2216 struct nfsmount *nmp;
2217 int error = 0, lockerror = ENOENT, nfsvers, status;
2218 uint32_t len;
2219 u_int64_t xid;
2220 struct nfsm_chain nmreq, nmrep;
2221
2222 nmp = NFSTONMP(np);
2223 if (!nmp)
2224 return (ENXIO);
2225 nfsvers = nmp->nm_vers;
2226 nfsm_chain_null(&nmreq);
2227 nfsm_chain_null(&nmrep);
2228
2229 nfsm_chain_build_alloc_init(error, &nmreq, NFSX_FH(nfsvers));
2230 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
2231 nfsm_chain_build_done(error, &nmreq);
2232 nfsmout_if(error);
2233 error = nfs_request(np, NULL, &nmreq, NFSPROC_READLINK, ctx, NULL, &nmrep, &xid, &status);
2234 if ((lockerror = nfs_node_lock(np)))
2235 error = lockerror;
2236 if (nfsvers == NFS_VER3)
2237 nfsm_chain_postop_attr_update(error, &nmrep, np, &xid);
2238 if (!error)
2239 error = status;
2240 nfsm_chain_get_32(error, &nmrep, len);
2241 nfsmout_if(error);
2242 if ((nfsvers == NFS_VER2) && (len > *buflenp)) {
2243 error = EBADRPC;
2244 goto nfsmout;
2245 }
2246 if (len >= *buflenp) {
2247 if (np->n_size && (np->n_size < *buflenp))
2248 len = np->n_size;
2249 else
2250 len = *buflenp - 1;
2251 }
2252 nfsm_chain_get_opaque(error, &nmrep, len, buf);
2253 if (!error)
2254 *buflenp = len;
2255 nfsmout:
2256 if (!lockerror)
2257 nfs_node_unlock(np);
2258 nfsm_chain_cleanup(&nmreq);
2259 nfsm_chain_cleanup(&nmrep);
2260 return (error);
2261 }
2262
2263 /*
2264 * NFS read RPC call
2265 * Ditto above
2266 */
2267 int
2268 nfs_read_rpc(nfsnode_t np, uio_t uio, vfs_context_t ctx)
2269 {
2270 struct nfsmount *nmp;
2271 int error = 0, nfsvers, eof = 0;
2272 size_t nmrsize, len, retlen;
2273 user_ssize_t tsiz;
2274 off_t txoffset;
2275 struct nfsreq rq, *req = &rq;
2276 uint32_t stategenid = 0, restart = 0;
2277
2278 FSDBG_TOP(536, np, uio_offset(uio), uio_resid(uio), 0);
2279 nmp = NFSTONMP(np);
2280 if (!nmp)
2281 return (ENXIO);
2282 nfsvers = nmp->nm_vers;
2283 nmrsize = nmp->nm_rsize;
2284
2285 txoffset = uio_offset(uio);
2286 tsiz = uio_resid(uio);
2287 if ((nfsvers == NFS_VER2) && ((uint64_t)(txoffset + tsiz) > 0xffffffffULL)) {
2288 FSDBG_BOT(536, np, uio_offset(uio), uio_resid(uio), EFBIG);
2289 return (EFBIG);
2290 }
2291
2292 while (tsiz > 0) {
2293 len = retlen = (tsiz > (user_ssize_t)nmrsize) ? nmrsize : (size_t)tsiz;
2294 FSDBG(536, np, txoffset, len, 0);
2295 if (np->n_flag & NREVOKE) {
2296 error = EIO;
2297 break;
2298 }
2299 if (nmp->nm_vers >= NFS_VER4)
2300 stategenid = nmp->nm_stategenid;
2301 error = nmp->nm_funcs->nf_read_rpc_async(np, txoffset, len,
2302 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, &req);
2303 if (!error)
2304 error = nmp->nm_funcs->nf_read_rpc_async_finish(np, req, uio, &retlen, &eof);
2305 if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error) &&
2306 (++restart <= nfs_mount_state_max_restarts(nmp))) { /* guard against no progress */
2307 lck_mtx_lock(&nmp->nm_lock);
2308 if ((error != NFSERR_GRACE) && (stategenid == nmp->nm_stategenid)) {
2309 NP(np, "nfs_read_rpc: error %d, initiating recovery", error);
2310 nfs_need_recover(nmp, error);
2311 }
2312 lck_mtx_unlock(&nmp->nm_lock);
2313 if (np->n_flag & NREVOKE) {
2314 error = EIO;
2315 } else {
2316 if (error == NFSERR_GRACE)
2317 tsleep(&nmp->nm_state, (PZERO-1), "nfsgrace", 2*hz);
2318 if (!(error = nfs_mount_state_wait_for_recovery(nmp)))
2319 continue;
2320 }
2321 }
2322 if (error)
2323 break;
2324 txoffset += retlen;
2325 tsiz -= retlen;
2326 if (nfsvers != NFS_VER2) {
2327 if (eof || (retlen == 0))
2328 tsiz = 0;
2329 } else if (retlen < len)
2330 tsiz = 0;
2331 }
2332
2333 FSDBG_BOT(536, np, eof, uio_resid(uio), error);
2334 return (error);
2335 }
2336
2337 int
2338 nfs3_read_rpc_async(
2339 nfsnode_t np,
2340 off_t offset,
2341 size_t len,
2342 thread_t thd,
2343 kauth_cred_t cred,
2344 struct nfsreq_cbinfo *cb,
2345 struct nfsreq **reqp)
2346 {
2347 struct nfsmount *nmp;
2348 int error = 0, nfsvers;
2349 struct nfsm_chain nmreq;
2350
2351 nmp = NFSTONMP(np);
2352 if (!nmp)
2353 return (ENXIO);
2354 nfsvers = nmp->nm_vers;
2355
2356 nfsm_chain_null(&nmreq);
2357 nfsm_chain_build_alloc_init(error, &nmreq, NFSX_FH(nfsvers) + 3 * NFSX_UNSIGNED);
2358 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
2359 if (nfsvers == NFS_VER3) {
2360 nfsm_chain_add_64(error, &nmreq, offset);
2361 nfsm_chain_add_32(error, &nmreq, len);
2362 } else {
2363 nfsm_chain_add_32(error, &nmreq, offset);
2364 nfsm_chain_add_32(error, &nmreq, len);
2365 nfsm_chain_add_32(error, &nmreq, 0);
2366 }
2367 nfsm_chain_build_done(error, &nmreq);
2368 nfsmout_if(error);
2369 error = nfs_request_async(np, NULL, &nmreq, NFSPROC_READ, thd, cred, NULL, 0, cb, reqp);
2370 nfsmout:
2371 nfsm_chain_cleanup(&nmreq);
2372 return (error);
2373 }
2374
2375 int
2376 nfs3_read_rpc_async_finish(
2377 nfsnode_t np,
2378 struct nfsreq *req,
2379 uio_t uio,
2380 size_t *lenp,
2381 int *eofp)
2382 {
2383 int error = 0, lockerror, nfsvers, status, eof = 0;
2384 size_t retlen = 0;
2385 uint64_t xid;
2386 struct nfsmount *nmp;
2387 struct nfsm_chain nmrep;
2388
2389 nmp = NFSTONMP(np);
2390 if (!nmp) {
2391 nfs_request_async_cancel(req);
2392 return (ENXIO);
2393 }
2394 nfsvers = nmp->nm_vers;
2395
2396 nfsm_chain_null(&nmrep);
2397
2398 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
2399 if (error == EINPROGRESS) /* async request restarted */
2400 return (error);
2401
2402 if ((lockerror = nfs_node_lock(np)))
2403 error = lockerror;
2404 if (nfsvers == NFS_VER3)
2405 nfsm_chain_postop_attr_update(error, &nmrep, np, &xid);
2406 if (!error)
2407 error = status;
2408 if (nfsvers == NFS_VER3) {
2409 nfsm_chain_adv(error, &nmrep, NFSX_UNSIGNED);
2410 nfsm_chain_get_32(error, &nmrep, eof);
2411 } else {
2412 nfsm_chain_loadattr(error, &nmrep, np, nfsvers, &xid);
2413 }
2414 if (!lockerror)
2415 nfs_node_unlock(np);
2416 nfsm_chain_get_32(error, &nmrep, retlen);
2417 if ((nfsvers == NFS_VER2) && (retlen > *lenp))
2418 error = EBADRPC;
2419 nfsmout_if(error);
2420 error = nfsm_chain_get_uio(&nmrep, MIN(retlen, *lenp), uio);
2421 if (eofp) {
2422 if (nfsvers == NFS_VER3) {
2423 if (!eof && !retlen)
2424 eof = 1;
2425 } else if (retlen < *lenp) {
2426 eof = 1;
2427 }
2428 *eofp = eof;
2429 }
2430 *lenp = MIN(retlen, *lenp);
2431 nfsmout:
2432 nfsm_chain_cleanup(&nmrep);
2433 return (error);
2434 }
2435
2436 /*
2437 * NFS write call
2438 */
2439 int
2440 nfs_vnop_write(
2441 struct vnop_write_args /* {
2442 struct vnodeop_desc *a_desc;
2443 vnode_t a_vp;
2444 struct uio *a_uio;
2445 int a_ioflag;
2446 vfs_context_t a_context;
2447 } */ *ap)
2448 {
2449 vfs_context_t ctx = ap->a_context;
2450 uio_t uio = ap->a_uio;
2451 vnode_t vp = ap->a_vp;
2452 nfsnode_t np = VTONFS(vp);
2453 int ioflag = ap->a_ioflag;
2454 struct nfsbuf *bp;
2455 struct nfsmount *nmp = VTONMP(vp);
2456 daddr64_t lbn;
2457 int biosize;
2458 int n, on, error = 0;
2459 off_t boff, start, end;
2460 uio_t auio;
2461 char auio_buf [ UIO_SIZEOF(1) ];
2462 thread_t thd;
2463 kauth_cred_t cred;
2464
2465 FSDBG_TOP(515, np, uio_offset(uio), uio_resid(uio), ioflag);
2466
2467 if (vnode_vtype(vp) != VREG) {
2468 FSDBG_BOT(515, np, uio_offset(uio), uio_resid(uio), EIO);
2469 return (EIO);
2470 }
2471
2472 thd = vfs_context_thread(ctx);
2473 cred = vfs_context_ucred(ctx);
2474
2475 nfs_data_lock(np, NFS_DATA_LOCK_SHARED);
2476
2477 if ((error = nfs_node_lock(np))) {
2478 nfs_data_unlock(np);
2479 FSDBG_BOT(515, np, uio_offset(uio), uio_resid(uio), error);
2480 return (error);
2481 }
2482 np->n_wrbusy++;
2483
2484 if (np->n_flag & NWRITEERR) {
2485 error = np->n_error;
2486 np->n_flag &= ~NWRITEERR;
2487 }
2488 if (np->n_flag & NNEEDINVALIDATE) {
2489 np->n_flag &= ~NNEEDINVALIDATE;
2490 nfs_node_unlock(np);
2491 nfs_data_unlock(np);
2492 nfs_vinvalbuf(vp, V_SAVE|V_IGNORE_WRITEERR, ctx, 1);
2493 nfs_data_lock(np, NFS_DATA_LOCK_SHARED);
2494 } else {
2495 nfs_node_unlock(np);
2496 }
2497 if (error)
2498 goto out;
2499
2500 biosize = nmp->nm_biosize;
2501
2502 if (ioflag & (IO_APPEND | IO_SYNC)) {
2503 nfs_node_lock_force(np);
2504 if (np->n_flag & NMODIFIED) {
2505 NATTRINVALIDATE(np);
2506 nfs_node_unlock(np);
2507 nfs_data_unlock(np);
2508 error = nfs_vinvalbuf(vp, V_SAVE, ctx, 1);
2509 nfs_data_lock(np, NFS_DATA_LOCK_SHARED);
2510 if (error) {
2511 FSDBG(515, np, uio_offset(uio), 0x10bad01, error);
2512 goto out;
2513 }
2514 } else {
2515 nfs_node_unlock(np);
2516 }
2517 if (ioflag & IO_APPEND) {
2518 nfs_data_unlock(np);
2519 /* nfs_getattr() will check changed and purge caches */
2520 error = nfs_getattr(np, NULL, ctx, NGA_UNCACHED);
2521 /* we'll be extending the file, so take the data lock exclusive */
2522 nfs_data_lock(np, NFS_DATA_LOCK_EXCLUSIVE);
2523 if (error) {
2524 FSDBG(515, np, uio_offset(uio), 0x10bad02, error);
2525 goto out;
2526 }
2527 uio_setoffset(uio, np->n_size);
2528 }
2529 }
2530 if (uio_offset(uio) < 0) {
2531 error = EINVAL;
2532 FSDBG_BOT(515, np, uio_offset(uio), 0xbad0ff, error);
2533 goto out;
2534 }
2535 if (uio_resid(uio) == 0)
2536 goto out;
2537
2538 if (((uio_offset(uio) + uio_resid(uio)) > (off_t)np->n_size) && !(ioflag & IO_APPEND)) {
2539 /* it looks like we'll be extending the file, so take the data lock exclusive */
2540 nfs_data_unlock(np);
2541 nfs_data_lock(np, NFS_DATA_LOCK_EXCLUSIVE);
2542 }
2543
2544 do {
2545 OSAddAtomic(1, &nfsstats.biocache_writes);
2546 lbn = uio_offset(uio) / biosize;
2547 on = uio_offset(uio) % biosize;
2548 n = biosize - on;
2549 if (uio_resid(uio) < n)
2550 n = uio_resid(uio);
2551 again:
2552 /*
2553 * Get a cache block for writing. The range to be written is
2554 * (off..off+n) within the block. We ensure that the block
2555 * either has no dirty region or that the given range is
2556 * contiguous with the existing dirty region.
2557 */
2558 error = nfs_buf_get(np, lbn, biosize, thd, NBLK_WRITE, &bp);
2559 if (error)
2560 goto out;
2561 /* map the block because we know we're going to write to it */
2562 NFS_BUF_MAP(bp);
2563
2564 if (ioflag & IO_NOCACHE)
2565 SET(bp->nb_flags, NB_NOCACHE);
2566
2567 if (!IS_VALID_CRED(bp->nb_wcred)) {
2568 kauth_cred_ref(cred);
2569 bp->nb_wcred = cred;
2570 }
2571
2572 /*
2573 * If there's already a dirty range AND dirty pages in this block we
2574 * need to send a commit AND write the dirty pages before continuing.
2575 *
2576 * If there's already a dirty range OR dirty pages in this block
2577 * and the new write range is not contiguous with the existing range,
2578 * then force the buffer to be written out now.
2579 * (We used to just extend the dirty range to cover the valid,
2580 * but unwritten, data in between also. But writing ranges
2581 * of data that weren't actually written by an application
2582 * risks overwriting some other client's data with stale data
2583 * that's just masquerading as new written data.)
2584 */
2585 if (bp->nb_dirtyend > 0) {
2586 if (on > bp->nb_dirtyend || (on + n) < bp->nb_dirtyoff || bp->nb_dirty) {
2587 FSDBG(515, np, uio_offset(uio), bp, 0xd15c001);
2588 /* write/commit buffer "synchronously" */
2589 /* (NB_STABLE indicates that data writes should be FILESYNC) */
2590 CLR(bp->nb_flags, (NB_DONE | NB_ERROR | NB_INVAL));
2591 SET(bp->nb_flags, (NB_ASYNC | NB_STABLE));
2592 error = nfs_buf_write(bp);
2593 if (error)
2594 goto out;
2595 goto again;
2596 }
2597 } else if (bp->nb_dirty) {
2598 int firstpg, lastpg;
2599 u_int32_t pagemask;
2600 /* calculate write range pagemask */
2601 firstpg = on/PAGE_SIZE;
2602 lastpg = (on+n-1)/PAGE_SIZE;
2603 pagemask = ((1 << (lastpg+1)) - 1) & ~((1 << firstpg) - 1);
2604 /* check if there are dirty pages outside the write range */
2605 if (bp->nb_dirty & ~pagemask) {
2606 FSDBG(515, np, uio_offset(uio), bp, 0xd15c002);
2607 /* write/commit buffer "synchronously" */
2608 /* (NB_STABLE indicates that data writes should be FILESYNC) */
2609 CLR(bp->nb_flags, (NB_DONE | NB_ERROR | NB_INVAL));
2610 SET(bp->nb_flags, (NB_ASYNC | NB_STABLE));
2611 error = nfs_buf_write(bp);
2612 if (error)
2613 goto out;
2614 goto again;
2615 }
2616 /* if the first or last pages are already dirty */
2617 /* make sure that the dirty range encompasses those pages */
2618 if (NBPGDIRTY(bp,firstpg) || NBPGDIRTY(bp,lastpg)) {
2619 FSDBG(515, np, uio_offset(uio), bp, 0xd15c003);
2620 bp->nb_dirtyoff = min(on, firstpg * PAGE_SIZE);
2621 if (NBPGDIRTY(bp,lastpg)) {
2622 bp->nb_dirtyend = (lastpg+1) * PAGE_SIZE;
2623 /* clip to EOF */
2624 if (NBOFF(bp) + bp->nb_dirtyend > (off_t)np->n_size) {
2625 bp->nb_dirtyend = np->n_size - NBOFF(bp);
2626 if (bp->nb_dirtyoff >= bp->nb_dirtyend)
2627 bp->nb_dirtyoff = bp->nb_dirtyend = 0;
2628 }
2629 } else
2630 bp->nb_dirtyend = on+n;
2631 }
2632 }
2633
2634 /*
2635 * Are we extending the size of the file with this write?
2636 * If so, update file size now that we have the block.
2637 * If there was a partial buf at the old eof, validate
2638 * and zero the new bytes.
2639 */
2640 if ((uio_offset(uio) + n) > (off_t)np->n_size) {
2641 struct nfsbuf *eofbp = NULL;
2642 daddr64_t eofbn = np->n_size / biosize;
2643 int eofoff = np->n_size % biosize;
2644 int neweofoff = (uio_offset(uio) + n) % biosize;
2645
2646 FSDBG(515, 0xb1ffa000, uio_offset(uio) + n, eofoff, neweofoff);
2647
2648 if (eofoff && (eofbn < lbn) &&
2649 ((error = nfs_buf_get(np, eofbn, biosize, thd, NBLK_WRITE|NBLK_ONLYVALID, &eofbp))))
2650 goto out;
2651
2652 /* if we're extending within the same last block */
2653 /* and the block is flagged as being cached... */
2654 if ((lbn == eofbn) && ISSET(bp->nb_flags, NB_CACHE)) {
2655 /* ...check that all pages in buffer are valid */
2656 int endpg = ((neweofoff ? neweofoff : biosize) - 1)/PAGE_SIZE;
2657 u_int32_t pagemask;
2658 /* pagemask only has to extend to last page being written to */
2659 pagemask = (1 << (endpg+1)) - 1;
2660 FSDBG(515, 0xb1ffa001, bp->nb_valid, pagemask, 0);
2661 if ((bp->nb_valid & pagemask) != pagemask) {
2662 /* zerofill any hole */
2663 if (on > bp->nb_validend) {
2664 int i;
2665 for (i=bp->nb_validend/PAGE_SIZE; i <= (on - 1)/PAGE_SIZE; i++)
2666 NBPGVALID_SET(bp, i);
2667 NFS_BUF_MAP(bp);
2668 FSDBG(516, bp, bp->nb_validend, on - bp->nb_validend, 0xf01e);
2669 bzero((char *)bp->nb_data + bp->nb_validend,
2670 on - bp->nb_validend);
2671 }
2672 /* zerofill any trailing data in the last page */
2673 if (neweofoff) {
2674 NFS_BUF_MAP(bp);
2675 FSDBG(516, bp, neweofoff, PAGE_SIZE - (neweofoff & PAGE_MASK), 0xe0f);
2676 bzero((char *)bp->nb_data + neweofoff,
2677 PAGE_SIZE - (neweofoff & PAGE_MASK));
2678 }
2679 }
2680 }
2681 np->n_size = uio_offset(uio) + n;
2682 nfs_node_lock_force(np);
2683 CLR(np->n_flag, NUPDATESIZE);
2684 np->n_flag |= NMODIFIED;
2685 nfs_node_unlock(np);
2686 FSDBG(516, np, np->n_size, np->n_vattr.nva_size, 0xf00d0001);
2687 ubc_setsize(vp, (off_t)np->n_size); /* XXX errors */
2688 if (eofbp) {
2689 /*
2690 * We may need to zero any previously invalid data
2691 * after the old EOF in the previous EOF buffer.
2692 *
2693 * For the old last page, don't zero bytes if there
2694 * are invalid bytes in that page (i.e. the page isn't
2695 * currently valid).
2696 * For pages after the old last page, zero them and
2697 * mark them as valid.
2698 */
2699 char *d;
2700 int i;
2701 if (ioflag & IO_NOCACHE)
2702 SET(eofbp->nb_flags, NB_NOCACHE);
2703 NFS_BUF_MAP(eofbp);
2704 FSDBG(516, eofbp, eofoff, biosize - eofoff, 0xe0fff01e);
2705 d = eofbp->nb_data;
2706 i = eofoff/PAGE_SIZE;
2707 while (eofoff < biosize) {
2708 int poff = eofoff & PAGE_MASK;
2709 if (!poff || NBPGVALID(eofbp,i)) {
2710 bzero(d + eofoff, PAGE_SIZE - poff);
2711 NBPGVALID_SET(eofbp, i);
2712 }
2713 if (bp->nb_validend == eofoff)
2714 bp->nb_validend += PAGE_SIZE - poff;
2715 eofoff += PAGE_SIZE - poff;
2716 i++;
2717 }
2718 nfs_buf_release(eofbp, 1);
2719 }
2720 }
2721 /*
2722 * If dirtyend exceeds file size, chop it down. This should
2723 * not occur unless there is a race.
2724 */
2725 if (NBOFF(bp) + bp->nb_dirtyend > (off_t)np->n_size) {
2726 bp->nb_dirtyend = np->n_size - NBOFF(bp);
2727 if (bp->nb_dirtyoff >= bp->nb_dirtyend)
2728 bp->nb_dirtyoff = bp->nb_dirtyend = 0;
2729 }
2730 /*
2731 * UBC doesn't handle partial pages, so we need to make sure
2732 * that any pages left in the page cache are completely valid.
2733 *
2734 * Writes that are smaller than a block are delayed if they
2735 * don't extend to the end of the block.
2736 *
2737 * If the block isn't (completely) cached, we may need to read
2738 * in some parts of pages that aren't covered by the write.
2739 * If the write offset (on) isn't page aligned, we'll need to
2740 * read the start of the first page being written to. Likewise,
2741 * if the offset of the end of the write (on+n) isn't page aligned,
2742 * we'll need to read the end of the last page being written to.
2743 *
2744 * Notes:
2745 * We don't want to read anything we're just going to write over.
2746 * We don't want to read anything we're just going drop when the
2747 * I/O is complete (i.e. don't do reads for NOCACHE requests).
2748 * We don't want to issue multiple I/Os if we don't have to
2749 * (because they're synchronous rpcs).
2750 * We don't want to read anything we already have modified in the
2751 * page cache.
2752 */
2753 if (!ISSET(bp->nb_flags, NB_CACHE) && (n < biosize)) {
2754 int firstpg, lastpg, dirtypg;
2755 int firstpgoff, lastpgoff;
2756 start = end = -1;
2757 firstpg = on/PAGE_SIZE;
2758 firstpgoff = on & PAGE_MASK;
2759 lastpg = (on+n-1)/PAGE_SIZE;
2760 lastpgoff = (on+n) & PAGE_MASK;
2761 if (firstpgoff && !NBPGVALID(bp,firstpg)) {
2762 /* need to read start of first page */
2763 start = firstpg * PAGE_SIZE;
2764 end = start + firstpgoff;
2765 }
2766 if (lastpgoff && !NBPGVALID(bp,lastpg)) {
2767 /* need to read end of last page */
2768 if (start < 0)
2769 start = (lastpg * PAGE_SIZE) + lastpgoff;
2770 end = (lastpg + 1) * PAGE_SIZE;
2771 }
2772 if (ISSET(bp->nb_flags, NB_NOCACHE)) {
2773 /*
2774 * For nocache writes, if there is any partial page at the
2775 * start or end of the write range, then we do the write
2776 * synchronously to make sure that we can drop the data
2777 * from the cache as soon as the WRITE finishes. Normally,
2778 * we would do an unstable write and not drop the data until
2779 * it was committed. But doing that here would risk allowing
2780 * invalid data to be read from the cache between the WRITE
2781 * and the COMMIT.
2782 * (NB_STABLE indicates that data writes should be FILESYNC)
2783 */
2784 if (end > start)
2785 SET(bp->nb_flags, NB_STABLE);
2786 goto skipread;
2787 }
2788 if (end > start) {
2789 /* need to read the data in range: start...end-1 */
2790
2791 /* first, check for dirty pages in between */
2792 /* if there are, we'll have to do two reads because */
2793 /* we don't want to overwrite the dirty pages. */
2794 for (dirtypg=start/PAGE_SIZE; dirtypg <= (end-1)/PAGE_SIZE; dirtypg++)
2795 if (NBPGDIRTY(bp,dirtypg))
2796 break;
2797
2798 /* if start is at beginning of page, try */
2799 /* to get any preceeding pages as well. */
2800 if (!(start & PAGE_MASK)) {
2801 /* stop at next dirty/valid page or start of block */
2802 for (; start > 0; start-=PAGE_SIZE)
2803 if (NBPGVALID(bp,((start-1)/PAGE_SIZE)))
2804 break;
2805 }
2806
2807 NFS_BUF_MAP(bp);
2808 /* setup uio for read(s) */
2809 boff = NBOFF(bp);
2810 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
2811 &auio_buf, sizeof(auio_buf));
2812
2813 if (dirtypg <= (end-1)/PAGE_SIZE) {
2814 /* there's a dirty page in the way, so just do two reads */
2815 /* we'll read the preceding data here */
2816 uio_reset(auio, boff + start, UIO_SYSSPACE, UIO_READ);
2817 uio_addiov(auio, CAST_USER_ADDR_T(bp->nb_data + start), on - start);
2818 error = nfs_read_rpc(np, auio, ctx);
2819 if (error) {
2820 /* couldn't read the data, so treat buffer as synchronous NOCACHE */
2821 SET(bp->nb_flags, (NB_NOCACHE|NB_STABLE));
2822 goto skipread;
2823 }
2824 if (uio_resid(auio) > 0) {
2825 FSDBG(516, bp, (caddr_t)uio_curriovbase(auio) - bp->nb_data, uio_resid(auio), 0xd00dee01);
2826 bzero(CAST_DOWN(caddr_t, uio_curriovbase(auio)), uio_resid(auio));
2827 }
2828 if (!error) {
2829 /* update validoff/validend if necessary */
2830 if ((bp->nb_validoff < 0) || (bp->nb_validoff > start))
2831 bp->nb_validoff = start;
2832 if ((bp->nb_validend < 0) || (bp->nb_validend < on))
2833 bp->nb_validend = on;
2834 if ((off_t)np->n_size > boff + bp->nb_validend)
2835 bp->nb_validend = min(np->n_size - (boff + start), biosize);
2836 /* validate any pages before the write offset */
2837 for (; start < on/PAGE_SIZE; start+=PAGE_SIZE)
2838 NBPGVALID_SET(bp, start/PAGE_SIZE);
2839 }
2840 /* adjust start to read any trailing data */
2841 start = on+n;
2842 }
2843
2844 /* if end is at end of page, try to */
2845 /* get any following pages as well. */
2846 if (!(end & PAGE_MASK)) {
2847 /* stop at next valid page or end of block */
2848 for (; end < biosize; end+=PAGE_SIZE)
2849 if (NBPGVALID(bp,end/PAGE_SIZE))
2850 break;
2851 }
2852
2853 if (((boff+start) >= (off_t)np->n_size) ||
2854 ((start >= on) && ((boff + on + n) >= (off_t)np->n_size))) {
2855 /*
2856 * Either this entire read is beyond the current EOF
2857 * or the range that we won't be modifying (on+n...end)
2858 * is all beyond the current EOF.
2859 * No need to make a trip across the network to
2860 * read nothing. So, just zero the buffer instead.
2861 */
2862 FSDBG(516, bp, start, end - start, 0xd00dee00);
2863 bzero(bp->nb_data + start, end - start);
2864 error = 0;
2865 } else {
2866 /* now we'll read the (rest of the) data */
2867 uio_reset(auio, boff + start, UIO_SYSSPACE, UIO_READ);
2868 uio_addiov(auio, CAST_USER_ADDR_T(bp->nb_data + start), end - start);
2869 error = nfs_read_rpc(np, auio, ctx);
2870 if (error) {
2871 /* couldn't read the data, so treat buffer as synchronous NOCACHE */
2872 SET(bp->nb_flags, (NB_NOCACHE|NB_STABLE));
2873 goto skipread;
2874 }
2875 if (uio_resid(auio) > 0) {
2876 FSDBG(516, bp, (caddr_t)uio_curriovbase(auio) - bp->nb_data, uio_resid(auio), 0xd00dee02);
2877 bzero(CAST_DOWN(caddr_t, uio_curriovbase(auio)), uio_resid(auio));
2878 }
2879 }
2880 if (!error) {
2881 /* update validoff/validend if necessary */
2882 if ((bp->nb_validoff < 0) || (bp->nb_validoff > start))
2883 bp->nb_validoff = start;
2884 if ((bp->nb_validend < 0) || (bp->nb_validend < end))
2885 bp->nb_validend = end;
2886 if ((off_t)np->n_size > boff + bp->nb_validend)
2887 bp->nb_validend = min(np->n_size - (boff + start), biosize);
2888 /* validate any pages before the write offset's page */
2889 for (; start < (off_t)trunc_page_32(on); start+=PAGE_SIZE)
2890 NBPGVALID_SET(bp, start/PAGE_SIZE);
2891 /* validate any pages after the range of pages being written to */
2892 for (; (end - 1) > (off_t)round_page_32(on+n-1); end-=PAGE_SIZE)
2893 NBPGVALID_SET(bp, (end-1)/PAGE_SIZE);
2894 }
2895 /* Note: pages being written to will be validated when written */
2896 }
2897 }
2898 skipread:
2899
2900 if (ISSET(bp->nb_flags, NB_ERROR)) {
2901 error = bp->nb_error;
2902 nfs_buf_release(bp, 1);
2903 goto out;
2904 }
2905
2906 nfs_node_lock_force(np);
2907 np->n_flag |= NMODIFIED;
2908 nfs_node_unlock(np);
2909
2910 NFS_BUF_MAP(bp);
2911 error = uiomove((char *)bp->nb_data + on, n, uio);
2912 if (error) {
2913 SET(bp->nb_flags, NB_ERROR);
2914 nfs_buf_release(bp, 1);
2915 goto out;
2916 }
2917
2918 /* validate any pages written to */
2919 start = on & ~PAGE_MASK;
2920 for (; start < on+n; start += PAGE_SIZE) {
2921 NBPGVALID_SET(bp, start/PAGE_SIZE);
2922 /*
2923 * This may seem a little weird, but we don't actually set the
2924 * dirty bits for writes. This is because we keep the dirty range
2925 * in the nb_dirtyoff/nb_dirtyend fields. Also, particularly for
2926 * delayed writes, when we give the pages back to the VM we don't
2927 * want to keep them marked dirty, because when we later write the
2928 * buffer we won't be able to tell which pages were written dirty
2929 * and which pages were mmapped and dirtied.
2930 */
2931 }
2932 if (bp->nb_dirtyend > 0) {
2933 bp->nb_dirtyoff = min(on, bp->nb_dirtyoff);
2934 bp->nb_dirtyend = max((on + n), bp->nb_dirtyend);
2935 } else {
2936 bp->nb_dirtyoff = on;
2937 bp->nb_dirtyend = on + n;
2938 }
2939 if (bp->nb_validend <= 0 || bp->nb_validend < bp->nb_dirtyoff ||
2940 bp->nb_validoff > bp->nb_dirtyend) {
2941 bp->nb_validoff = bp->nb_dirtyoff;
2942 bp->nb_validend = bp->nb_dirtyend;
2943 } else {
2944 bp->nb_validoff = min(bp->nb_validoff, bp->nb_dirtyoff);
2945 bp->nb_validend = max(bp->nb_validend, bp->nb_dirtyend);
2946 }
2947 if (!ISSET(bp->nb_flags, NB_CACHE))
2948 nfs_buf_normalize_valid_range(np, bp);
2949
2950 /*
2951 * Since this block is being modified, it must be written
2952 * again and not just committed.
2953 */
2954 if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) {
2955 nfs_node_lock_force(np);
2956 if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) {
2957 np->n_needcommitcnt--;
2958 CHECK_NEEDCOMMITCNT(np);
2959 }
2960 CLR(bp->nb_flags, NB_NEEDCOMMIT);
2961 nfs_node_unlock(np);
2962 }
2963
2964 if (ioflag & IO_SYNC) {
2965 error = nfs_buf_write(bp);
2966 if (error)
2967 goto out;
2968 } else if (((n + on) == biosize) || (ioflag & IO_APPEND) ||
2969 (ioflag & IO_NOCACHE) || ISSET(bp->nb_flags, NB_NOCACHE)) {
2970 SET(bp->nb_flags, NB_ASYNC);
2971 error = nfs_buf_write(bp);
2972 if (error)
2973 goto out;
2974 } else {
2975 /* If the block wasn't already delayed: charge for the write */
2976 if (!ISSET(bp->nb_flags, NB_DELWRI)) {
2977 proc_t p = vfs_context_proc(ctx);
2978 if (p && p->p_stats)
2979 OSIncrementAtomicLong(&p->p_stats->p_ru.ru_oublock);
2980 }
2981 nfs_buf_write_delayed(bp);
2982 }
2983 if (np->n_needcommitcnt >= NFS_A_LOT_OF_NEEDCOMMITS)
2984 nfs_flushcommits(np, 1);
2985
2986 } while (uio_resid(uio) > 0 && n > 0);
2987
2988 out:
2989 nfs_node_lock_force(np);
2990 np->n_wrbusy--;
2991 nfs_node_unlock(np);
2992 nfs_data_unlock(np);
2993 FSDBG_BOT(515, np, uio_offset(uio), uio_resid(uio), error);
2994 return (error);
2995 }
2996
2997
2998 /*
2999 * NFS write call
3000 */
3001 int
3002 nfs_write_rpc(
3003 nfsnode_t np,
3004 uio_t uio,
3005 vfs_context_t ctx,
3006 int *iomodep,
3007 uint64_t *wverfp)
3008 {
3009 return nfs_write_rpc2(np, uio, vfs_context_thread(ctx), vfs_context_ucred(ctx), iomodep, wverfp);
3010 }
3011
3012 int
3013 nfs_write_rpc2(
3014 nfsnode_t np,
3015 uio_t uio,
3016 thread_t thd,
3017 kauth_cred_t cred,
3018 int *iomodep,
3019 uint64_t *wverfp)
3020 {
3021 struct nfsmount *nmp;
3022 int error = 0, nfsvers;
3023 int backup, wverfset, commit, committed;
3024 uint64_t wverf = 0, wverf2;
3025 size_t nmwsize, totalsize, tsiz, len, rlen;
3026 struct nfsreq rq, *req = &rq;
3027 uint32_t stategenid = 0, vrestart = 0, restart = 0;
3028
3029 #if DIAGNOSTIC
3030 /* XXX limitation based on need to back up uio on short write */
3031 if (uio_iovcnt(uio) != 1)
3032 panic("nfs3_write_rpc: iovcnt > 1");
3033 #endif
3034 FSDBG_TOP(537, np, uio_offset(uio), uio_resid(uio), *iomodep);
3035 nmp = NFSTONMP(np);
3036 if (!nmp)
3037 return (ENXIO);
3038 nfsvers = nmp->nm_vers;
3039 nmwsize = nmp->nm_wsize;
3040
3041 wverfset = 0;
3042 committed = NFS_WRITE_FILESYNC;
3043
3044 totalsize = tsiz = uio_resid(uio);
3045 if ((nfsvers == NFS_VER2) && ((uint64_t)(uio_offset(uio) + tsiz) > 0xffffffffULL)) {
3046 FSDBG_BOT(537, np, uio_offset(uio), uio_resid(uio), EFBIG);
3047 return (EFBIG);
3048 }
3049
3050 while (tsiz > 0) {
3051 len = (tsiz > nmwsize) ? nmwsize : tsiz;
3052 FSDBG(537, np, uio_offset(uio), len, 0);
3053 if (np->n_flag & NREVOKE) {
3054 error = EIO;
3055 break;
3056 }
3057 if (nmp->nm_vers >= NFS_VER4)
3058 stategenid = nmp->nm_stategenid;
3059 error = nmp->nm_funcs->nf_write_rpc_async(np, uio, len, thd, cred, *iomodep, NULL, &req);
3060 if (!error)
3061 error = nmp->nm_funcs->nf_write_rpc_async_finish(np, req, &commit, &rlen, &wverf2);
3062 nmp = NFSTONMP(np);
3063 if (!nmp)
3064 error = ENXIO;
3065 if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error) &&
3066 (++restart <= nfs_mount_state_max_restarts(nmp))) { /* guard against no progress */
3067 lck_mtx_lock(&nmp->nm_lock);
3068 if ((error != NFSERR_GRACE) && (stategenid == nmp->nm_stategenid)) {
3069 NP(np, "nfs_write_rpc: error %d, initiating recovery", error);
3070 nfs_need_recover(nmp, error);
3071 }
3072 lck_mtx_unlock(&nmp->nm_lock);
3073 if (np->n_flag & NREVOKE) {
3074 error = EIO;
3075 } else {
3076 if (error == NFSERR_GRACE)
3077 tsleep(&nmp->nm_state, (PZERO-1), "nfsgrace", 2*hz);
3078 if (!(error = nfs_mount_state_wait_for_recovery(nmp)))
3079 continue;
3080 }
3081 }
3082 if (error)
3083 break;
3084 if (nfsvers == NFS_VER2) {
3085 tsiz -= len;
3086 continue;
3087 }
3088
3089 /* check for a short write */
3090 if (rlen < len) {
3091 backup = len - rlen;
3092 uio_pushback(uio, backup);
3093 len = rlen;
3094 }
3095
3096 /* return lowest commit level returned */
3097 if (commit < committed)
3098 committed = commit;
3099
3100 tsiz -= len;
3101
3102 /* check write verifier */
3103 if (!wverfset) {
3104 wverf = wverf2;
3105 wverfset = 1;
3106 } else if (wverf != wverf2) {
3107 /* verifier changed, so we need to restart all the writes */
3108 if (++vrestart > 100) {
3109 /* give up after too many restarts */
3110 error = EIO;
3111 break;
3112 }
3113 backup = totalsize - tsiz;
3114 uio_pushback(uio, backup);
3115 committed = NFS_WRITE_FILESYNC;
3116 wverfset = 0;
3117 tsiz = totalsize;
3118 }
3119 }
3120 if (wverfset && wverfp)
3121 *wverfp = wverf;
3122 *iomodep = committed;
3123 if (error)
3124 uio_setresid(uio, tsiz);
3125 FSDBG_BOT(537, np, committed, uio_resid(uio), error);
3126 return (error);
3127 }
3128
3129 int
3130 nfs3_write_rpc_async(
3131 nfsnode_t np,
3132 uio_t uio,
3133 size_t len,
3134 thread_t thd,
3135 kauth_cred_t cred,
3136 int iomode,
3137 struct nfsreq_cbinfo *cb,
3138 struct nfsreq **reqp)
3139 {
3140 struct nfsmount *nmp;
3141 mount_t mp;
3142 int error = 0, nfsvers;
3143 struct nfsm_chain nmreq;
3144
3145 nmp = NFSTONMP(np);
3146 if (!nmp)
3147 return (ENXIO);
3148 nfsvers = nmp->nm_vers;
3149
3150 /* for async mounts, don't bother sending sync write requests */
3151 if ((iomode != NFS_WRITE_UNSTABLE) && nfs_allow_async &&
3152 ((mp = NFSTOMP(np))) && (vfs_flags(mp) & MNT_ASYNC))
3153 iomode = NFS_WRITE_UNSTABLE;
3154
3155 nfsm_chain_null(&nmreq);
3156 nfsm_chain_build_alloc_init(error, &nmreq,
3157 NFSX_FH(nfsvers) + 5 * NFSX_UNSIGNED + nfsm_rndup(len));
3158 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
3159 if (nfsvers == NFS_VER3) {
3160 nfsm_chain_add_64(error, &nmreq, uio_offset(uio));
3161 nfsm_chain_add_32(error, &nmreq, len);
3162 nfsm_chain_add_32(error, &nmreq, iomode);
3163 } else {
3164 nfsm_chain_add_32(error, &nmreq, 0);
3165 nfsm_chain_add_32(error, &nmreq, uio_offset(uio));
3166 nfsm_chain_add_32(error, &nmreq, 0);
3167 }
3168 nfsm_chain_add_32(error, &nmreq, len);
3169 nfsmout_if(error);
3170 error = nfsm_chain_add_uio(&nmreq, uio, len);
3171 nfsm_chain_build_done(error, &nmreq);
3172 nfsmout_if(error);
3173 error = nfs_request_async(np, NULL, &nmreq, NFSPROC_WRITE, thd, cred, NULL, 0, cb, reqp);
3174 nfsmout:
3175 nfsm_chain_cleanup(&nmreq);
3176 return (error);
3177 }
3178
3179 int
3180 nfs3_write_rpc_async_finish(
3181 nfsnode_t np,
3182 struct nfsreq *req,
3183 int *iomodep,
3184 size_t *rlenp,
3185 uint64_t *wverfp)
3186 {
3187 struct nfsmount *nmp;
3188 int error = 0, lockerror = ENOENT, nfsvers, status;
3189 int updatemtime = 0, wccpostattr = 0, rlen, committed = NFS_WRITE_FILESYNC;
3190 u_int64_t xid, wverf;
3191 mount_t mp;
3192 struct nfsm_chain nmrep;
3193
3194 nmp = NFSTONMP(np);
3195 if (!nmp) {
3196 nfs_request_async_cancel(req);
3197 return (ENXIO);
3198 }
3199 nfsvers = nmp->nm_vers;
3200
3201 nfsm_chain_null(&nmrep);
3202
3203 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
3204 if (error == EINPROGRESS) /* async request restarted */
3205 return (error);
3206 nmp = NFSTONMP(np);
3207 if (!nmp)
3208 error = ENXIO;
3209 if (!error && (lockerror = nfs_node_lock(np)))
3210 error = lockerror;
3211 if (nfsvers == NFS_VER3) {
3212 struct timespec premtime = { 0, 0 };
3213 nfsm_chain_get_wcc_data(error, &nmrep, np, &premtime, &wccpostattr, &xid);
3214 if (nfstimespeccmp(&np->n_mtime, &premtime, ==))
3215 updatemtime = 1;
3216 if (!error)
3217 error = status;
3218 nfsm_chain_get_32(error, &nmrep, rlen);
3219 nfsmout_if(error);
3220 *rlenp = rlen;
3221 if (rlen <= 0)
3222 error = NFSERR_IO;
3223 nfsm_chain_get_32(error, &nmrep, committed);
3224 nfsm_chain_get_64(error, &nmrep, wverf);
3225 nfsmout_if(error);
3226 if (wverfp)
3227 *wverfp = wverf;
3228 lck_mtx_lock(&nmp->nm_lock);
3229 if (!(nmp->nm_state & NFSSTA_HASWRITEVERF)) {
3230 nmp->nm_verf = wverf;
3231 nmp->nm_state |= NFSSTA_HASWRITEVERF;
3232 } else if (nmp->nm_verf != wverf) {
3233 nmp->nm_verf = wverf;
3234 }
3235 lck_mtx_unlock(&nmp->nm_lock);
3236 } else {
3237 if (!error)
3238 error = status;
3239 nfsm_chain_loadattr(error, &nmrep, np, nfsvers, &xid);
3240 nfsmout_if(error);
3241 }
3242 if (updatemtime)
3243 NFS_CHANGED_UPDATE(nfsvers, np, &np->n_vattr);
3244 nfsmout:
3245 if (!lockerror)
3246 nfs_node_unlock(np);
3247 nfsm_chain_cleanup(&nmrep);
3248 if ((committed != NFS_WRITE_FILESYNC) && nfs_allow_async &&
3249 ((mp = NFSTOMP(np))) && (vfs_flags(mp) & MNT_ASYNC))
3250 committed = NFS_WRITE_FILESYNC;
3251 *iomodep = committed;
3252 return (error);
3253 }
3254
3255 /*
3256 * NFS mknod vnode op
3257 *
3258 * For NFS v2 this is a kludge. Use a create RPC but with the IFMT bits of the
3259 * mode set to specify the file type and the size field for rdev.
3260 */
3261 int
3262 nfs3_vnop_mknod(
3263 struct vnop_mknod_args /* {
3264 struct vnodeop_desc *a_desc;
3265 vnode_t a_dvp;
3266 vnode_t *a_vpp;
3267 struct componentname *a_cnp;
3268 struct vnode_attr *a_vap;
3269 vfs_context_t a_context;
3270 } */ *ap)
3271 {
3272 vnode_t dvp = ap->a_dvp;
3273 vnode_t *vpp = ap->a_vpp;
3274 struct componentname *cnp = ap->a_cnp;
3275 struct vnode_attr *vap = ap->a_vap;
3276 vfs_context_t ctx = ap->a_context;
3277 vnode_t newvp = NULL;
3278 nfsnode_t np = NULL;
3279 struct nfsmount *nmp;
3280 nfsnode_t dnp = VTONFS(dvp);
3281 struct nfs_vattr nvattr;
3282 fhandle_t fh;
3283 int error = 0, lockerror = ENOENT, busyerror = ENOENT, status, wccpostattr = 0;
3284 struct timespec premtime = { 0, 0 };
3285 u_int32_t rdev;
3286 u_int64_t xid, dxid;
3287 int nfsvers, gotuid, gotgid;
3288 struct nfsm_chain nmreq, nmrep;
3289 struct nfsreq rq, *req = &rq;
3290
3291 nmp = VTONMP(dvp);
3292 if (!nmp)
3293 return (ENXIO);
3294 nfsvers = nmp->nm_vers;
3295
3296 if (!VATTR_IS_ACTIVE(vap, va_type))
3297 return (EINVAL);
3298 if (vap->va_type == VCHR || vap->va_type == VBLK) {
3299 if (!VATTR_IS_ACTIVE(vap, va_rdev))
3300 return (EINVAL);
3301 rdev = vap->va_rdev;
3302 } else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
3303 rdev = 0xffffffff;
3304 else {
3305 return (ENOTSUP);
3306 }
3307 if ((nfsvers == NFS_VER2) && (cnp->cn_namelen > NFS_MAXNAMLEN))
3308 return (ENAMETOOLONG);
3309
3310 nfs_avoid_needless_id_setting_on_create(dnp, vap, ctx);
3311
3312 VATTR_SET_SUPPORTED(vap, va_mode);
3313 VATTR_SET_SUPPORTED(vap, va_uid);
3314 VATTR_SET_SUPPORTED(vap, va_gid);
3315 VATTR_SET_SUPPORTED(vap, va_data_size);
3316 VATTR_SET_SUPPORTED(vap, va_access_time);
3317 VATTR_SET_SUPPORTED(vap, va_modify_time);
3318 gotuid = VATTR_IS_ACTIVE(vap, va_uid);
3319 gotgid = VATTR_IS_ACTIVE(vap, va_gid);
3320
3321 nfsm_chain_null(&nmreq);
3322 nfsm_chain_null(&nmrep);
3323
3324 nfsm_chain_build_alloc_init(error, &nmreq,
3325 NFSX_FH(nfsvers) + 4 * NFSX_UNSIGNED +
3326 nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(nfsvers));
3327 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
3328 nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
3329 if (nfsvers == NFS_VER3) {
3330 nfsm_chain_add_32(error, &nmreq, vtonfs_type(vap->va_type, nfsvers));
3331 nfsm_chain_add_v3sattr(error, &nmreq, vap);
3332 if (vap->va_type == VCHR || vap->va_type == VBLK) {
3333 nfsm_chain_add_32(error, &nmreq, major(vap->va_rdev));
3334 nfsm_chain_add_32(error, &nmreq, minor(vap->va_rdev));
3335 }
3336 } else {
3337 nfsm_chain_add_v2sattr(error, &nmreq, vap, rdev);
3338 }
3339 nfsm_chain_build_done(error, &nmreq);
3340 if (!error)
3341 error = busyerror = nfs_node_set_busy(dnp, vfs_context_thread(ctx));
3342 nfsmout_if(error);
3343
3344 error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_MKNOD,
3345 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req);
3346 if (!error)
3347 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
3348
3349 if ((lockerror = nfs_node_lock(dnp)))
3350 error = lockerror;
3351 /* XXX no EEXIST kludge here? */
3352 dxid = xid;
3353 if (!error && !status) {
3354 if (dnp->n_flag & NNEGNCENTRIES) {
3355 dnp->n_flag &= ~NNEGNCENTRIES;
3356 cache_purge_negatives(dvp);
3357 }
3358 error = nfsm_chain_get_fh_attr(&nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr);
3359 }
3360 if (nfsvers == NFS_VER3)
3361 nfsm_chain_get_wcc_data(error, &nmrep, dnp, &premtime, &wccpostattr, &dxid);
3362 if (!error)
3363 error = status;
3364 nfsmout:
3365 nfsm_chain_cleanup(&nmreq);
3366 nfsm_chain_cleanup(&nmrep);
3367
3368 if (!lockerror) {
3369 dnp->n_flag |= NMODIFIED;
3370 /* if directory hadn't changed, update namecache mtime */
3371 if (nfstimespeccmp(&dnp->n_ncmtime, &premtime, ==))
3372 NFS_CHANGED_UPDATE_NC(nfsvers, dnp, &dnp->n_vattr);
3373 nfs_node_unlock(dnp);
3374 /* nfs_getattr() will check changed and purge caches */
3375 nfs_getattr(dnp, NULL, ctx, wccpostattr ? NGA_CACHED : NGA_UNCACHED);
3376 }
3377
3378 if (!error && fh.fh_len)
3379 error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, rq.r_auth, NG_MAKEENTRY, &np);
3380 if (!error && !np)
3381 error = nfs_lookitup(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &np);
3382 if (!error && np)
3383 newvp = NFSTOV(np);
3384 if (!busyerror)
3385 nfs_node_clear_busy(dnp);
3386
3387 if (!error && (gotuid || gotgid) &&
3388 (!newvp || nfs_getattrcache(np, &nvattr, 0) ||
3389 (gotuid && (nvattr.nva_uid != vap->va_uid)) ||
3390 (gotgid && (nvattr.nva_gid != vap->va_gid)))) {
3391 /* clear ID bits if server didn't use them (or we can't tell) */
3392 VATTR_CLEAR_SUPPORTED(vap, va_uid);
3393 VATTR_CLEAR_SUPPORTED(vap, va_gid);
3394 }
3395 if (error) {
3396 if (newvp) {
3397 nfs_node_unlock(np);
3398 vnode_put(newvp);
3399 }
3400 } else {
3401 *vpp = newvp;
3402 nfs_node_unlock(np);
3403 }
3404 return (error);
3405 }
3406
3407 static uint32_t create_verf;
3408 /*
3409 * NFS file create call
3410 */
3411 int
3412 nfs3_vnop_create(
3413 struct vnop_create_args /* {
3414 struct vnodeop_desc *a_desc;
3415 vnode_t a_dvp;
3416 vnode_t *a_vpp;
3417 struct componentname *a_cnp;
3418 struct vnode_attr *a_vap;
3419 vfs_context_t a_context;
3420 } */ *ap)
3421 {
3422 vfs_context_t ctx = ap->a_context;
3423 vnode_t dvp = ap->a_dvp;
3424 struct vnode_attr *vap = ap->a_vap;
3425 struct componentname *cnp = ap->a_cnp;
3426 struct nfs_vattr nvattr;
3427 fhandle_t fh;
3428 nfsnode_t np = NULL;
3429 struct nfsmount *nmp;
3430 nfsnode_t dnp = VTONFS(dvp);
3431 vnode_t newvp = NULL;
3432 int error = 0, lockerror = ENOENT, busyerror = ENOENT, status, wccpostattr = 0, fmode = 0;
3433 struct timespec premtime = { 0, 0 };
3434 int nfsvers, gotuid, gotgid;
3435 u_int64_t xid, dxid;
3436 uint32_t val;
3437 struct nfsm_chain nmreq, nmrep;
3438 struct nfsreq rq, *req = &rq;
3439 struct nfs_dulookup dul;
3440
3441 nmp = VTONMP(dvp);
3442 if (!nmp)
3443 return (ENXIO);
3444 nfsvers = nmp->nm_vers;
3445
3446 if ((nfsvers == NFS_VER2) && (cnp->cn_namelen > NFS_MAXNAMLEN))
3447 return (ENAMETOOLONG);
3448
3449 nfs_avoid_needless_id_setting_on_create(dnp, vap, ctx);
3450
3451 VATTR_SET_SUPPORTED(vap, va_mode);
3452 VATTR_SET_SUPPORTED(vap, va_uid);
3453 VATTR_SET_SUPPORTED(vap, va_gid);
3454 VATTR_SET_SUPPORTED(vap, va_data_size);
3455 VATTR_SET_SUPPORTED(vap, va_access_time);
3456 VATTR_SET_SUPPORTED(vap, va_modify_time);
3457 gotuid = VATTR_IS_ACTIVE(vap, va_uid);
3458 gotgid = VATTR_IS_ACTIVE(vap, va_gid);
3459
3460 if (vap->va_vaflags & VA_EXCLUSIVE) {
3461 fmode |= O_EXCL;
3462 if (!VATTR_IS_ACTIVE(vap, va_access_time) || !VATTR_IS_ACTIVE(vap, va_modify_time))
3463 vap->va_vaflags |= VA_UTIMES_NULL;
3464 }
3465
3466 again:
3467 error = busyerror = nfs_node_set_busy(dnp, vfs_context_thread(ctx));
3468 nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
3469
3470 nfsm_chain_null(&nmreq);
3471 nfsm_chain_null(&nmrep);
3472
3473 nfsm_chain_build_alloc_init(error, &nmreq,
3474 NFSX_FH(nfsvers) + 2 * NFSX_UNSIGNED +
3475 nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(nfsvers));
3476 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
3477 nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
3478 if (nfsvers == NFS_VER3) {
3479 if (fmode & O_EXCL) {
3480 nfsm_chain_add_32(error, &nmreq, NFS_CREATE_EXCLUSIVE);
3481 lck_rw_lock_shared(in_ifaddr_rwlock);
3482 if (!TAILQ_EMPTY(&in_ifaddrhead))
3483 val = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr.s_addr;
3484 else
3485 val = create_verf;
3486 lck_rw_done(in_ifaddr_rwlock);
3487 nfsm_chain_add_32(error, &nmreq, val);
3488 ++create_verf;
3489 nfsm_chain_add_32(error, &nmreq, create_verf);
3490 } else {
3491 nfsm_chain_add_32(error, &nmreq, NFS_CREATE_UNCHECKED);
3492 nfsm_chain_add_v3sattr(error, &nmreq, vap);
3493 }
3494 } else {
3495 nfsm_chain_add_v2sattr(error, &nmreq, vap, 0);
3496 }
3497 nfsm_chain_build_done(error, &nmreq);
3498 nfsmout_if(error);
3499
3500 error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_CREATE,
3501 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req);
3502 if (!error) {
3503 nfs_dulookup_start(&dul, dnp, ctx);
3504 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
3505 }
3506
3507 if ((lockerror = nfs_node_lock(dnp)))
3508 error = lockerror;
3509 dxid = xid;
3510 if (!error && !status) {
3511 if (dnp->n_flag & NNEGNCENTRIES) {
3512 dnp->n_flag &= ~NNEGNCENTRIES;
3513 cache_purge_negatives(dvp);
3514 }
3515 error = nfsm_chain_get_fh_attr(&nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr);
3516 }
3517 if (nfsvers == NFS_VER3)
3518 nfsm_chain_get_wcc_data(error, &nmrep, dnp, &premtime, &wccpostattr, &dxid);
3519 if (!error)
3520 error = status;
3521 nfsmout:
3522 nfsm_chain_cleanup(&nmreq);
3523 nfsm_chain_cleanup(&nmrep);
3524
3525 if (!lockerror) {
3526 dnp->n_flag |= NMODIFIED;
3527 /* if directory hadn't changed, update namecache mtime */
3528 if (nfstimespeccmp(&dnp->n_ncmtime, &premtime, ==))
3529 NFS_CHANGED_UPDATE_NC(nfsvers, dnp, &dnp->n_vattr);
3530 nfs_node_unlock(dnp);
3531 /* nfs_getattr() will check changed and purge caches */
3532 nfs_getattr(dnp, NULL, ctx, wccpostattr ? NGA_CACHED : NGA_UNCACHED);
3533 }
3534
3535 if (!error && fh.fh_len)
3536 error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, rq.r_auth, NG_MAKEENTRY, &np);
3537 if (!error && !np)
3538 error = nfs_lookitup(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &np);
3539 if (!error && np)
3540 newvp = NFSTOV(np);
3541
3542 nfs_dulookup_finish(&dul, dnp, ctx);
3543 if (!busyerror)
3544 nfs_node_clear_busy(dnp);
3545
3546 if (error) {
3547 if ((nfsvers == NFS_VER3) && (fmode & O_EXCL) && (error == NFSERR_NOTSUPP)) {
3548 fmode &= ~O_EXCL;
3549 goto again;
3550 }
3551 if (newvp) {
3552 nfs_node_unlock(np);
3553 vnode_put(newvp);
3554 }
3555 } else if ((nfsvers == NFS_VER3) && (fmode & O_EXCL)) {
3556 nfs_node_unlock(np);
3557 error = nfs3_setattr_rpc(np, vap, ctx);
3558 if (error && (gotuid || gotgid)) {
3559 /* it's possible the server didn't like our attempt to set IDs. */
3560 /* so, let's try it again without those */
3561 VATTR_CLEAR_ACTIVE(vap, va_uid);
3562 VATTR_CLEAR_ACTIVE(vap, va_gid);
3563 error = nfs3_setattr_rpc(np, vap, ctx);
3564 }
3565 if (error)
3566 vnode_put(newvp);
3567 else
3568 nfs_node_lock_force(np);
3569 }
3570 if (!error)
3571 *ap->a_vpp = newvp;
3572 if (!error && (gotuid || gotgid) &&
3573 (!newvp || nfs_getattrcache(np, &nvattr, 0) ||
3574 (gotuid && (nvattr.nva_uid != vap->va_uid)) ||
3575 (gotgid && (nvattr.nva_gid != vap->va_gid)))) {
3576 /* clear ID bits if server didn't use them (or we can't tell) */
3577 VATTR_CLEAR_SUPPORTED(vap, va_uid);
3578 VATTR_CLEAR_SUPPORTED(vap, va_gid);
3579 }
3580 if (!error)
3581 nfs_node_unlock(np);
3582 return (error);
3583 }
3584
3585 /*
3586 * NFS file remove call
3587 * To try and make NFS semantics closer to UFS semantics, a file that has
3588 * other processes using the vnode is renamed instead of removed and then
3589 * removed later on the last close.
3590 * - If vnode_isinuse()
3591 * If a rename is not already in the works
3592 * call nfs_sillyrename() to set it up
3593 * else
3594 * do the remove RPC
3595 */
3596 int
3597 nfs_vnop_remove(
3598 struct vnop_remove_args /* {
3599 struct vnodeop_desc *a_desc;
3600 vnode_t a_dvp;
3601 vnode_t a_vp;
3602 struct componentname *a_cnp;
3603 int a_flags;
3604 vfs_context_t a_context;
3605 } */ *ap)
3606 {
3607 vfs_context_t ctx = ap->a_context;
3608 vnode_t vp = ap->a_vp;
3609 vnode_t dvp = ap->a_dvp;
3610 struct componentname *cnp = ap->a_cnp;
3611 nfsnode_t dnp = VTONFS(dvp);
3612 nfsnode_t np = VTONFS(vp);
3613 int error = 0, nfsvers, namedattrs, inuse, gotattr = 0, flushed = 0, setsize = 0;
3614 struct nfs_vattr nvattr;
3615 struct nfsmount *nmp;
3616 struct nfs_dulookup dul;
3617
3618 /* XXX prevent removing a sillyrenamed file? */
3619
3620 nmp = NFSTONMP(dnp);
3621 if (!nmp)
3622 return (ENXIO);
3623 nfsvers = nmp->nm_vers;
3624 namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR);
3625
3626 again_relock:
3627 error = nfs_node_set_busy2(dnp, np, vfs_context_thread(ctx));
3628 if (error)
3629 return (error);
3630
3631 /* lock the node while we remove the file */
3632 lck_mtx_lock(nfs_node_hash_mutex);
3633 while (np->n_hflag & NHLOCKED) {
3634 np->n_hflag |= NHLOCKWANT;
3635 msleep(np, nfs_node_hash_mutex, PINOD, "nfs_remove", NULL);
3636 }
3637 np->n_hflag |= NHLOCKED;
3638 lck_mtx_unlock(nfs_node_hash_mutex);
3639
3640 if (!namedattrs)
3641 nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
3642 again:
3643 inuse = vnode_isinuse(vp, 0);
3644 if ((ap->a_flags & VNODE_REMOVE_NODELETEBUSY) && inuse) {
3645 /* Caller requested Carbon delete semantics, but file is busy */
3646 error = EBUSY;
3647 goto out;
3648 }
3649 if (inuse && !gotattr) {
3650 if (nfs_getattr(np, &nvattr, ctx, NGA_CACHED))
3651 nvattr.nva_nlink = 1;
3652 gotattr = 1;
3653 goto again;
3654 }
3655 if (!inuse || (np->n_sillyrename && (nvattr.nva_nlink > 1))) {
3656
3657 if (!inuse && !flushed) { /* flush all the buffers first */
3658 /* unlock the node */
3659 lck_mtx_lock(nfs_node_hash_mutex);
3660 np->n_hflag &= ~NHLOCKED;
3661 if (np->n_hflag & NHLOCKWANT) {
3662 np->n_hflag &= ~NHLOCKWANT;
3663 wakeup(np);
3664 }
3665 lck_mtx_unlock(nfs_node_hash_mutex);
3666 nfs_node_clear_busy2(dnp, np);
3667 error = nfs_vinvalbuf(vp, V_SAVE, ctx, 1);
3668 FSDBG(260, np, np->n_size, np->n_vattr.nva_size, 0xf00d0011);
3669 flushed = 1;
3670 if (error == EINTR) {
3671 nfs_node_lock_force(np);
3672 NATTRINVALIDATE(np);
3673 nfs_node_unlock(np);
3674 return (error);
3675 }
3676 if (!namedattrs)
3677 nfs_dulookup_finish(&dul, dnp, ctx);
3678 goto again_relock;
3679 }
3680
3681 if ((nmp->nm_vers >= NFS_VER4) && (np->n_openflags & N_DELEG_MASK))
3682 nfs4_delegation_return(np, 0, vfs_context_thread(ctx), vfs_context_ucred(ctx));
3683
3684 /*
3685 * Purge the name cache so that the chance of a lookup for
3686 * the name succeeding while the remove is in progress is
3687 * minimized.
3688 */
3689 nfs_name_cache_purge(dnp, np, cnp, ctx);
3690
3691 if (!namedattrs)
3692 nfs_dulookup_start(&dul, dnp, ctx);
3693
3694 /* Do the rpc */
3695 error = nmp->nm_funcs->nf_remove_rpc(dnp, cnp->cn_nameptr, cnp->cn_namelen,
3696 vfs_context_thread(ctx), vfs_context_ucred(ctx));
3697
3698 /*
3699 * Kludge City: If the first reply to the remove rpc is lost..
3700 * the reply to the retransmitted request will be ENOENT
3701 * since the file was in fact removed
3702 * Therefore, we cheat and return success.
3703 */
3704 if (error == ENOENT)
3705 error = 0;
3706
3707 if (!error && !inuse && !np->n_sillyrename) {
3708 /*
3709 * removal succeeded, it's not in use, and not silly renamed so
3710 * remove nfsnode from hash now so we can't accidentally find it
3711 * again if another object gets created with the same filehandle
3712 * before this vnode gets reclaimed
3713 */
3714 lck_mtx_lock(nfs_node_hash_mutex);
3715 if (np->n_hflag & NHHASHED) {
3716 LIST_REMOVE(np, n_hash);
3717 np->n_hflag &= ~NHHASHED;
3718 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e);
3719 }
3720 lck_mtx_unlock(nfs_node_hash_mutex);
3721 /* clear flags now: won't get nfs_vnop_inactive for recycled vnode */
3722 /* clear all flags other than these */
3723 nfs_node_lock_force(np);
3724 np->n_flag &= (NMODIFIED);
3725 NATTRINVALIDATE(np);
3726 nfs_node_unlock(np);
3727 vnode_recycle(vp);
3728 setsize = 1;
3729 } else {
3730 nfs_node_lock_force(np);
3731 NATTRINVALIDATE(np);
3732 nfs_node_unlock(np);
3733 }
3734 } else if (!np->n_sillyrename) {
3735 if (!namedattrs)
3736 nfs_dulookup_start(&dul, dnp, ctx);
3737 error = nfs_sillyrename(dnp, np, cnp, ctx);
3738 nfs_node_lock_force(np);
3739 NATTRINVALIDATE(np);
3740 nfs_node_unlock(np);
3741 } else {
3742 nfs_node_lock_force(np);
3743 NATTRINVALIDATE(np);
3744 nfs_node_unlock(np);
3745 if (!namedattrs)
3746 nfs_dulookup_start(&dul, dnp, ctx);
3747 }
3748
3749 /* nfs_getattr() will check changed and purge caches */
3750 nfs_getattr(dnp, NULL, ctx, NGA_CACHED);
3751 if (!namedattrs)
3752 nfs_dulookup_finish(&dul, dnp, ctx);
3753 out:
3754 /* unlock the node */
3755 lck_mtx_lock(nfs_node_hash_mutex);
3756 np->n_hflag &= ~NHLOCKED;
3757 if (np->n_hflag & NHLOCKWANT) {
3758 np->n_hflag &= ~NHLOCKWANT;
3759 wakeup(np);
3760 }
3761 lck_mtx_unlock(nfs_node_hash_mutex);
3762 nfs_node_clear_busy2(dnp, np);
3763 if (setsize)
3764 ubc_setsize(vp, 0);
3765 return (error);
3766 }
3767
3768 /*
3769 * NFS silly-renamed file removal function called from nfs_vnop_inactive
3770 */
3771 int
3772 nfs_removeit(struct nfs_sillyrename *nsp)
3773 {
3774 struct nfsmount *nmp = NFSTONMP(nsp->nsr_dnp);
3775 if (!nmp)
3776 return (ENXIO);
3777 return nmp->nm_funcs->nf_remove_rpc(nsp->nsr_dnp, nsp->nsr_name, nsp->nsr_namlen, NULL, nsp->nsr_cred);
3778 }
3779
3780 /*
3781 * NFS remove rpc, called from nfs_remove() and nfs_removeit().
3782 */
3783 int
3784 nfs3_remove_rpc(
3785 nfsnode_t dnp,
3786 char *name,
3787 int namelen,
3788 thread_t thd,
3789 kauth_cred_t cred)
3790 {
3791 int error = 0, lockerror = ENOENT, status, wccpostattr = 0;
3792 struct timespec premtime = { 0, 0 };
3793 struct nfsmount *nmp;
3794 int nfsvers;
3795 u_int64_t xid;
3796 struct nfsm_chain nmreq, nmrep;
3797
3798 nmp = NFSTONMP(dnp);
3799 if (!nmp)
3800 return (ENXIO);
3801 nfsvers = nmp->nm_vers;
3802 if ((nfsvers == NFS_VER2) && (namelen > NFS_MAXNAMLEN))
3803 return (ENAMETOOLONG);
3804
3805 nfsm_chain_null(&nmreq);
3806 nfsm_chain_null(&nmrep);
3807
3808 nfsm_chain_build_alloc_init(error, &nmreq,
3809 NFSX_FH(nfsvers) + NFSX_UNSIGNED + nfsm_rndup(namelen));
3810 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
3811 nfsm_chain_add_name(error, &nmreq, name, namelen, nmp);
3812 nfsm_chain_build_done(error, &nmreq);
3813 nfsmout_if(error);
3814
3815 error = nfs_request2(dnp, NULL, &nmreq, NFSPROC_REMOVE, thd, cred, NULL, 0, &nmrep, &xid, &status);
3816
3817 if ((lockerror = nfs_node_lock(dnp)))
3818 error = lockerror;
3819 if (nfsvers == NFS_VER3)
3820 nfsm_chain_get_wcc_data(error, &nmrep, dnp, &premtime, &wccpostattr, &xid);
3821 nfsmout_if(error);
3822 dnp->n_flag |= NMODIFIED;
3823 /* if directory hadn't changed, update namecache mtime */
3824 if (nfstimespeccmp(&dnp->n_ncmtime, &premtime, ==))
3825 NFS_CHANGED_UPDATE_NC(nfsvers, dnp, &dnp->n_vattr);
3826 if (!wccpostattr)
3827 NATTRINVALIDATE(dnp);
3828 if (!error)
3829 error = status;
3830 nfsmout:
3831 if (!lockerror)
3832 nfs_node_unlock(dnp);
3833 nfsm_chain_cleanup(&nmreq);
3834 nfsm_chain_cleanup(&nmrep);
3835 return (error);
3836 }
3837
3838 /*
3839 * NFS file rename call
3840 */
3841 int
3842 nfs_vnop_rename(
3843 struct vnop_rename_args /* {
3844 struct vnodeop_desc *a_desc;
3845 vnode_t a_fdvp;
3846 vnode_t a_fvp;
3847 struct componentname *a_fcnp;
3848 vnode_t a_tdvp;
3849 vnode_t a_tvp;
3850 struct componentname *a_tcnp;
3851 vfs_context_t a_context;
3852 } */ *ap)
3853 {
3854 vfs_context_t ctx = ap->a_context;
3855 vnode_t fdvp = ap->a_fdvp;
3856 vnode_t fvp = ap->a_fvp;
3857 vnode_t tdvp = ap->a_tdvp;
3858 vnode_t tvp = ap->a_tvp;
3859 nfsnode_t fdnp, fnp, tdnp, tnp;
3860 struct componentname *tcnp = ap->a_tcnp;
3861 struct componentname *fcnp = ap->a_fcnp;
3862 int error, nfsvers, inuse=0, tvprecycle=0, locked=0;
3863 mount_t fmp, tdmp, tmp;
3864 struct nfs_vattr nvattr;
3865 struct nfsmount *nmp;
3866
3867 fdnp = VTONFS(fdvp);
3868 fnp = VTONFS(fvp);
3869 tdnp = VTONFS(tdvp);
3870 tnp = tvp ? VTONFS(tvp) : NULL;
3871
3872 nmp = NFSTONMP(fdnp);
3873 if (!nmp)
3874 return (ENXIO);
3875 nfsvers = nmp->nm_vers;
3876
3877 error = nfs_node_set_busy4(fdnp, fnp, tdnp, tnp, vfs_context_thread(ctx));
3878 if (error)
3879 return (error);
3880
3881 if (tvp && (tvp != fvp)) {
3882 /* lock the node while we rename over the existing file */
3883 lck_mtx_lock(nfs_node_hash_mutex);
3884 while (tnp->n_hflag & NHLOCKED) {
3885 tnp->n_hflag |= NHLOCKWANT;
3886 msleep(tnp, nfs_node_hash_mutex, PINOD, "nfs_rename", NULL);
3887 }
3888 tnp->n_hflag |= NHLOCKED;
3889 lck_mtx_unlock(nfs_node_hash_mutex);
3890 locked = 1;
3891 }
3892
3893 /* Check for cross-device rename */
3894 fmp = vnode_mount(fvp);
3895 tmp = tvp ? vnode_mount(tvp) : NULL;
3896 tdmp = vnode_mount(tdvp);
3897 if ((fmp != tdmp) || (tvp && (fmp != tmp))) {
3898 error = EXDEV;
3899 goto out;
3900 }
3901
3902 /* XXX prevent renaming from/over a sillyrenamed file? */
3903
3904 /*
3905 * If the tvp exists and is in use, sillyrename it before doing the
3906 * rename of the new file over it.
3907 * XXX Can't sillyrename a directory.
3908 * Don't sillyrename if source and target are same vnode (hard
3909 * links or case-variants)
3910 */
3911 if (tvp && (tvp != fvp))
3912 inuse = vnode_isinuse(tvp, 0);
3913 if (inuse && !tnp->n_sillyrename && (vnode_vtype(tvp) != VDIR)) {
3914 error = nfs_sillyrename(tdnp, tnp, tcnp, ctx);
3915 if (error) {
3916 /* sillyrename failed. Instead of pressing on, return error */
3917 goto out; /* should not be ENOENT. */
3918 } else {
3919 /* sillyrename succeeded.*/
3920 tvp = NULL;
3921 }
3922 } else if (tvp && (nmp->nm_vers >= NFS_VER4) && (tnp->n_openflags & N_DELEG_MASK)) {
3923 nfs4_delegation_return(tnp, 0, vfs_context_thread(ctx), vfs_context_ucred(ctx));
3924 }
3925
3926 error = nmp->nm_funcs->nf_rename_rpc(fdnp, fcnp->cn_nameptr, fcnp->cn_namelen,
3927 tdnp, tcnp->cn_nameptr, tcnp->cn_namelen, ctx);
3928
3929 /*
3930 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
3931 */
3932 if (error == ENOENT)
3933 error = 0;
3934
3935 if (tvp && (tvp != fvp) && !tnp->n_sillyrename) {
3936 nfs_node_lock_force(tnp);
3937 tvprecycle = (!error && !vnode_isinuse(tvp, 0) &&
3938 (nfs_getattrcache(tnp, &nvattr, 0) || (nvattr.nva_nlink == 1)));
3939 nfs_node_unlock(tnp);
3940 lck_mtx_lock(nfs_node_hash_mutex);
3941 if (tvprecycle && (tnp->n_hflag & NHHASHED)) {
3942 /*
3943 * remove nfsnode from hash now so we can't accidentally find it
3944 * again if another object gets created with the same filehandle
3945 * before this vnode gets reclaimed
3946 */
3947 LIST_REMOVE(tnp, n_hash);
3948 tnp->n_hflag &= ~NHHASHED;
3949 FSDBG(266, 0, tnp, tnp->n_flag, 0xb1eb1e);
3950 }
3951 lck_mtx_unlock(nfs_node_hash_mutex);
3952 }
3953
3954 /* purge the old name cache entries and enter the new one */
3955 nfs_name_cache_purge(fdnp, fnp, fcnp, ctx);
3956 if (tvp) {
3957 nfs_name_cache_purge(tdnp, tnp, tcnp, ctx);
3958 if (tvprecycle) {
3959 /* clear flags now: won't get nfs_vnop_inactive for recycled vnode */
3960 /* clear all flags other than these */
3961 nfs_node_lock_force(tnp);
3962 tnp->n_flag &= (NMODIFIED);
3963 nfs_node_unlock(tnp);
3964 vnode_recycle(tvp);
3965 }
3966 }
3967 if (!error) {
3968 nfs_node_lock_force(tdnp);
3969 if (tdnp->n_flag & NNEGNCENTRIES) {
3970 tdnp->n_flag &= ~NNEGNCENTRIES;
3971 cache_purge_negatives(tdvp);
3972 }
3973 nfs_node_unlock(tdnp);
3974 nfs_node_lock_force(fnp);
3975 cache_enter(tdvp, fvp, tcnp);
3976 if (tdvp != fdvp) { /* update parent pointer */
3977 if (fnp->n_parent && !vnode_get(fnp->n_parent)) {
3978 /* remove ref from old parent */
3979 vnode_rele(fnp->n_parent);
3980 vnode_put(fnp->n_parent);
3981 }
3982 fnp->n_parent = tdvp;
3983 if (tdvp && !vnode_get(tdvp)) {
3984 /* add ref to new parent */
3985 vnode_ref(tdvp);
3986 vnode_put(tdvp);
3987 } else {
3988 fnp->n_parent = NULL;
3989 }
3990 }
3991 nfs_node_unlock(fnp);
3992 }
3993 out:
3994 /* nfs_getattr() will check changed and purge caches */
3995 nfs_getattr(fdnp, NULL, ctx, NGA_CACHED);
3996 nfs_getattr(tdnp, NULL, ctx, NGA_CACHED);
3997 if (locked) {
3998 /* unlock node */
3999 lck_mtx_lock(nfs_node_hash_mutex);
4000 tnp->n_hflag &= ~NHLOCKED;
4001 if (tnp->n_hflag & NHLOCKWANT) {
4002 tnp->n_hflag &= ~NHLOCKWANT;
4003 wakeup(tnp);
4004 }
4005 lck_mtx_unlock(nfs_node_hash_mutex);
4006 }
4007 nfs_node_clear_busy4(fdnp, fnp, tdnp, tnp);
4008 return (error);
4009 }
4010
4011 /*
4012 * Do an NFS rename rpc. Called from nfs_vnop_rename() and nfs_sillyrename().
4013 */
4014 int
4015 nfs3_rename_rpc(
4016 nfsnode_t fdnp,
4017 char *fnameptr,
4018 int fnamelen,
4019 nfsnode_t tdnp,
4020 char *tnameptr,
4021 int tnamelen,
4022 vfs_context_t ctx)
4023 {
4024 int error = 0, lockerror = ENOENT, status, fwccpostattr = 0, twccpostattr = 0;
4025 struct timespec fpremtime = { 0, 0 }, tpremtime = { 0, 0 };
4026 struct nfsmount *nmp;
4027 int nfsvers;
4028 u_int64_t xid, txid;
4029 struct nfsm_chain nmreq, nmrep;
4030
4031 nmp = NFSTONMP(fdnp);
4032 if (!nmp)
4033 return (ENXIO);
4034 nfsvers = nmp->nm_vers;
4035 if ((nfsvers == NFS_VER2) &&
4036 ((fnamelen > NFS_MAXNAMLEN) || (tnamelen > NFS_MAXNAMLEN)))
4037 return (ENAMETOOLONG);
4038
4039 nfsm_chain_null(&nmreq);
4040 nfsm_chain_null(&nmrep);
4041
4042 nfsm_chain_build_alloc_init(error, &nmreq,
4043 (NFSX_FH(nfsvers) + NFSX_UNSIGNED) * 2 +
4044 nfsm_rndup(fnamelen) + nfsm_rndup(tnamelen));
4045 nfsm_chain_add_fh(error, &nmreq, nfsvers, fdnp->n_fhp, fdnp->n_fhsize);
4046 nfsm_chain_add_name(error, &nmreq, fnameptr, fnamelen, nmp);
4047 nfsm_chain_add_fh(error, &nmreq, nfsvers, tdnp->n_fhp, tdnp->n_fhsize);
4048 nfsm_chain_add_name(error, &nmreq, tnameptr, tnamelen, nmp);
4049 nfsm_chain_build_done(error, &nmreq);
4050 nfsmout_if(error);
4051
4052 error = nfs_request(fdnp, NULL, &nmreq, NFSPROC_RENAME, ctx, NULL, &nmrep, &xid, &status);
4053
4054 if ((lockerror = nfs_node_lock2(fdnp, tdnp)))
4055 error = lockerror;
4056 if (nfsvers == NFS_VER3) {
4057 txid = xid;
4058 nfsm_chain_get_wcc_data(error, &nmrep, fdnp, &fpremtime, &fwccpostattr, &xid);
4059 nfsm_chain_get_wcc_data(error, &nmrep, tdnp, &tpremtime, &twccpostattr, &txid);
4060 }
4061 if (!error)
4062 error = status;
4063 nfsmout:
4064 nfsm_chain_cleanup(&nmreq);
4065 nfsm_chain_cleanup(&nmrep);
4066 if (!lockerror) {
4067 fdnp->n_flag |= NMODIFIED;
4068 /* if directory hadn't changed, update namecache mtime */
4069 if (nfstimespeccmp(&fdnp->n_ncmtime, &fpremtime, ==))
4070 NFS_CHANGED_UPDATE_NC(nfsvers, fdnp, &fdnp->n_vattr);
4071 if (!fwccpostattr)
4072 NATTRINVALIDATE(fdnp);
4073 tdnp->n_flag |= NMODIFIED;
4074 /* if directory hadn't changed, update namecache mtime */
4075 if (nfstimespeccmp(&tdnp->n_ncmtime, &tpremtime, ==))
4076 NFS_CHANGED_UPDATE_NC(nfsvers, tdnp, &tdnp->n_vattr);
4077 if (!twccpostattr)
4078 NATTRINVALIDATE(tdnp);
4079 nfs_node_unlock2(fdnp, tdnp);
4080 }
4081 return (error);
4082 }
4083
4084 /*
4085 * NFS hard link create call
4086 */
4087 int
4088 nfs3_vnop_link(
4089 struct vnop_link_args /* {
4090 struct vnodeop_desc *a_desc;
4091 vnode_t a_vp;
4092 vnode_t a_tdvp;
4093 struct componentname *a_cnp;
4094 vfs_context_t a_context;
4095 } */ *ap)
4096 {
4097 vfs_context_t ctx = ap->a_context;
4098 vnode_t vp = ap->a_vp;
4099 vnode_t tdvp = ap->a_tdvp;
4100 struct componentname *cnp = ap->a_cnp;
4101 int error = 0, lockerror = ENOENT, status, wccpostattr = 0, attrflag = 0;
4102 struct timespec premtime = { 0, 0 };
4103 struct nfsmount *nmp;
4104 nfsnode_t np = VTONFS(vp);
4105 nfsnode_t tdnp = VTONFS(tdvp);
4106 int nfsvers;
4107 u_int64_t xid, txid;
4108 struct nfsm_chain nmreq, nmrep;
4109
4110 if (vnode_mount(vp) != vnode_mount(tdvp))
4111 return (EXDEV);
4112
4113 nmp = VTONMP(vp);
4114 if (!nmp)
4115 return (ENXIO);
4116 nfsvers = nmp->nm_vers;
4117 if ((nfsvers == NFS_VER2) && (cnp->cn_namelen > NFS_MAXNAMLEN))
4118 return (ENAMETOOLONG);
4119
4120 /*
4121 * Push all writes to the server, so that the attribute cache
4122 * doesn't get "out of sync" with the server.
4123 * XXX There should be a better way!
4124 */
4125 nfs_flush(np, MNT_WAIT, vfs_context_thread(ctx), V_IGNORE_WRITEERR);
4126
4127 error = nfs_node_set_busy2(tdnp, np, vfs_context_thread(ctx));
4128 if (error)
4129 return (error);
4130
4131 nfsm_chain_null(&nmreq);
4132 nfsm_chain_null(&nmrep);
4133
4134 nfsm_chain_build_alloc_init(error, &nmreq,
4135 NFSX_FH(nfsvers)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
4136 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
4137 nfsm_chain_add_fh(error, &nmreq, nfsvers, tdnp->n_fhp, tdnp->n_fhsize);
4138 nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
4139 nfsm_chain_build_done(error, &nmreq);
4140 nfsmout_if(error);
4141 error = nfs_request(np, NULL, &nmreq, NFSPROC_LINK, ctx, NULL, &nmrep, &xid, &status);
4142
4143 if ((lockerror = nfs_node_lock2(tdnp, np))) {
4144 error = lockerror;
4145 goto nfsmout;
4146 }
4147 if (nfsvers == NFS_VER3) {
4148 txid = xid;
4149 nfsm_chain_postop_attr_update_flag(error, &nmrep, np, attrflag, &xid);
4150 nfsm_chain_get_wcc_data(error, &nmrep, tdnp, &premtime, &wccpostattr, &txid);
4151 }
4152 if (!error)
4153 error = status;
4154 nfsmout:
4155 nfsm_chain_cleanup(&nmreq);
4156 nfsm_chain_cleanup(&nmrep);
4157 if (!lockerror) {
4158 if (!attrflag)
4159 NATTRINVALIDATE(np);
4160 tdnp->n_flag |= NMODIFIED;
4161 /* if directory hadn't changed, update namecache mtime */
4162 if (nfstimespeccmp(&tdnp->n_ncmtime, &premtime, ==))
4163 NFS_CHANGED_UPDATE_NC(nfsvers, tdnp, &tdnp->n_vattr);
4164 if (!wccpostattr)
4165 NATTRINVALIDATE(tdnp);
4166 if (!error && (tdnp->n_flag & NNEGNCENTRIES)) {
4167 tdnp->n_flag &= ~NNEGNCENTRIES;
4168 cache_purge_negatives(tdvp);
4169 }
4170 nfs_node_unlock2(tdnp, np);
4171 }
4172 nfs_node_clear_busy2(tdnp, np);
4173 /*
4174 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
4175 */
4176 if (error == EEXIST)
4177 error = 0;
4178 return (error);
4179 }
4180
4181 /*
4182 * NFS symbolic link create call
4183 */
4184 int
4185 nfs3_vnop_symlink(
4186 struct vnop_symlink_args /* {
4187 struct vnodeop_desc *a_desc;
4188 vnode_t a_dvp;
4189 vnode_t *a_vpp;
4190 struct componentname *a_cnp;
4191 struct vnode_attr *a_vap;
4192 char *a_target;
4193 vfs_context_t a_context;
4194 } */ *ap)
4195 {
4196 vfs_context_t ctx = ap->a_context;
4197 vnode_t dvp = ap->a_dvp;
4198 struct vnode_attr *vap = ap->a_vap;
4199 struct componentname *cnp = ap->a_cnp;
4200 struct nfs_vattr nvattr;
4201 fhandle_t fh;
4202 int slen, error = 0, lockerror = ENOENT, busyerror = ENOENT, status, wccpostattr = 0;
4203 struct timespec premtime = { 0, 0 };
4204 vnode_t newvp = NULL;
4205 int nfsvers, gotuid, gotgid;
4206 u_int64_t xid, dxid;
4207 nfsnode_t np = NULL;
4208 nfsnode_t dnp = VTONFS(dvp);
4209 struct nfsmount *nmp;
4210 struct nfsm_chain nmreq, nmrep;
4211 struct nfsreq rq, *req = &rq;
4212 struct nfs_dulookup dul;
4213
4214 nmp = VTONMP(dvp);
4215 if (!nmp)
4216 return (ENXIO);
4217 nfsvers = nmp->nm_vers;
4218
4219 slen = strlen(ap->a_target);
4220 if ((nfsvers == NFS_VER2) &&
4221 ((cnp->cn_namelen > NFS_MAXNAMLEN) || (slen > NFS_MAXPATHLEN)))
4222 return (ENAMETOOLONG);
4223
4224 nfs_avoid_needless_id_setting_on_create(dnp, vap, ctx);
4225
4226 VATTR_SET_SUPPORTED(vap, va_mode);
4227 VATTR_SET_SUPPORTED(vap, va_uid);
4228 VATTR_SET_SUPPORTED(vap, va_gid);
4229 VATTR_SET_SUPPORTED(vap, va_data_size);
4230 VATTR_SET_SUPPORTED(vap, va_access_time);
4231 VATTR_SET_SUPPORTED(vap, va_modify_time);
4232 gotuid = VATTR_IS_ACTIVE(vap, va_uid);
4233 gotgid = VATTR_IS_ACTIVE(vap, va_gid);
4234
4235 error = busyerror = nfs_node_set_busy(dnp, vfs_context_thread(ctx));
4236 nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
4237
4238 nfsm_chain_null(&nmreq);
4239 nfsm_chain_null(&nmrep);
4240
4241 nfsm_chain_build_alloc_init(error, &nmreq,
4242 NFSX_FH(nfsvers) + 2 * NFSX_UNSIGNED +
4243 nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(nfsvers));
4244 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
4245 nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
4246 if (nfsvers == NFS_VER3)
4247 nfsm_chain_add_v3sattr(error, &nmreq, vap);
4248 nfsm_chain_add_name(error, &nmreq, ap->a_target, slen, nmp);
4249 if (nfsvers == NFS_VER2)
4250 nfsm_chain_add_v2sattr(error, &nmreq, vap, -1);
4251 nfsm_chain_build_done(error, &nmreq);
4252 nfsmout_if(error);
4253
4254 error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_SYMLINK,
4255 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req);
4256 if (!error) {
4257 nfs_dulookup_start(&dul, dnp, ctx);
4258 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
4259 }
4260
4261 if ((lockerror = nfs_node_lock(dnp)))
4262 error = lockerror;
4263 dxid = xid;
4264 if (!error && !status) {
4265 if (dnp->n_flag & NNEGNCENTRIES) {
4266 dnp->n_flag &= ~NNEGNCENTRIES;
4267 cache_purge_negatives(dvp);
4268 }
4269 if (nfsvers == NFS_VER3)
4270 error = nfsm_chain_get_fh_attr(&nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr);
4271 else
4272 fh.fh_len = 0;
4273 }
4274 if (nfsvers == NFS_VER3)
4275 nfsm_chain_get_wcc_data(error, &nmrep, dnp, &premtime, &wccpostattr, &dxid);
4276 if (!error)
4277 error = status;
4278 nfsmout:
4279 nfsm_chain_cleanup(&nmreq);
4280 nfsm_chain_cleanup(&nmrep);
4281
4282 if (!lockerror) {
4283 dnp->n_flag |= NMODIFIED;
4284 /* if directory hadn't changed, update namecache mtime */
4285 if (nfstimespeccmp(&dnp->n_ncmtime, &premtime, ==))
4286 NFS_CHANGED_UPDATE_NC(nfsvers, dnp, &dnp->n_vattr);
4287 nfs_node_unlock(dnp);
4288 /* nfs_getattr() will check changed and purge caches */
4289 nfs_getattr(dnp, NULL, ctx, wccpostattr ? NGA_CACHED : NGA_UNCACHED);
4290 }
4291
4292 if (!error && fh.fh_len)
4293 error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, rq.r_auth, NG_MAKEENTRY, &np);
4294 if (!error && np)
4295 newvp = NFSTOV(np);
4296
4297 nfs_dulookup_finish(&dul, dnp, ctx);
4298
4299 /*
4300 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
4301 * if we can succeed in looking up the symlink.
4302 */
4303 if ((error == EEXIST) || (!error && !newvp)) {
4304 if (newvp) {
4305 nfs_node_unlock(np);
4306 vnode_put(newvp);
4307 newvp = NULL;
4308 }
4309 error = nfs_lookitup(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &np);
4310 if (!error) {
4311 newvp = NFSTOV(np);
4312 if (vnode_vtype(newvp) != VLNK)
4313 error = EEXIST;
4314 }
4315 }
4316 if (!busyerror)
4317 nfs_node_clear_busy(dnp);
4318 if (!error && (gotuid || gotgid) &&
4319 (!newvp || nfs_getattrcache(np, &nvattr, 0) ||
4320 (gotuid && (nvattr.nva_uid != vap->va_uid)) ||
4321 (gotgid && (nvattr.nva_gid != vap->va_gid)))) {
4322 /* clear ID bits if server didn't use them (or we can't tell) */
4323 VATTR_CLEAR_SUPPORTED(vap, va_uid);
4324 VATTR_CLEAR_SUPPORTED(vap, va_gid);
4325 }
4326 if (error) {
4327 if (newvp) {
4328 nfs_node_unlock(np);
4329 vnode_put(newvp);
4330 }
4331 } else {
4332 nfs_node_unlock(np);
4333 *ap->a_vpp = newvp;
4334 }
4335 return (error);
4336 }
4337
4338 /*
4339 * NFS make dir call
4340 */
4341 int
4342 nfs3_vnop_mkdir(
4343 struct vnop_mkdir_args /* {
4344 struct vnodeop_desc *a_desc;
4345 vnode_t a_dvp;
4346 vnode_t *a_vpp;
4347 struct componentname *a_cnp;
4348 struct vnode_attr *a_vap;
4349 vfs_context_t a_context;
4350 } */ *ap)
4351 {
4352 vfs_context_t ctx = ap->a_context;
4353 vnode_t dvp = ap->a_dvp;
4354 struct vnode_attr *vap = ap->a_vap;
4355 struct componentname *cnp = ap->a_cnp;
4356 struct nfs_vattr nvattr;
4357 nfsnode_t np = NULL;
4358 struct nfsmount *nmp;
4359 nfsnode_t dnp = VTONFS(dvp);
4360 vnode_t newvp = NULL;
4361 int error = 0, lockerror = ENOENT, busyerror = ENOENT, status, wccpostattr = 0;
4362 struct timespec premtime = { 0, 0 };
4363 int nfsvers, gotuid, gotgid;
4364 u_int64_t xid, dxid;
4365 fhandle_t fh;
4366 struct nfsm_chain nmreq, nmrep;
4367 struct nfsreq rq, *req = &rq;
4368 struct nfs_dulookup dul;
4369
4370 nmp = VTONMP(dvp);
4371 if (!nmp)
4372 return (ENXIO);
4373 nfsvers = nmp->nm_vers;
4374 if ((nfsvers == NFS_VER2) && (cnp->cn_namelen > NFS_MAXNAMLEN))
4375 return (ENAMETOOLONG);
4376
4377 nfs_avoid_needless_id_setting_on_create(dnp, vap, ctx);
4378
4379 VATTR_SET_SUPPORTED(vap, va_mode);
4380 VATTR_SET_SUPPORTED(vap, va_uid);
4381 VATTR_SET_SUPPORTED(vap, va_gid);
4382 VATTR_SET_SUPPORTED(vap, va_data_size);
4383 VATTR_SET_SUPPORTED(vap, va_access_time);
4384 VATTR_SET_SUPPORTED(vap, va_modify_time);
4385 gotuid = VATTR_IS_ACTIVE(vap, va_uid);
4386 gotgid = VATTR_IS_ACTIVE(vap, va_gid);
4387
4388 error = busyerror = nfs_node_set_busy(dnp, vfs_context_thread(ctx));
4389 nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
4390
4391 nfsm_chain_null(&nmreq);
4392 nfsm_chain_null(&nmrep);
4393
4394 nfsm_chain_build_alloc_init(error, &nmreq,
4395 NFSX_FH(nfsvers) + NFSX_UNSIGNED +
4396 nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(nfsvers));
4397 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
4398 nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
4399 if (nfsvers == NFS_VER3)
4400 nfsm_chain_add_v3sattr(error, &nmreq, vap);
4401 else
4402 nfsm_chain_add_v2sattr(error, &nmreq, vap, -1);
4403 nfsm_chain_build_done(error, &nmreq);
4404 nfsmout_if(error);
4405
4406 error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_MKDIR,
4407 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req);
4408 if (!error) {
4409 nfs_dulookup_start(&dul, dnp, ctx);
4410 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
4411 }
4412
4413 if ((lockerror = nfs_node_lock(dnp)))
4414 error = lockerror;
4415 dxid = xid;
4416 if (!error && !status) {
4417 if (dnp->n_flag & NNEGNCENTRIES) {
4418 dnp->n_flag &= ~NNEGNCENTRIES;
4419 cache_purge_negatives(dvp);
4420 }
4421 error = nfsm_chain_get_fh_attr(&nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr);
4422 }
4423 if (nfsvers == NFS_VER3)
4424 nfsm_chain_get_wcc_data(error, &nmrep, dnp, &premtime, &wccpostattr, &dxid);
4425 if (!error)
4426 error = status;
4427 nfsmout:
4428 nfsm_chain_cleanup(&nmreq);
4429 nfsm_chain_cleanup(&nmrep);
4430
4431 if (!lockerror) {
4432 dnp->n_flag |= NMODIFIED;
4433 /* if directory hadn't changed, update namecache mtime */
4434 if (nfstimespeccmp(&dnp->n_ncmtime, &premtime, ==))
4435 NFS_CHANGED_UPDATE_NC(nfsvers, dnp, &dnp->n_vattr);
4436 nfs_node_unlock(dnp);
4437 /* nfs_getattr() will check changed and purge caches */
4438 nfs_getattr(dnp, NULL, ctx, wccpostattr ? NGA_CACHED : NGA_UNCACHED);
4439 }
4440
4441 if (!error && fh.fh_len)
4442 error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len, &nvattr, &xid, rq.r_auth, NG_MAKEENTRY, &np);
4443 if (!error && np)
4444 newvp = NFSTOV(np);
4445
4446 nfs_dulookup_finish(&dul, dnp, ctx);
4447
4448 /*
4449 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
4450 * if we can succeed in looking up the directory.
4451 */
4452 if ((error == EEXIST) || (!error && !newvp)) {
4453 if (newvp) {
4454 nfs_node_unlock(np);
4455 vnode_put(newvp);
4456 newvp = NULL;
4457 }
4458 error = nfs_lookitup(dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx, &np);
4459 if (!error) {
4460 newvp = NFSTOV(np);
4461 if (vnode_vtype(newvp) != VDIR)
4462 error = EEXIST;
4463 }
4464 }
4465 if (!busyerror)
4466 nfs_node_clear_busy(dnp);
4467 if (!error && (gotuid || gotgid) &&
4468 (!newvp || nfs_getattrcache(np, &nvattr, 0) ||
4469 (gotuid && (nvattr.nva_uid != vap->va_uid)) ||
4470 (gotgid && (nvattr.nva_gid != vap->va_gid)))) {
4471 /* clear ID bits if server didn't use them (or we can't tell) */
4472 VATTR_CLEAR_SUPPORTED(vap, va_uid);
4473 VATTR_CLEAR_SUPPORTED(vap, va_gid);
4474 }
4475 if (error) {
4476 if (newvp) {
4477 nfs_node_unlock(np);
4478 vnode_put(newvp);
4479 }
4480 } else {
4481 nfs_node_unlock(np);
4482 *ap->a_vpp = newvp;
4483 }
4484 return (error);
4485 }
4486
4487 /*
4488 * NFS remove directory call
4489 */
4490 int
4491 nfs3_vnop_rmdir(
4492 struct vnop_rmdir_args /* {
4493 struct vnodeop_desc *a_desc;
4494 vnode_t a_dvp;
4495 vnode_t a_vp;
4496 struct componentname *a_cnp;
4497 vfs_context_t a_context;
4498 } */ *ap)
4499 {
4500 vfs_context_t ctx = ap->a_context;
4501 vnode_t vp = ap->a_vp;
4502 vnode_t dvp = ap->a_dvp;
4503 struct componentname *cnp = ap->a_cnp;
4504 int error = 0, lockerror = ENOENT, status, wccpostattr = 0;
4505 struct timespec premtime = { 0, 0 };
4506 struct nfsmount *nmp;
4507 nfsnode_t np = VTONFS(vp);
4508 nfsnode_t dnp = VTONFS(dvp);
4509 int nfsvers;
4510 u_int64_t xid;
4511 struct nfsm_chain nmreq, nmrep;
4512 struct nfsreq rq, *req = &rq;
4513 struct nfs_dulookup dul;
4514
4515 nmp = VTONMP(vp);
4516 if (!nmp)
4517 return (ENXIO);
4518 nfsvers = nmp->nm_vers;
4519 if ((nfsvers == NFS_VER2) && (cnp->cn_namelen > NFS_MAXNAMLEN))
4520 return (ENAMETOOLONG);
4521
4522 if ((error = nfs_node_set_busy2(dnp, np, vfs_context_thread(ctx))))
4523 return (error);
4524
4525 nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx);
4526
4527 nfsm_chain_null(&nmreq);
4528 nfsm_chain_null(&nmrep);
4529
4530 nfsm_chain_build_alloc_init(error, &nmreq,
4531 NFSX_FH(nfsvers) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
4532 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
4533 nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp);
4534 nfsm_chain_build_done(error, &nmreq);
4535 nfsmout_if(error);
4536
4537 error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_RMDIR,
4538 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req);
4539 if (!error) {
4540 nfs_dulookup_start(&dul, dnp, ctx);
4541 error = nfs_request_async_finish(req, &nmrep, &xid, &status);
4542 }
4543
4544 if ((lockerror = nfs_node_lock(dnp)))
4545 error = lockerror;
4546 if (nfsvers == NFS_VER3)
4547 nfsm_chain_get_wcc_data(error, &nmrep, dnp, &premtime, &wccpostattr, &xid);
4548 if (!error)
4549 error = status;
4550 nfsmout:
4551 nfsm_chain_cleanup(&nmreq);
4552 nfsm_chain_cleanup(&nmrep);
4553
4554 if (!lockerror) {
4555 dnp->n_flag |= NMODIFIED;
4556 /* if directory hadn't changed, update namecache mtime */
4557 if (nfstimespeccmp(&dnp->n_ncmtime, &premtime, ==))
4558 NFS_CHANGED_UPDATE_NC(nfsvers, dnp, &dnp->n_vattr);
4559 nfs_node_unlock(dnp);
4560 nfs_name_cache_purge(dnp, np, cnp, ctx);
4561 /* nfs_getattr() will check changed and purge caches */
4562 nfs_getattr(dnp, NULL, ctx, wccpostattr ? NGA_CACHED : NGA_UNCACHED);
4563 }
4564 nfs_dulookup_finish(&dul, dnp, ctx);
4565 nfs_node_clear_busy2(dnp, np);
4566
4567 /*
4568 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
4569 */
4570 if (error == ENOENT)
4571 error = 0;
4572 if (!error) {
4573 /*
4574 * remove nfsnode from hash now so we can't accidentally find it
4575 * again if another object gets created with the same filehandle
4576 * before this vnode gets reclaimed
4577 */
4578 lck_mtx_lock(nfs_node_hash_mutex);
4579 if (np->n_hflag & NHHASHED) {
4580 LIST_REMOVE(np, n_hash);
4581 np->n_hflag &= ~NHHASHED;
4582 FSDBG(266, 0, np, np->n_flag, 0xb1eb1e);
4583 }
4584 lck_mtx_unlock(nfs_node_hash_mutex);
4585 }
4586 return (error);
4587 }
4588
4589 /*
4590 * NFS readdir call
4591 *
4592 * The incoming "offset" is a directory cookie indicating where in the
4593 * directory entries should be read from. A zero cookie means start at
4594 * the beginning of the directory. Any other cookie will be a cookie
4595 * returned from the server.
4596 *
4597 * Using that cookie, determine which buffer (and where in that buffer)
4598 * to start returning entries from. Buffer logical block numbers are
4599 * the cookies they start at. If a buffer is found that is not full,
4600 * call into the bio/RPC code to fill it. The RPC code will probably
4601 * fill several buffers (dropping the first, requiring a re-get).
4602 *
4603 * When done copying entries to the buffer, set the offset to the current
4604 * entry's cookie and enter that cookie in the cookie cache.
4605 *
4606 * Note: because the getdirentries(2) API returns a long-typed offset,
4607 * the incoming offset is a potentially truncated cookie (ptc).
4608 * The cookie matching code is aware of this and will fall back to
4609 * matching only 32 bits of the cookie.
4610 */
4611 int
4612 nfs_vnop_readdir(
4613 struct vnop_readdir_args /* {
4614 struct vnodeop_desc *a_desc;
4615 vnode_t a_vp;
4616 struct uio *a_uio;
4617 int a_flags;
4618 int *a_eofflag;
4619 int *a_numdirent;
4620 vfs_context_t a_context;
4621 } */ *ap)
4622 {
4623 vfs_context_t ctx = ap->a_context;
4624 vnode_t dvp = ap->a_vp;
4625 nfsnode_t dnp = VTONFS(dvp);
4626 struct nfsmount *nmp;
4627 uio_t uio = ap->a_uio;
4628 int error, nfsvers, extended, numdirent, bigcookies, ptc, done;
4629 uint16_t i, iptc, rlen, nlen;
4630 uint64_t cookie, nextcookie, lbn = 0;
4631 struct nfsbuf *bp = NULL;
4632 struct nfs_dir_buf_header *ndbhp;
4633 struct direntry *dp, *dpptc;
4634 struct dirent dent;
4635 char *cp = NULL;
4636 thread_t thd;
4637
4638 nmp = VTONMP(dvp);
4639 if (!nmp)
4640 return (ENXIO);
4641 nfsvers = nmp->nm_vers;
4642 bigcookies = (nmp->nm_state & NFSSTA_BIGCOOKIES);
4643 extended = (ap->a_flags & VNODE_READDIR_EXTENDED);
4644
4645 if (vnode_vtype(dvp) != VDIR)
4646 return (EPERM);
4647
4648 if (ap->a_eofflag)
4649 *ap->a_eofflag = 0;
4650
4651 if (uio_resid(uio) == 0)
4652 return (0);
4653
4654 if ((nfsvers >= NFS_VER4) && (dnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER)) {
4655 /* trigger directories should never be read, return nothing */
4656 return (0);
4657 }
4658
4659 thd = vfs_context_thread(ctx);
4660 numdirent = done = 0;
4661 nextcookie = uio_offset(uio);
4662 ptc = bigcookies && NFS_DIR_COOKIE_POTENTIALLY_TRUNCATED(nextcookie);
4663
4664 if ((error = nfs_node_lock(dnp)))
4665 goto out;
4666
4667 if (dnp->n_flag & NNEEDINVALIDATE) {
4668 dnp->n_flag &= ~NNEEDINVALIDATE;
4669 nfs_invaldir(dnp);
4670 nfs_node_unlock(dnp);
4671 error = nfs_vinvalbuf(dvp, 0, ctx, 1);
4672 if (!error)
4673 error = nfs_node_lock(dnp);
4674 if (error)
4675 goto out;
4676 }
4677
4678 /*
4679 * check for need to invalidate when (re)starting at beginning
4680 */
4681 if (!nextcookie) {
4682 if (dnp->n_flag & NMODIFIED) {
4683 nfs_invaldir(dnp);
4684 nfs_node_unlock(dnp);
4685 if ((error = nfs_vinvalbuf(dvp, 0, ctx, 1)))
4686 goto out;
4687 } else {
4688 nfs_node_unlock(dnp);
4689 }
4690 /* nfs_getattr() will check changed and purge caches */
4691 if ((error = nfs_getattr(dnp, NULL, ctx, NGA_UNCACHED)))
4692 goto out;
4693 } else {
4694 nfs_node_unlock(dnp);
4695 }
4696
4697 error = nfs_dir_cookie_to_lbn(dnp, nextcookie, &ptc, &lbn);
4698 if (error) {
4699 if (error < 0) { /* just hit EOF cookie */
4700 done = 1;
4701 error = 0;
4702 }
4703 if (ap->a_eofflag)
4704 *ap->a_eofflag = 1;
4705 }
4706
4707 while (!error && !done) {
4708 OSAddAtomic(1, &nfsstats.biocache_readdirs);
4709 cookie = nextcookie;
4710 getbuffer:
4711 error = nfs_buf_get(dnp, lbn, NFS_DIRBLKSIZ, thd, NBLK_READ, &bp);
4712 if (error)
4713 goto out;
4714 ndbhp = (struct nfs_dir_buf_header*)bp->nb_data;
4715 if (!ISSET(bp->nb_flags, NB_CACHE) || !ISSET(ndbhp->ndbh_flags, NDB_FULL)) {
4716 if (!ISSET(bp->nb_flags, NB_CACHE)) { /* initialize the buffer */
4717 ndbhp->ndbh_flags = 0;
4718 ndbhp->ndbh_count = 0;
4719 ndbhp->ndbh_entry_end = sizeof(*ndbhp);
4720 ndbhp->ndbh_ncgen = dnp->n_ncgen;
4721 }
4722 error = nfs_buf_readdir(bp, ctx);
4723 if (error == NFSERR_DIRBUFDROPPED)
4724 goto getbuffer;
4725 if (error)
4726 nfs_buf_release(bp, 1);
4727 if (error && (error != ENXIO) && (error != ETIMEDOUT) && (error != EINTR) && (error != ERESTART)) {
4728 if (!nfs_node_lock(dnp)) {
4729 nfs_invaldir(dnp);
4730 nfs_node_unlock(dnp);
4731 }
4732 nfs_vinvalbuf(dvp, 0, ctx, 1);
4733 if (error == NFSERR_BAD_COOKIE)
4734 error = ENOENT;
4735 }
4736 if (error)
4737 goto out;
4738 }
4739
4740 /* find next entry to return */
4741 dp = NFS_DIR_BUF_FIRST_DIRENTRY(bp);
4742 i = 0;
4743 if ((lbn != cookie) && !(ptc && NFS_DIR_COOKIE_SAME32(lbn, cookie))) {
4744 dpptc = NULL;
4745 iptc = 0;
4746 for (; (i < ndbhp->ndbh_count) && (cookie != dp->d_seekoff); i++) {
4747 if (ptc && !dpptc && NFS_DIR_COOKIE_SAME32(cookie, dp->d_seekoff)) {
4748 iptc = i;
4749 dpptc = dp;
4750 }
4751 nextcookie = dp->d_seekoff;
4752 dp = NFS_DIRENTRY_NEXT(dp);
4753 }
4754 if ((i == ndbhp->ndbh_count) && dpptc) {
4755 i = iptc;
4756 dp = dpptc;
4757 }
4758 if (i < ndbhp->ndbh_count) {
4759 nextcookie = dp->d_seekoff;
4760 dp = NFS_DIRENTRY_NEXT(dp);
4761 i++;
4762 }
4763 }
4764 ptc = 0; /* only have to deal with ptc on first cookie */
4765
4766 /* return as many entries as we can */
4767 for (; i < ndbhp->ndbh_count; i++) {
4768 if (extended) {
4769 rlen = dp->d_reclen;
4770 cp = (char*)dp;
4771 } else {
4772 if (!cp) {
4773 cp = (char*)&dent;
4774 bzero(cp, sizeof(dent));
4775 }
4776 if (dp->d_namlen > (sizeof(dent.d_name) - 1))
4777 nlen = sizeof(dent.d_name) - 1;
4778 else
4779 nlen = dp->d_namlen;
4780 rlen = NFS_DIRENT_LEN(nlen);
4781 dent.d_reclen = rlen;
4782 dent.d_ino = dp->d_ino;
4783 dent.d_type = dp->d_type;
4784 dent.d_namlen = nlen;
4785 strlcpy(dent.d_name, dp->d_name, nlen + 1);
4786 }
4787 /* check that the record fits */
4788 if (rlen > uio_resid(uio)) {
4789 done = 1;
4790 break;
4791 }
4792 if ((error = uiomove(cp, rlen, uio)))
4793 break;
4794 numdirent++;
4795 nextcookie = dp->d_seekoff;
4796 dp = NFS_DIRENTRY_NEXT(dp);
4797 }
4798
4799 if (i == ndbhp->ndbh_count) {
4800 /* hit end of buffer, move to next buffer */
4801 lbn = nextcookie;
4802 /* if we also hit EOF, we're done */
4803 if (ISSET(ndbhp->ndbh_flags, NDB_EOF)) {
4804 done = 1;
4805 if (ap->a_eofflag)
4806 *ap->a_eofflag = 1;
4807 }
4808 }
4809 if (!error)
4810 uio_setoffset(uio, nextcookie);
4811 if (!error && !done && (nextcookie == cookie)) {
4812 printf("nfs readdir cookie didn't change 0x%llx, %d/%d\n", cookie, i, ndbhp->ndbh_count);
4813 error = EIO;
4814 }
4815 nfs_buf_release(bp, 1);
4816 }
4817
4818 if (!error)
4819 nfs_dir_cookie_cache(dnp, nextcookie, lbn);
4820
4821 if (ap->a_numdirent)
4822 *ap->a_numdirent = numdirent;
4823 out:
4824 return (error);
4825 }
4826
4827
4828 /*
4829 * Invalidate cached directory information, except for the actual directory
4830 * blocks (which are invalidated separately).
4831 */
4832 void
4833 nfs_invaldir(nfsnode_t dnp)
4834 {
4835 if (vnode_vtype(NFSTOV(dnp)) != VDIR)
4836 return;
4837 dnp->n_eofcookie = 0;
4838 dnp->n_cookieverf = 0;
4839 if (!dnp->n_cookiecache)
4840 return;
4841 dnp->n_cookiecache->free = 0;
4842 dnp->n_cookiecache->mru = -1;
4843 memset(dnp->n_cookiecache->next, -1, NFSNUMCOOKIES);
4844 }
4845
4846 /*
4847 * calculate how much space is available for additional directory entries.
4848 */
4849 uint32_t
4850 nfs_dir_buf_freespace(struct nfsbuf *bp, int rdirplus)
4851 {
4852 struct nfs_dir_buf_header *ndbhp = (struct nfs_dir_buf_header*)bp->nb_data;
4853 uint32_t space;
4854
4855 if (!ndbhp)
4856 return (0);
4857 space = bp->nb_bufsize - ndbhp->ndbh_entry_end;
4858 if (rdirplus)
4859 space -= ndbhp->ndbh_count * sizeof(struct nfs_vattr);
4860 return (space);
4861 }
4862
4863 /*
4864 * add/update a cookie->lbn entry in the directory cookie cache
4865 */
4866 void
4867 nfs_dir_cookie_cache(nfsnode_t dnp, uint64_t cookie, uint64_t lbn)
4868 {
4869 struct nfsdmap *ndcc;
4870 int8_t i, prev;
4871
4872 if (!cookie)
4873 return;
4874
4875 if (nfs_node_lock(dnp))
4876 return;
4877
4878 if (cookie == dnp->n_eofcookie) { /* EOF cookie */
4879 nfs_node_unlock(dnp);
4880 return;
4881 }
4882
4883 ndcc = dnp->n_cookiecache;
4884 if (!ndcc) {
4885 /* allocate the cookie cache structure */
4886 MALLOC_ZONE(dnp->n_cookiecache, struct nfsdmap *,
4887 sizeof(struct nfsdmap), M_NFSDIROFF, M_WAITOK);
4888 if (!dnp->n_cookiecache) {
4889 nfs_node_unlock(dnp);
4890 return;
4891 }
4892 ndcc = dnp->n_cookiecache;
4893 ndcc->free = 0;
4894 ndcc->mru = -1;
4895 memset(ndcc->next, -1, NFSNUMCOOKIES);
4896 }
4897
4898 /*
4899 * Search the list for this cookie.
4900 * Keep track of previous and last entries.
4901 */
4902 prev = -1;
4903 i = ndcc->mru;
4904 while ((i != -1) && (cookie != ndcc->cookies[i].key)) {
4905 if (ndcc->next[i] == -1) /* stop on last entry so we can reuse */
4906 break;
4907 prev = i;
4908 i = ndcc->next[i];
4909 }
4910 if ((i != -1) && (cookie == ndcc->cookies[i].key)) {
4911 /* found it, remove from list */
4912 if (prev != -1)
4913 ndcc->next[prev] = ndcc->next[i];
4914 else
4915 ndcc->mru = ndcc->next[i];
4916 } else {
4917 /* not found, use next free entry or reuse last entry */
4918 if (ndcc->free != NFSNUMCOOKIES)
4919 i = ndcc->free++;
4920 else
4921 ndcc->next[prev] = -1;
4922 ndcc->cookies[i].key = cookie;
4923 ndcc->cookies[i].lbn = lbn;
4924 }
4925 /* insert cookie at head of MRU list */
4926 ndcc->next[i] = ndcc->mru;
4927 ndcc->mru = i;
4928 nfs_node_unlock(dnp);
4929 }
4930
4931 /*
4932 * Try to map the given directory cookie to a directory buffer (return lbn).
4933 * If we have a possibly truncated cookie (ptc), check for 32-bit matches too.
4934 */
4935 int
4936 nfs_dir_cookie_to_lbn(nfsnode_t dnp, uint64_t cookie, int *ptc, uint64_t *lbnp)
4937 {
4938 struct nfsdmap *ndcc = dnp->n_cookiecache;
4939 int8_t eofptc, found;
4940 int i, iptc;
4941 struct nfsmount *nmp;
4942 struct nfsbuf *bp, *lastbp;
4943 struct nfsbuflists blist;
4944 struct direntry *dp, *dpptc;
4945 struct nfs_dir_buf_header *ndbhp;
4946
4947 if (!cookie) { /* initial cookie */
4948 *lbnp = 0;
4949 *ptc = 0;
4950 return (0);
4951 }
4952
4953 if (nfs_node_lock(dnp))
4954 return (ENOENT);
4955
4956 if (cookie == dnp->n_eofcookie) { /* EOF cookie */
4957 nfs_node_unlock(dnp);
4958 OSAddAtomic(1, &nfsstats.direofcache_hits);
4959 *ptc = 0;
4960 return (-1);
4961 }
4962 /* note if cookie is a 32-bit match with the EOF cookie */
4963 eofptc = *ptc ? NFS_DIR_COOKIE_SAME32(cookie, dnp->n_eofcookie) : 0;
4964 iptc = -1;
4965
4966 /* search the list for the cookie */
4967 for (i = ndcc ? ndcc->mru : -1; i >= 0; i = ndcc->next[i]) {
4968 if (ndcc->cookies[i].key == cookie) {
4969 /* found a match for this cookie */
4970 *lbnp = ndcc->cookies[i].lbn;
4971 nfs_node_unlock(dnp);
4972 OSAddAtomic(1, &nfsstats.direofcache_hits);
4973 *ptc = 0;
4974 return (0);
4975 }
4976 /* check for 32-bit match */
4977 if (*ptc && (iptc == -1) && NFS_DIR_COOKIE_SAME32(ndcc->cookies[i].key, cookie))
4978 iptc = i;
4979 }
4980 /* exact match not found */
4981 if (eofptc) {
4982 /* but 32-bit match hit the EOF cookie */
4983 nfs_node_unlock(dnp);
4984 OSAddAtomic(1, &nfsstats.direofcache_hits);
4985 return (-1);
4986 }
4987 if (iptc >= 0) {
4988 /* but 32-bit match got a hit */
4989 *lbnp = ndcc->cookies[iptc].lbn;
4990 nfs_node_unlock(dnp);
4991 OSAddAtomic(1, &nfsstats.direofcache_hits);
4992 return (0);
4993 }
4994 nfs_node_unlock(dnp);
4995
4996 /*
4997 * No match found in the cookie cache... hmm...
4998 * Let's search the directory's buffers for the cookie.
4999 */
5000 nmp = NFSTONMP(dnp);
5001 if (!nmp)
5002 return (ENXIO);
5003 dpptc = NULL;
5004 found = 0;
5005
5006 lck_mtx_lock(nfs_buf_mutex);
5007 /*
5008 * Scan the list of buffers, keeping them in order.
5009 * Note that itercomplete inserts each of the remaining buffers
5010 * into the head of list (thus reversing the elements). So, we
5011 * make sure to iterate through all buffers, inserting them after
5012 * each other, to keep them in order.
5013 * Also note: the LIST_INSERT_AFTER(lastbp) is only safe because
5014 * we don't drop nfs_buf_mutex.
5015 */
5016 if (!nfs_buf_iterprepare(dnp, &blist, NBI_CLEAN)) {
5017 lastbp = NULL;
5018 while ((bp = LIST_FIRST(&blist))) {
5019 LIST_REMOVE(bp, nb_vnbufs);
5020 if (!lastbp)
5021 LIST_INSERT_HEAD(&dnp->n_cleanblkhd, bp, nb_vnbufs);
5022 else
5023 LIST_INSERT_AFTER(lastbp, bp, nb_vnbufs);
5024 lastbp = bp;
5025 if (found)
5026 continue;
5027 nfs_buf_refget(bp);
5028 if (nfs_buf_acquire(bp, NBAC_NOWAIT, 0, 0)) {
5029 /* just skip this buffer */
5030 nfs_buf_refrele(bp);
5031 continue;
5032 }
5033 nfs_buf_refrele(bp);
5034
5035 /* scan the buffer for the cookie */
5036 ndbhp = (struct nfs_dir_buf_header*)bp->nb_data;
5037 dp = NFS_DIR_BUF_FIRST_DIRENTRY(bp);
5038 dpptc = NULL;
5039 for (i=0; (i < ndbhp->ndbh_count) && (cookie != dp->d_seekoff); i++) {
5040 if (*ptc && !dpptc && NFS_DIR_COOKIE_SAME32(cookie, dp->d_seekoff)) {
5041 dpptc = dp;
5042 iptc = i;
5043 }
5044 dp = NFS_DIRENTRY_NEXT(dp);
5045 }
5046 if ((i == ndbhp->ndbh_count) && dpptc) {
5047 /* found only a PTC match */
5048 dp = dpptc;
5049 i = iptc;
5050 } else if (i < ndbhp->ndbh_count) {
5051 *ptc = 0;
5052 }
5053 if (i < (ndbhp->ndbh_count-1)) {
5054 /* next entry is *in* this buffer: return this block */
5055 *lbnp = bp->nb_lblkno;
5056 found = 1;
5057 } else if (i == (ndbhp->ndbh_count-1)) {
5058 /* next entry refers to *next* buffer: return next block */
5059 *lbnp = dp->d_seekoff;
5060 found = 1;
5061 }
5062 nfs_buf_drop(bp);
5063 }
5064 nfs_buf_itercomplete(dnp, &blist, NBI_CLEAN);
5065 }
5066 lck_mtx_unlock(nfs_buf_mutex);
5067 if (found) {
5068 OSAddAtomic(1, &nfsstats.direofcache_hits);
5069 return (0);
5070 }
5071
5072 /* still not found... oh well, just start a new block */
5073 *lbnp = cookie;
5074 OSAddAtomic(1, &nfsstats.direofcache_misses);
5075 return (0);
5076 }
5077
5078 /*
5079 * scan a directory buffer for the given name
5080 * Returns: ESRCH if not found, ENOENT if found invalid, 0 if found
5081 * Note: should only be called with RDIRPLUS directory buffers
5082 */
5083
5084 #define NDBS_PURGE 1
5085 #define NDBS_UPDATE 2
5086
5087 int
5088 nfs_dir_buf_search(
5089 struct nfsbuf *bp,
5090 struct componentname *cnp,
5091 fhandle_t *fhp,
5092 struct nfs_vattr *nvap,
5093 uint64_t *xidp,
5094 time_t *attrstampp,
5095 daddr64_t *nextlbnp,
5096 int flags)
5097 {
5098 struct direntry *dp;
5099 struct nfs_dir_buf_header *ndbhp;
5100 struct nfs_vattr *nvattrp;
5101 daddr64_t nextlbn = 0;
5102 int i, error = ESRCH, fhlen;
5103
5104 /* scan the buffer for the name */
5105 ndbhp = (struct nfs_dir_buf_header*)bp->nb_data;
5106 dp = NFS_DIR_BUF_FIRST_DIRENTRY(bp);
5107 for (i=0; i < ndbhp->ndbh_count; i++) {
5108 nextlbn = dp->d_seekoff;
5109 if ((cnp->cn_namelen == dp->d_namlen) && !strcmp(cnp->cn_nameptr, dp->d_name)) {
5110 fhlen = dp->d_name[dp->d_namlen+1];
5111 nvattrp = NFS_DIR_BUF_NVATTR(bp, i);
5112 if ((ndbhp->ndbh_ncgen != bp->nb_np->n_ncgen) || (fhp->fh_len == 0) ||
5113 (nvattrp->nva_type == VNON) || (nvattrp->nva_fileid == 0)) {
5114 /* entry is not valid */
5115 error = ENOENT;
5116 break;
5117 }
5118 if (flags == NDBS_PURGE) {
5119 dp->d_fileno = 0;
5120 bzero(nvattrp, sizeof(*nvattrp));
5121 error = ENOENT;
5122 break;
5123 }
5124 if (flags == NDBS_UPDATE) {
5125 /* update direntry's attrs if fh matches */
5126 if ((fhp->fh_len == fhlen) && !bcmp(&dp->d_name[dp->d_namlen+2], fhp->fh_data, fhlen)) {
5127 bcopy(nvap, nvattrp, sizeof(*nvap));
5128 dp->d_fileno = nvattrp->nva_fileid;
5129 nvattrp->nva_fileid = *xidp;
5130 *(time_t*)(&dp->d_name[dp->d_namlen+2+fhp->fh_len]) = *attrstampp;
5131 }
5132 error = 0;
5133 break;
5134 }
5135 /* copy out fh, attrs, attrstamp, and xid */
5136 fhp->fh_len = fhlen;
5137 bcopy(&dp->d_name[dp->d_namlen+2], fhp->fh_data, MAX(fhp->fh_len, (int)sizeof(fhp->fh_data)));
5138 *attrstampp = *(time_t*)(&dp->d_name[dp->d_namlen+2+fhp->fh_len]);
5139 bcopy(nvattrp, nvap, sizeof(*nvap));
5140 *xidp = nvap->nva_fileid;
5141 nvap->nva_fileid = dp->d_fileno;
5142 error = 0;
5143 break;
5144 }
5145 dp = NFS_DIRENTRY_NEXT(dp);
5146 }
5147 if (nextlbnp)
5148 *nextlbnp = nextlbn;
5149 return (error);
5150 }
5151
5152 /*
5153 * Look up a name in a directory's buffers.
5154 * Note: should only be called with RDIRPLUS directory buffers
5155 */
5156 int
5157 nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cnp, vfs_context_t ctx, int purge)
5158 {
5159 nfsnode_t newnp;
5160 struct nfsmount *nmp;
5161 int error = 0, i, found = 0, count = 0;
5162 u_int64_t xid;
5163 struct nfs_vattr nvattr;
5164 fhandle_t fh;
5165 time_t attrstamp = 0;
5166 thread_t thd = vfs_context_thread(ctx);
5167 struct nfsbuf *bp, *lastbp, *foundbp;
5168 struct nfsbuflists blist;
5169 daddr64_t lbn, nextlbn;
5170 int dotunder = (cnp->cn_namelen > 2) && (cnp->cn_nameptr[0] == '.') && (cnp->cn_nameptr[1] == '_');
5171
5172 if (!(nmp = NFSTONMP(dnp)))
5173 return (ENXIO);
5174 if (!purge)
5175 *npp = NULL;
5176
5177 /* first check most recent buffer (and next one too) */
5178 lbn = dnp->n_lastdbl;
5179 for (i=0; i < 2; i++) {
5180 if ((error = nfs_buf_get(dnp, lbn, NFS_DIRBLKSIZ, thd, NBLK_READ|NBLK_ONLYVALID, &bp)))
5181 return (error);
5182 if (!bp)
5183 break;
5184 count++;
5185 error = nfs_dir_buf_search(bp, cnp, &fh, &nvattr, &xid, &attrstamp, &nextlbn, purge ? NDBS_PURGE : 0);
5186 nfs_buf_release(bp, 0);
5187 if (error == ESRCH) {
5188 error = 0;
5189 } else {
5190 found = 1;
5191 break;
5192 }
5193 lbn = nextlbn;
5194 }
5195
5196 lck_mtx_lock(nfs_buf_mutex);
5197 if (found) {
5198 dnp->n_lastdbl = lbn;
5199 goto done;
5200 }
5201
5202 /*
5203 * Scan the list of buffers, keeping them in order.
5204 * Note that itercomplete inserts each of the remaining buffers
5205 * into the head of list (thus reversing the elements). So, we
5206 * make sure to iterate through all buffers, inserting them after
5207 * each other, to keep them in order.
5208 * Also note: the LIST_INSERT_AFTER(lastbp) is only safe because
5209 * we don't drop nfs_buf_mutex.
5210 */
5211 if (!nfs_buf_iterprepare(dnp, &blist, NBI_CLEAN)) {
5212 lastbp = foundbp = NULL;
5213 while ((bp = LIST_FIRST(&blist))) {
5214 LIST_REMOVE(bp, nb_vnbufs);
5215 if (!lastbp)
5216 LIST_INSERT_HEAD(&dnp->n_cleanblkhd, bp, nb_vnbufs);
5217 else
5218 LIST_INSERT_AFTER(lastbp, bp, nb_vnbufs);
5219 lastbp = bp;
5220 if (error || found)
5221 continue;
5222 if (!purge && dotunder && (count > 100)) /* don't waste too much time looking for ._ files */
5223 continue;
5224 nfs_buf_refget(bp);
5225 lbn = bp->nb_lblkno;
5226 if (nfs_buf_acquire(bp, NBAC_NOWAIT, 0, 0)) {
5227 /* just skip this buffer */
5228 nfs_buf_refrele(bp);
5229 continue;
5230 }
5231 nfs_buf_refrele(bp);
5232 count++;
5233 error = nfs_dir_buf_search(bp, cnp, &fh, &nvattr, &xid, &attrstamp, NULL, purge ? NDBS_PURGE : 0);
5234 if (error == ESRCH) {
5235 error = 0;
5236 } else {
5237 found = 1;
5238 foundbp = bp;
5239 }
5240 nfs_buf_drop(bp);
5241 }
5242 if (found) {
5243 LIST_REMOVE(foundbp, nb_vnbufs);
5244 LIST_INSERT_HEAD(&dnp->n_cleanblkhd, foundbp, nb_vnbufs);
5245 dnp->n_lastdbl = foundbp->nb_lblkno;
5246 }
5247 nfs_buf_itercomplete(dnp, &blist, NBI_CLEAN);
5248 }
5249 done:
5250 lck_mtx_unlock(nfs_buf_mutex);
5251
5252 if (!error && found && !purge) {
5253 error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len,
5254 &nvattr, &xid, dnp->n_auth, NG_MAKEENTRY, &newnp);
5255 if (error)
5256 return (error);
5257 newnp->n_attrstamp = attrstamp;
5258 *npp = newnp;
5259 nfs_node_unlock(newnp);
5260 /* check if the dir buffer's attrs are out of date */
5261 if (!nfs_getattr(newnp, &nvattr, ctx, NGA_CACHED) &&
5262 (newnp->n_attrstamp != attrstamp)) {
5263 /* they are, so update them */
5264 error = nfs_buf_get(dnp, lbn, NFS_DIRBLKSIZ, thd, NBLK_READ|NBLK_ONLYVALID, &bp);
5265 if (!error && bp) {
5266 attrstamp = newnp->n_attrstamp;
5267 xid = newnp->n_xid;
5268 nfs_dir_buf_search(bp, cnp, &fh, &nvattr, &xid, &attrstamp, NULL, NDBS_UPDATE);
5269 nfs_buf_release(bp, 0);
5270 }
5271 error = 0;
5272 }
5273 }
5274
5275 return (error);
5276 }
5277
5278 /*
5279 * Purge name cache entries for the given node.
5280 * For RDIRPLUS, also invalidate the entry in the directory's buffers.
5281 */
5282 void
5283 nfs_name_cache_purge(nfsnode_t dnp, nfsnode_t np, struct componentname *cnp, vfs_context_t ctx)
5284 {
5285 struct nfsmount *nmp = NFSTONMP(dnp);
5286
5287 cache_purge(NFSTOV(np));
5288 if (nmp && (nmp->nm_vers > NFS_VER2) && NMFLAG(nmp, RDIRPLUS))
5289 nfs_dir_buf_cache_lookup(dnp, NULL, cnp, ctx, 1);
5290 }
5291
5292 /*
5293 * NFS V3 readdir (plus) RPC.
5294 */
5295 int
5296 nfs3_readdir_rpc(nfsnode_t dnp, struct nfsbuf *bp, vfs_context_t ctx)
5297 {
5298 struct nfsmount *nmp;
5299 int error = 0, lockerror, nfsvers, rdirplus, bigcookies;
5300 int i, status, attrflag, fhflag, more_entries = 1, eof, bp_dropped = 0;
5301 uint32_t nmreaddirsize, nmrsize;
5302 uint32_t namlen, skiplen, fhlen, xlen, attrlen, reclen, space_free, space_needed;
5303 uint64_t cookie, lastcookie, xid, savedxid, fileno;
5304 struct nfsm_chain nmreq, nmrep, nmrepsave;
5305 fhandle_t fh;
5306 struct nfs_vattr *nvattrp;
5307 struct nfs_dir_buf_header *ndbhp;
5308 struct direntry *dp;
5309 char *padstart, padlen;
5310 struct timeval now;
5311
5312 nmp = NFSTONMP(dnp);
5313 if (!nmp)
5314 return (ENXIO);
5315 nfsvers = nmp->nm_vers;
5316 nmreaddirsize = nmp->nm_readdirsize;
5317 nmrsize = nmp->nm_rsize;
5318 bigcookies = nmp->nm_state & NFSSTA_BIGCOOKIES;
5319 noplus:
5320 rdirplus = ((nfsvers > NFS_VER2) && NMFLAG(nmp, RDIRPLUS)) ? 1 : 0;
5321
5322 if ((lockerror = nfs_node_lock(dnp)))
5323 return (lockerror);
5324
5325 /* determine cookie to use, and move dp to the right offset */
5326 ndbhp = (struct nfs_dir_buf_header*)bp->nb_data;
5327 dp = NFS_DIR_BUF_FIRST_DIRENTRY(bp);
5328 if (ndbhp->ndbh_count) {
5329 for (i=0; i < ndbhp->ndbh_count-1; i++)
5330 dp = NFS_DIRENTRY_NEXT(dp);
5331 cookie = dp->d_seekoff;
5332 dp = NFS_DIRENTRY_NEXT(dp);
5333 } else {
5334 cookie = bp->nb_lblkno;
5335 /* increment with every buffer read */
5336 OSAddAtomic(1, &nfsstats.readdir_bios);
5337 }
5338 lastcookie = cookie;
5339
5340 /*
5341 * Loop around doing readdir(plus) RPCs of size nm_readdirsize until
5342 * the buffer is full (or we hit EOF). Then put the remainder of the
5343 * results in the next buffer(s).
5344 */
5345 nfsm_chain_null(&nmreq);
5346 nfsm_chain_null(&nmrep);
5347 while (nfs_dir_buf_freespace(bp, rdirplus) && !(ndbhp->ndbh_flags & NDB_FULL)) {
5348 nfsm_chain_build_alloc_init(error, &nmreq,
5349 NFSX_FH(nfsvers) + NFSX_READDIR(nfsvers) + NFSX_UNSIGNED);
5350 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
5351 if (nfsvers == NFS_VER3) {
5352 /* opaque values don't need swapping, but as long */
5353 /* as we are consistent about it, it should be ok */
5354 nfsm_chain_add_64(error, &nmreq, cookie);
5355 nfsm_chain_add_64(error, &nmreq, dnp->n_cookieverf);
5356 } else {
5357 nfsm_chain_add_32(error, &nmreq, cookie);
5358 }
5359 nfsm_chain_add_32(error, &nmreq, nmreaddirsize);
5360 if (rdirplus)
5361 nfsm_chain_add_32(error, &nmreq, nmrsize);
5362 nfsm_chain_build_done(error, &nmreq);
5363 nfs_node_unlock(dnp);
5364 lockerror = ENOENT;
5365 nfsmout_if(error);
5366
5367 error = nfs_request(dnp, NULL, &nmreq,
5368 rdirplus ? NFSPROC_READDIRPLUS : NFSPROC_READDIR,
5369 ctx, NULL, &nmrep, &xid, &status);
5370
5371 if ((lockerror = nfs_node_lock(dnp)))
5372 error = lockerror;
5373
5374 savedxid = xid;
5375 if (nfsvers == NFS_VER3)
5376 nfsm_chain_postop_attr_update(error, &nmrep, dnp, &xid);
5377 if (!error)
5378 error = status;
5379 if (nfsvers == NFS_VER3)
5380 nfsm_chain_get_64(error, &nmrep, dnp->n_cookieverf);
5381 nfsm_chain_get_32(error, &nmrep, more_entries);
5382
5383 if (!lockerror) {
5384 nfs_node_unlock(dnp);
5385 lockerror = ENOENT;
5386 }
5387 if (error == NFSERR_NOTSUPP) {
5388 /* oops... it doesn't look like readdirplus is supported */
5389 lck_mtx_lock(&nmp->nm_lock);
5390 NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_RDIRPLUS);
5391 lck_mtx_unlock(&nmp->nm_lock);
5392 goto noplus;
5393 }
5394 nfsmout_if(error);
5395
5396 if (rdirplus)
5397 microuptime(&now);
5398
5399 /* loop through the entries packing them into the buffer */
5400 while (more_entries) {
5401 if (nfsvers == NFS_VER3)
5402 nfsm_chain_get_64(error, &nmrep, fileno);
5403 else
5404 nfsm_chain_get_32(error, &nmrep, fileno);
5405 nfsm_chain_get_32(error, &nmrep, namlen);
5406 nfsmout_if(error);
5407 /* just truncate names that don't fit in direntry.d_name */
5408 if (namlen <= 0) {
5409 error = EBADRPC;
5410 goto nfsmout;
5411 }
5412 if (namlen > (sizeof(dp->d_name)-1)) {
5413 skiplen = namlen - sizeof(dp->d_name) + 1;
5414 namlen = sizeof(dp->d_name) - 1;
5415 } else {
5416 skiplen = 0;
5417 }
5418 /* guess that fh size will be same as parent */
5419 fhlen = rdirplus ? (1 + dnp->n_fhsize) : 0;
5420 xlen = rdirplus ? (fhlen + sizeof(time_t)) : 0;
5421 attrlen = rdirplus ? sizeof(struct nfs_vattr) : 0;
5422 reclen = NFS_DIRENTRY_LEN(namlen + xlen);
5423 space_needed = reclen + attrlen;
5424 space_free = nfs_dir_buf_freespace(bp, rdirplus);
5425 if (space_needed > space_free) {
5426 /*
5427 * We still have entries to pack, but we've
5428 * run out of room in the current buffer.
5429 * So we need to move to the next buffer.
5430 * The block# for the next buffer is the
5431 * last cookie in the current buffer.
5432 */
5433 nextbuffer:
5434 ndbhp->ndbh_flags |= NDB_FULL;
5435 nfs_buf_release(bp, 0);
5436 bp_dropped = 1;
5437 bp = NULL;
5438 error = nfs_buf_get(dnp, lastcookie, NFS_DIRBLKSIZ, vfs_context_thread(ctx), NBLK_READ, &bp);
5439 nfsmout_if(error);
5440 /* initialize buffer */
5441 ndbhp = (struct nfs_dir_buf_header*)bp->nb_data;
5442 ndbhp->ndbh_flags = 0;
5443 ndbhp->ndbh_count = 0;
5444 ndbhp->ndbh_entry_end = sizeof(*ndbhp);
5445 ndbhp->ndbh_ncgen = dnp->n_ncgen;
5446 space_free = nfs_dir_buf_freespace(bp, rdirplus);
5447 dp = NFS_DIR_BUF_FIRST_DIRENTRY(bp);
5448 /* increment with every buffer read */
5449 OSAddAtomic(1, &nfsstats.readdir_bios);
5450 }
5451 nmrepsave = nmrep;
5452 dp->d_fileno = fileno;
5453 dp->d_namlen = namlen;
5454 dp->d_reclen = reclen;
5455 dp->d_type = DT_UNKNOWN;
5456 nfsm_chain_get_opaque(error, &nmrep, namlen, dp->d_name);
5457 nfsmout_if(error);
5458 dp->d_name[namlen] = '\0';
5459 if (skiplen)
5460 nfsm_chain_adv(error, &nmrep,
5461 nfsm_rndup(namlen + skiplen) - nfsm_rndup(namlen));
5462 if (nfsvers == NFS_VER3)
5463 nfsm_chain_get_64(error, &nmrep, cookie);
5464 else
5465 nfsm_chain_get_32(error, &nmrep, cookie);
5466 nfsmout_if(error);
5467 dp->d_seekoff = cookie;
5468 if (!bigcookies && (cookie >> 32) && (nmp == NFSTONMP(dnp))) {
5469 /* we've got a big cookie, make sure flag is set */
5470 lck_mtx_lock(&nmp->nm_lock);
5471 nmp->nm_state |= NFSSTA_BIGCOOKIES;
5472 lck_mtx_unlock(&nmp->nm_lock);
5473 bigcookies = 1;
5474 }
5475 if (rdirplus) {
5476 nvattrp = NFS_DIR_BUF_NVATTR(bp, ndbhp->ndbh_count);
5477 /* check for attributes */
5478 nfsm_chain_get_32(error, &nmrep, attrflag);
5479 nfsmout_if(error);
5480 if (attrflag) {
5481 /* grab attributes */
5482 error = nfs_parsefattr(&nmrep, NFS_VER3, nvattrp);
5483 nfsmout_if(error);
5484 dp->d_type = IFTODT(VTTOIF(nvattrp->nva_type));
5485 /* fileid is already in d_fileno, so stash xid in attrs */
5486 nvattrp->nva_fileid = savedxid;
5487 } else {
5488 /* mark the attributes invalid */
5489 bzero(nvattrp, sizeof(struct nfs_vattr));
5490 }
5491 /* check for file handle */
5492 nfsm_chain_get_32(error, &nmrep, fhflag);
5493 nfsmout_if(error);
5494 if (fhflag) {
5495 nfsm_chain_get_fh(error, &nmrep, NFS_VER3, &fh);
5496 nfsmout_if(error);
5497 fhlen = fh.fh_len + 1;
5498 xlen = fhlen + sizeof(time_t);
5499 reclen = NFS_DIRENTRY_LEN(namlen + xlen);
5500 space_needed = reclen + attrlen;
5501 if (space_needed > space_free) {
5502 /* didn't actually have the room... move on to next buffer */
5503 nmrep = nmrepsave;
5504 goto nextbuffer;
5505 }
5506 /* pack the file handle into the record */
5507 dp->d_name[dp->d_namlen+1] = fh.fh_len;
5508 bcopy(fh.fh_data, &dp->d_name[dp->d_namlen+2], fh.fh_len);
5509 } else {
5510 /* mark the file handle invalid */
5511 fh.fh_len = 0;
5512 fhlen = fh.fh_len + 1;
5513 xlen = fhlen + sizeof(time_t);
5514 reclen = NFS_DIRENTRY_LEN(namlen + xlen);
5515 bzero(&dp->d_name[dp->d_namlen+1], fhlen);
5516 }
5517 *(time_t*)(&dp->d_name[dp->d_namlen+1+fhlen]) = now.tv_sec;
5518 dp->d_reclen = reclen;
5519 }
5520 padstart = dp->d_name + dp->d_namlen + 1 + xlen;
5521 ndbhp->ndbh_count++;
5522 lastcookie = cookie;
5523 /* advance to next direntry in buffer */
5524 dp = NFS_DIRENTRY_NEXT(dp);
5525 ndbhp->ndbh_entry_end = (char*)dp - bp->nb_data;
5526 /* zero out the pad bytes */
5527 padlen = (char*)dp - padstart;
5528 if (padlen > 0)
5529 bzero(padstart, padlen);
5530 /* check for more entries */
5531 nfsm_chain_get_32(error, &nmrep, more_entries);
5532 nfsmout_if(error);
5533 }
5534 /* Finally, get the eof boolean */
5535 nfsm_chain_get_32(error, &nmrep, eof);
5536 nfsmout_if(error);
5537 if (eof) {
5538 ndbhp->ndbh_flags |= (NDB_FULL|NDB_EOF);
5539 nfs_node_lock_force(dnp);
5540 dnp->n_eofcookie = lastcookie;
5541 nfs_node_unlock(dnp);
5542 } else {
5543 more_entries = 1;
5544 }
5545 if (bp_dropped) {
5546 nfs_buf_release(bp, 0);
5547 bp = NULL;
5548 break;
5549 }
5550 if ((lockerror = nfs_node_lock(dnp)))
5551 error = lockerror;
5552 nfsmout_if(error);
5553 nfsm_chain_cleanup(&nmrep);
5554 nfsm_chain_null(&nmreq);
5555 }
5556 nfsmout:
5557 if (bp_dropped && bp)
5558 nfs_buf_release(bp, 0);
5559 if (!lockerror)
5560 nfs_node_unlock(dnp);
5561 nfsm_chain_cleanup(&nmreq);
5562 nfsm_chain_cleanup(&nmrep);
5563 return (bp_dropped ? NFSERR_DIRBUFDROPPED : error);
5564 }
5565
5566 /*
5567 * Silly rename. To make the NFS filesystem that is stateless look a little
5568 * more like the "ufs" a remove of an active vnode is translated to a rename
5569 * to a funny looking filename that is removed by nfs_vnop_inactive on the
5570 * nfsnode. There is the potential for another process on a different client
5571 * to create the same funny name between when the lookitup() fails and the
5572 * rename() completes, but...
5573 */
5574
5575 /* format of "random" silly names - includes a number and pid */
5576 /* (note: shouldn't exceed size of nfs_sillyrename.nsr_name) */
5577 #define NFS_SILLYNAME_FORMAT ".nfs.%08x.%04x"
5578 /* starting from zero isn't silly enough */
5579 static uint32_t nfs_sillyrename_number = 0x20051025;
5580
5581 int
5582 nfs_sillyrename(
5583 nfsnode_t dnp,
5584 nfsnode_t np,
5585 struct componentname *cnp,
5586 vfs_context_t ctx)
5587 {
5588 struct nfs_sillyrename *nsp;
5589 int error;
5590 short pid;
5591 kauth_cred_t cred;
5592 uint32_t num;
5593 struct nfsmount *nmp;
5594
5595 nmp = NFSTONMP(dnp);
5596 if (!nmp)
5597 return (ENXIO);
5598
5599 nfs_name_cache_purge(dnp, np, cnp, ctx);
5600
5601 MALLOC_ZONE(nsp, struct nfs_sillyrename *,
5602 sizeof (struct nfs_sillyrename), M_NFSREQ, M_WAITOK);
5603 if (!nsp)
5604 return (ENOMEM);
5605 cred = vfs_context_ucred(ctx);
5606 kauth_cred_ref(cred);
5607 nsp->nsr_cred = cred;
5608 nsp->nsr_dnp = dnp;
5609 error = vnode_ref(NFSTOV(dnp));
5610 if (error)
5611 goto bad_norele;
5612
5613 /* Fudge together a funny name */
5614 pid = vfs_context_pid(ctx);
5615 num = OSAddAtomic(1, &nfs_sillyrename_number);
5616 nsp->nsr_namlen = snprintf(nsp->nsr_name, sizeof(nsp->nsr_name),
5617 NFS_SILLYNAME_FORMAT, num, (pid & 0xffff));
5618 if (nsp->nsr_namlen >= (int)sizeof(nsp->nsr_name))
5619 nsp->nsr_namlen = sizeof(nsp->nsr_name) - 1;
5620
5621 /* Try lookitups until we get one that isn't there */
5622 while (nfs_lookitup(dnp, nsp->nsr_name, nsp->nsr_namlen, ctx, NULL) == 0) {
5623 num = OSAddAtomic(1, &nfs_sillyrename_number);
5624 nsp->nsr_namlen = snprintf(nsp->nsr_name, sizeof(nsp->nsr_name),
5625 NFS_SILLYNAME_FORMAT, num, (pid & 0xffff));
5626 if (nsp->nsr_namlen >= (int)sizeof(nsp->nsr_name))
5627 nsp->nsr_namlen = sizeof(nsp->nsr_name) - 1;
5628 }
5629
5630 /* now, do the rename */
5631 error = nmp->nm_funcs->nf_rename_rpc(dnp, cnp->cn_nameptr, cnp->cn_namelen,
5632 dnp, nsp->nsr_name, nsp->nsr_namlen, ctx);
5633
5634 /* Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. */
5635 if (error == ENOENT)
5636 error = 0;
5637 if (!error) {
5638 nfs_node_lock_force(dnp);
5639 if (dnp->n_flag & NNEGNCENTRIES) {
5640 dnp->n_flag &= ~NNEGNCENTRIES;
5641 cache_purge_negatives(NFSTOV(dnp));
5642 }
5643 nfs_node_unlock(dnp);
5644 }
5645 FSDBG(267, dnp, np, num, error);
5646 if (error)
5647 goto bad;
5648 error = nfs_lookitup(dnp, nsp->nsr_name, nsp->nsr_namlen, ctx, &np);
5649 nfs_node_lock_force(np);
5650 np->n_sillyrename = nsp;
5651 nfs_node_unlock(np);
5652 return (0);
5653 bad:
5654 vnode_rele(NFSTOV(dnp));
5655 bad_norele:
5656 nsp->nsr_cred = NOCRED;
5657 kauth_cred_unref(&cred);
5658 FREE_ZONE(nsp, sizeof(*nsp), M_NFSREQ);
5659 return (error);
5660 }
5661
5662 int
5663 nfs3_lookup_rpc_async(
5664 nfsnode_t dnp,
5665 char *name,
5666 int namelen,
5667 vfs_context_t ctx,
5668 struct nfsreq **reqp)
5669 {
5670 struct nfsmount *nmp;
5671 struct nfsm_chain nmreq;
5672 int error = 0, nfsvers;
5673
5674 nmp = NFSTONMP(dnp);
5675 if (!nmp)
5676 return (ENXIO);
5677 nfsvers = nmp->nm_vers;
5678
5679 nfsm_chain_null(&nmreq);
5680
5681 nfsm_chain_build_alloc_init(error, &nmreq,
5682 NFSX_FH(nfsvers) + NFSX_UNSIGNED + nfsm_rndup(namelen));
5683 nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize);
5684 nfsm_chain_add_name(error, &nmreq, name, namelen, nmp);
5685 nfsm_chain_build_done(error, &nmreq);
5686 nfsmout_if(error);
5687 error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_LOOKUP,
5688 vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, reqp);
5689 nfsmout:
5690 nfsm_chain_cleanup(&nmreq);
5691 return (error);
5692 }
5693
5694 int
5695 nfs3_lookup_rpc_async_finish(
5696 nfsnode_t dnp,
5697 __unused char *name,
5698 __unused int namelen,
5699 vfs_context_t ctx,
5700 struct nfsreq *req,
5701 u_int64_t *xidp,
5702 fhandle_t *fhp,
5703 struct nfs_vattr *nvap)
5704 {
5705 int error = 0, lockerror = ENOENT, status, nfsvers, attrflag;
5706 u_int64_t xid;
5707 struct nfsmount *nmp;
5708 struct nfsm_chain nmrep;
5709
5710 nmp = NFSTONMP(dnp);
5711 nfsvers = nmp->nm_vers;
5712
5713 nfsm_chain_null(&nmrep);
5714
5715 error = nfs_request_async_finish(req, &nmrep, xidp, &status);
5716
5717 if ((lockerror = nfs_node_lock(dnp)))
5718 error = lockerror;
5719 xid = *xidp;
5720 if (error || status) {
5721 if (nfsvers == NFS_VER3)
5722 nfsm_chain_postop_attr_update(error, &nmrep, dnp, &xid);
5723 if (!error)
5724 error = status;
5725 goto nfsmout;
5726 }
5727
5728 nfsmout_if(error || !fhp || !nvap);
5729
5730 /* get the file handle */
5731 nfsm_chain_get_fh(error, &nmrep, nfsvers, fhp);
5732
5733 /* get the attributes */
5734 if (nfsvers == NFS_VER3) {
5735 nfsm_chain_postop_attr_get(error, &nmrep, attrflag, nvap);
5736 nfsm_chain_postop_attr_update(error, &nmrep, dnp, &xid);
5737 if (!error && !attrflag)
5738 error = nfs3_getattr_rpc(NULL, NFSTOMP(dnp), fhp->fh_data, fhp->fh_len, 0, ctx, nvap, xidp);
5739 } else {
5740 error = nfs_parsefattr(&nmrep, nfsvers, nvap);
5741 }
5742 nfsmout:
5743 if (!lockerror)
5744 nfs_node_unlock(dnp);
5745 nfsm_chain_cleanup(&nmrep);
5746 return (error);
5747 }
5748
5749 /*
5750 * Look up a file name and optionally either update the file handle or
5751 * allocate an nfsnode, depending on the value of npp.
5752 * npp == NULL --> just do the lookup
5753 * *npp == NULL --> allocate a new nfsnode and make sure attributes are
5754 * handled too
5755 * *npp != NULL --> update the file handle in the vnode
5756 */
5757 int
5758 nfs_lookitup(
5759 nfsnode_t dnp,
5760 char *name,
5761 int namelen,
5762 vfs_context_t ctx,
5763 nfsnode_t *npp)
5764 {
5765 int error = 0;
5766 nfsnode_t np, newnp = NULL;
5767 u_int64_t xid;
5768 fhandle_t fh;
5769 struct nfsmount *nmp;
5770 struct nfs_vattr nvattr;
5771 struct nfsreq rq, *req = &rq;
5772
5773 nmp = NFSTONMP(dnp);
5774 if (!nmp)
5775 return (ENXIO);
5776
5777 if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXNAME) &&
5778 (namelen > (int)nmp->nm_fsattr.nfsa_maxname))
5779 return (ENAMETOOLONG);
5780
5781 NVATTR_INIT(&nvattr);
5782
5783 /* check for lookup of "." */
5784 if ((name[0] == '.') && (namelen == 1)) {
5785 /* skip lookup, we know who we are */
5786 fh.fh_len = 0;
5787 newnp = dnp;
5788 goto nfsmout;
5789 }
5790
5791 error = nmp->nm_funcs->nf_lookup_rpc_async(dnp, name, namelen, ctx, &req);
5792 nfsmout_if(error);
5793 error = nmp->nm_funcs->nf_lookup_rpc_async_finish(dnp, name, namelen, ctx, req, &xid, &fh, &nvattr);
5794 nfsmout_if(!npp || error);
5795
5796 if (*npp) {
5797 np = *npp;
5798 if (fh.fh_len != np->n_fhsize) {
5799 u_char *oldbuf = (np->n_fhsize > NFS_SMALLFH) ? np->n_fhp : NULL;
5800 if (fh.fh_len > NFS_SMALLFH) {
5801 MALLOC_ZONE(np->n_fhp, u_char *, fh.fh_len, M_NFSBIGFH, M_WAITOK);
5802 if (!np->n_fhp) {
5803 np->n_fhp = oldbuf;
5804 error = ENOMEM;
5805 goto nfsmout;
5806 }
5807 } else {
5808 np->n_fhp = &np->n_fh[0];
5809 }
5810 if (oldbuf)
5811 FREE_ZONE(oldbuf, np->n_fhsize, M_NFSBIGFH);
5812 }
5813 bcopy(fh.fh_data, np->n_fhp, fh.fh_len);
5814 np->n_fhsize = fh.fh_len;
5815 nfs_node_lock_force(np);
5816 error = nfs_loadattrcache(np, &nvattr, &xid, 0);
5817 nfs_node_unlock(np);
5818 nfsmout_if(error);
5819 newnp = np;
5820 } else if (NFS_CMPFH(dnp, fh.fh_data, fh.fh_len)) {
5821 nfs_node_lock_force(dnp);
5822 if (dnp->n_xid <= xid)
5823 error = nfs_loadattrcache(dnp, &nvattr, &xid, 0);
5824 nfs_node_unlock(dnp);
5825 nfsmout_if(error);
5826 newnp = dnp;
5827 } else {
5828 struct componentname cn, *cnp = &cn;
5829 bzero(cnp, sizeof(*cnp));
5830 cnp->cn_nameptr = name;
5831 cnp->cn_namelen = namelen;
5832 error = nfs_nget(NFSTOMP(dnp), dnp, cnp, fh.fh_data, fh.fh_len,
5833 &nvattr, &xid, rq.r_auth, NG_MAKEENTRY, &np);
5834 nfsmout_if(error);
5835 newnp = np;
5836 }
5837
5838 nfsmout:
5839 if (npp && !*npp && !error)
5840 *npp = newnp;
5841 NVATTR_CLEANUP(&nvattr);
5842 return (error);
5843 }
5844
5845 /*
5846 * set up and initialize a "._" file lookup structure used for
5847 * performing async lookups.
5848 */
5849 void
5850 nfs_dulookup_init(struct nfs_dulookup *dulp, nfsnode_t dnp, const char *name, int namelen, vfs_context_t ctx)
5851 {
5852 int error, du_namelen;
5853 vnode_t du_vp;
5854 struct nfsmount *nmp = NFSTONMP(dnp);
5855
5856 /* check for ._ file in name cache */
5857 dulp->du_flags = 0;
5858 bzero(&dulp->du_cn, sizeof(dulp->du_cn));
5859 du_namelen = namelen + 2;
5860 if (!nmp || NMFLAG(nmp, NONEGNAMECACHE))
5861 return;
5862 if ((namelen >= 2) && (name[0] == '.') && (name[1] == '_'))
5863 return;
5864 if (du_namelen >= (int)sizeof(dulp->du_smallname))
5865 MALLOC(dulp->du_cn.cn_nameptr, char *, du_namelen + 1, M_TEMP, M_WAITOK);
5866 else
5867 dulp->du_cn.cn_nameptr = dulp->du_smallname;
5868 if (!dulp->du_cn.cn_nameptr)
5869 return;
5870 dulp->du_cn.cn_namelen = du_namelen;
5871 snprintf(dulp->du_cn.cn_nameptr, du_namelen + 1, "._%s", name);
5872 dulp->du_cn.cn_nameptr[du_namelen] = '\0';
5873 dulp->du_cn.cn_nameiop = LOOKUP;
5874 dulp->du_cn.cn_flags = MAKEENTRY;
5875
5876 error = cache_lookup(NFSTOV(dnp), &du_vp, &dulp->du_cn);
5877 if (error == -1) {
5878 vnode_put(du_vp);
5879 } else if (!error) {
5880 nmp = NFSTONMP(dnp);
5881 if (nmp && (nmp->nm_vers > NFS_VER2) && NMFLAG(nmp, RDIRPLUS)) {
5882 /* if rdirplus, try dir buf cache lookup */
5883 nfsnode_t du_np = NULL;
5884 if (!nfs_dir_buf_cache_lookup(dnp, &du_np, &dulp->du_cn, ctx, 0) && du_np) {
5885 /* dir buf cache hit */
5886 du_vp = NFSTOV(du_np);
5887 vnode_put(du_vp);
5888 error = -1;
5889 }
5890 }
5891 if (!error)
5892 dulp->du_flags |= NFS_DULOOKUP_DOIT;
5893 }
5894 }
5895
5896 /*
5897 * start an async "._" file lookup request
5898 */
5899 void
5900 nfs_dulookup_start(struct nfs_dulookup *dulp, nfsnode_t dnp, vfs_context_t ctx)
5901 {
5902 struct nfsmount *nmp = NFSTONMP(dnp);
5903 struct nfsreq *req = &dulp->du_req;
5904
5905 if (!nmp || !(dulp->du_flags & NFS_DULOOKUP_DOIT) || (dulp->du_flags & NFS_DULOOKUP_INPROG))
5906 return;
5907 if (!nmp->nm_funcs->nf_lookup_rpc_async(dnp, dulp->du_cn.cn_nameptr,
5908 dulp->du_cn.cn_namelen, ctx, &req))
5909 dulp->du_flags |= NFS_DULOOKUP_INPROG;
5910 }
5911
5912 /*
5913 * finish an async "._" file lookup request and clean up the structure
5914 */
5915 void
5916 nfs_dulookup_finish(struct nfs_dulookup *dulp, nfsnode_t dnp, vfs_context_t ctx)
5917 {
5918 struct nfsmount *nmp = NFSTONMP(dnp);
5919 int error;
5920 nfsnode_t du_np;
5921 u_int64_t xid;
5922 fhandle_t fh;
5923 struct nfs_vattr nvattr;
5924
5925 if (!nmp || !(dulp->du_flags & NFS_DULOOKUP_INPROG))
5926 goto out;
5927
5928 NVATTR_INIT(&nvattr);
5929 error = nmp->nm_funcs->nf_lookup_rpc_async_finish(dnp, dulp->du_cn.cn_nameptr,
5930 dulp->du_cn.cn_namelen, ctx, &dulp->du_req, &xid, &fh, &nvattr);
5931 dulp->du_flags &= ~NFS_DULOOKUP_INPROG;
5932 if (error == ENOENT) {
5933 /* add a negative entry in the name cache */
5934 nfs_node_lock_force(dnp);
5935 cache_enter(NFSTOV(dnp), NULL, &dulp->du_cn);
5936 dnp->n_flag |= NNEGNCENTRIES;
5937 nfs_node_unlock(dnp);
5938 } else if (!error) {
5939 error = nfs_nget(NFSTOMP(dnp), dnp, &dulp->du_cn, fh.fh_data, fh.fh_len,
5940 &nvattr, &xid, dulp->du_req.r_auth, NG_MAKEENTRY, &du_np);
5941 if (!error) {
5942 nfs_node_unlock(du_np);
5943 vnode_put(NFSTOV(du_np));
5944 }
5945 }
5946 NVATTR_CLEANUP(&nvattr);
5947 out:
5948 if (dulp->du_flags & NFS_DULOOKUP_INPROG)
5949 nfs_request_async_cancel(&dulp->du_req);
5950 if (dulp->du_cn.cn_nameptr && (dulp->du_cn.cn_nameptr != dulp->du_smallname))
5951 FREE(dulp->du_cn.cn_nameptr, M_TEMP);
5952 }
5953
5954
5955 /*
5956 * NFS Version 3 commit RPC
5957 */
5958 int
5959 nfs3_commit_rpc(
5960 nfsnode_t np,
5961 uint64_t offset,
5962 uint64_t count,
5963 kauth_cred_t cred,
5964 uint64_t wverf)
5965 {
5966 struct nfsmount *nmp;
5967 int error = 0, lockerror, status, wccpostattr = 0, nfsvers;
5968 struct timespec premtime = { 0, 0 };
5969 u_int64_t xid, newwverf;
5970 uint32_t count32;
5971 struct nfsm_chain nmreq, nmrep;
5972
5973 nmp = NFSTONMP(np);
5974 FSDBG(521, np, offset, count, nmp ? nmp->nm_state : 0);
5975 if (!nmp)
5976 return (ENXIO);
5977 if (!(nmp->nm_state & NFSSTA_HASWRITEVERF))
5978 return (0);
5979 nfsvers = nmp->nm_vers;
5980
5981 if (count > UINT32_MAX)
5982 count32 = 0;
5983 else
5984 count32 = count;
5985
5986 nfsm_chain_null(&nmreq);
5987 nfsm_chain_null(&nmrep);
5988
5989 nfsm_chain_build_alloc_init(error, &nmreq, NFSX_FH(NFS_VER3));
5990 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
5991 nfsm_chain_add_64(error, &nmreq, offset);
5992 nfsm_chain_add_32(error, &nmreq, count32);
5993 nfsm_chain_build_done(error, &nmreq);
5994 nfsmout_if(error);
5995 error = nfs_request2(np, NULL, &nmreq, NFSPROC_COMMIT,
5996 current_thread(), cred, NULL, 0, &nmrep, &xid, &status);
5997 if ((lockerror = nfs_node_lock(np)))
5998 error = lockerror;
5999 /* can we do anything useful with the wcc info? */
6000 nfsm_chain_get_wcc_data(error, &nmrep, np, &premtime, &wccpostattr, &xid);
6001 if (!lockerror)
6002 nfs_node_unlock(np);
6003 if (!error)
6004 error = status;
6005 nfsm_chain_get_64(error, &nmrep, newwverf);
6006 nfsmout_if(error);
6007 lck_mtx_lock(&nmp->nm_lock);
6008 if (nmp->nm_verf != newwverf)
6009 nmp->nm_verf = newwverf;
6010 if (wverf != newwverf)
6011 error = NFSERR_STALEWRITEVERF;
6012 lck_mtx_unlock(&nmp->nm_lock);
6013 nfsmout:
6014 nfsm_chain_cleanup(&nmreq);
6015 nfsm_chain_cleanup(&nmrep);
6016 return (error);
6017 }
6018
6019
6020 int
6021 nfs_vnop_blockmap(
6022 __unused struct vnop_blockmap_args /* {
6023 struct vnodeop_desc *a_desc;
6024 vnode_t a_vp;
6025 off_t a_foffset;
6026 size_t a_size;
6027 daddr64_t *a_bpn;
6028 size_t *a_run;
6029 void *a_poff;
6030 int a_flags;
6031 } */ *ap)
6032 {
6033 return (ENOTSUP);
6034 }
6035
6036
6037 /*
6038 * fsync vnode op. Just call nfs_flush().
6039 */
6040 /* ARGSUSED */
6041 int
6042 nfs_vnop_fsync(
6043 struct vnop_fsync_args /* {
6044 struct vnodeop_desc *a_desc;
6045 vnode_t a_vp;
6046 int a_waitfor;
6047 vfs_context_t a_context;
6048 } */ *ap)
6049 {
6050 return (nfs_flush(VTONFS(ap->a_vp), ap->a_waitfor, vfs_context_thread(ap->a_context), 0));
6051 }
6052
6053
6054 /*
6055 * Do an NFS pathconf RPC.
6056 */
6057 int
6058 nfs3_pathconf_rpc(
6059 nfsnode_t np,
6060 struct nfs_fsattr *nfsap,
6061 vfs_context_t ctx)
6062 {
6063 u_int64_t xid;
6064 int error = 0, lockerror, status, nfsvers;
6065 struct nfsm_chain nmreq, nmrep;
6066 struct nfsmount *nmp = NFSTONMP(np);
6067 uint32_t val = 0;
6068
6069 if (!nmp)
6070 return (ENXIO);
6071 nfsvers = nmp->nm_vers;
6072
6073 nfsm_chain_null(&nmreq);
6074 nfsm_chain_null(&nmrep);
6075
6076 /* fetch pathconf info from server */
6077 nfsm_chain_build_alloc_init(error, &nmreq, NFSX_FH(NFS_VER3));
6078 nfsm_chain_add_fh(error, &nmreq, nfsvers, np->n_fhp, np->n_fhsize);
6079 nfsm_chain_build_done(error, &nmreq);
6080 nfsmout_if(error);
6081 error = nfs_request(np, NULL, &nmreq, NFSPROC_PATHCONF, ctx, NULL, &nmrep, &xid, &status);
6082 if ((lockerror = nfs_node_lock(np)))
6083 error = lockerror;
6084 nfsm_chain_postop_attr_update(error, &nmrep, np, &xid);
6085 if (!lockerror)
6086 nfs_node_unlock(np);
6087 if (!error)
6088 error = status;
6089 nfsm_chain_get_32(error, &nmrep, nfsap->nfsa_maxlink);
6090 nfsm_chain_get_32(error, &nmrep, nfsap->nfsa_maxname);
6091 nfsm_chain_get_32(error, &nmrep, val);
6092 if (val)
6093 nfsap->nfsa_flags |= NFS_FSFLAG_NO_TRUNC;
6094 nfsm_chain_get_32(error, &nmrep, val);
6095 if (val)
6096 nfsap->nfsa_flags |= NFS_FSFLAG_CHOWN_RESTRICTED;
6097 nfsm_chain_get_32(error, &nmrep, val);
6098 if (val)
6099 nfsap->nfsa_flags |= NFS_FSFLAG_CASE_INSENSITIVE;
6100 nfsm_chain_get_32(error, &nmrep, val);
6101 if (val)
6102 nfsap->nfsa_flags |= NFS_FSFLAG_CASE_PRESERVING;
6103 NFS_BITMAP_SET(nfsap->nfsa_bitmap, NFS_FATTR_MAXLINK);
6104 NFS_BITMAP_SET(nfsap->nfsa_bitmap, NFS_FATTR_MAXNAME);
6105 NFS_BITMAP_SET(nfsap->nfsa_bitmap, NFS_FATTR_NO_TRUNC);
6106 NFS_BITMAP_SET(nfsap->nfsa_bitmap, NFS_FATTR_CHOWN_RESTRICTED);
6107 NFS_BITMAP_SET(nfsap->nfsa_bitmap, NFS_FATTR_CASE_INSENSITIVE);
6108 NFS_BITMAP_SET(nfsap->nfsa_bitmap, NFS_FATTR_CASE_PRESERVING);
6109 nfsmout:
6110 nfsm_chain_cleanup(&nmreq);
6111 nfsm_chain_cleanup(&nmrep);
6112 return (error);
6113 }
6114
6115 /* save pathconf info for NFSv3 mount */
6116 void
6117 nfs3_pathconf_cache(struct nfsmount *nmp, struct nfs_fsattr *nfsap)
6118 {
6119 nmp->nm_fsattr.nfsa_maxlink = nfsap->nfsa_maxlink;
6120 nmp->nm_fsattr.nfsa_maxname = nfsap->nfsa_maxname;
6121 nmp->nm_fsattr.nfsa_flags |= nfsap->nfsa_flags & NFS_FSFLAG_NO_TRUNC;
6122 nmp->nm_fsattr.nfsa_flags |= nfsap->nfsa_flags & NFS_FSFLAG_CHOWN_RESTRICTED;
6123 nmp->nm_fsattr.nfsa_flags |= nfsap->nfsa_flags & NFS_FSFLAG_CASE_INSENSITIVE;
6124 nmp->nm_fsattr.nfsa_flags |= nfsap->nfsa_flags & NFS_FSFLAG_CASE_PRESERVING;
6125 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXLINK);
6126 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_MAXNAME);
6127 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_NO_TRUNC);
6128 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_CHOWN_RESTRICTED);
6129 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_CASE_INSENSITIVE);
6130 NFS_BITMAP_SET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_CASE_PRESERVING);
6131 nmp->nm_state |= NFSSTA_GOTPATHCONF;
6132 }
6133
6134 /*
6135 * Return POSIX pathconf information applicable to nfs.
6136 *
6137 * The NFS V2 protocol doesn't support this, so just return EINVAL
6138 * for V2.
6139 */
6140 /* ARGSUSED */
6141 int
6142 nfs_vnop_pathconf(
6143 struct vnop_pathconf_args /* {
6144 struct vnodeop_desc *a_desc;
6145 vnode_t a_vp;
6146 int a_name;
6147 int32_t *a_retval;
6148 vfs_context_t a_context;
6149 } */ *ap)
6150 {
6151 vnode_t vp = ap->a_vp;
6152 nfsnode_t np = VTONFS(vp);
6153 struct nfsmount *nmp;
6154 struct nfs_fsattr nfsa, *nfsap;
6155 int error = 0;
6156 uint64_t maxFileSize;
6157 uint nbits;
6158
6159 nmp = VTONMP(vp);
6160 if (!nmp)
6161 return (ENXIO);
6162
6163 switch (ap->a_name) {
6164 case _PC_LINK_MAX:
6165 case _PC_NAME_MAX:
6166 case _PC_CHOWN_RESTRICTED:
6167 case _PC_NO_TRUNC:
6168 case _PC_CASE_SENSITIVE:
6169 case _PC_CASE_PRESERVING:
6170 break;
6171 case _PC_FILESIZEBITS:
6172 if (nmp->nm_vers == NFS_VER2) {
6173 *ap->a_retval = 32;
6174 return (0);
6175 }
6176 break;
6177 case _PC_XATTR_SIZE_BITS:
6178 /* Do we support xattrs natively? */
6179 if (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR)
6180 break; /* Yes */
6181 /* No... so just return an error */
6182 /* FALLTHROUGH */
6183 default:
6184 /* don't bother contacting the server if we know the answer */
6185 return (EINVAL);
6186 }
6187
6188 if (nmp->nm_vers == NFS_VER2)
6189 return (EINVAL);
6190
6191 lck_mtx_lock(&nmp->nm_lock);
6192 if (nmp->nm_vers == NFS_VER3) {
6193 if (!(nmp->nm_state & NFSSTA_GOTPATHCONF)) {
6194 /* no pathconf info cached */
6195 lck_mtx_unlock(&nmp->nm_lock);
6196 NFS_CLEAR_ATTRIBUTES(nfsa.nfsa_bitmap);
6197 error = nfs3_pathconf_rpc(np, &nfsa, ap->a_context);
6198 if (error)
6199 return (error);
6200 nmp = VTONMP(vp);
6201 if (!nmp)
6202 return (ENXIO);
6203 lck_mtx_lock(&nmp->nm_lock);
6204 if (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_HOMOGENEOUS) {
6205 /* all files have the same pathconf info, */
6206 /* so cache a copy of the results */
6207 nfs3_pathconf_cache(nmp, &nfsa);
6208 }
6209 nfsap = &nfsa;
6210 } else {
6211 nfsap = &nmp->nm_fsattr;
6212 }
6213 } else if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_HOMOGENEOUS)) {
6214 /* no pathconf info cached */
6215 lck_mtx_unlock(&nmp->nm_lock);
6216 NFS_CLEAR_ATTRIBUTES(nfsa.nfsa_bitmap);
6217 error = nfs4_pathconf_rpc(np, &nfsa, ap->a_context);
6218 if (error)
6219 return (error);
6220 nmp = VTONMP(vp);
6221 if (!nmp)
6222 return (ENXIO);
6223 lck_mtx_lock(&nmp->nm_lock);
6224 nfsap = &nfsa;
6225 } else {
6226 nfsap = &nmp->nm_fsattr;
6227 }
6228
6229 switch (ap->a_name) {
6230 case _PC_LINK_MAX:
6231 if (NFS_BITMAP_ISSET(nfsap->nfsa_bitmap, NFS_FATTR_MAXLINK))
6232 *ap->a_retval = nfsap->nfsa_maxlink;
6233 else if ((nmp->nm_vers == NFS_VER4) && NFS_BITMAP_ISSET(np->n_vattr.nva_bitmap, NFS_FATTR_MAXLINK))
6234 *ap->a_retval = np->n_vattr.nva_maxlink;
6235 else
6236 error = EINVAL;
6237 break;
6238 case _PC_NAME_MAX:
6239 if (NFS_BITMAP_ISSET(nfsap->nfsa_bitmap, NFS_FATTR_MAXNAME))
6240 *ap->a_retval = nfsap->nfsa_maxname;
6241 else
6242 error = EINVAL;
6243 break;
6244 case _PC_CHOWN_RESTRICTED:
6245 if (NFS_BITMAP_ISSET(nfsap->nfsa_bitmap, NFS_FATTR_CHOWN_RESTRICTED))
6246 *ap->a_retval = (nfsap->nfsa_flags & NFS_FSFLAG_CHOWN_RESTRICTED) ? 200112 /* _POSIX_CHOWN_RESTRICTED */ : 0;
6247 else
6248 error = EINVAL;
6249 break;
6250 case _PC_NO_TRUNC:
6251 if (NFS_BITMAP_ISSET(nfsap->nfsa_bitmap, NFS_FATTR_NO_TRUNC))
6252 *ap->a_retval = (nfsap->nfsa_flags & NFS_FSFLAG_NO_TRUNC) ? 200112 /* _POSIX_NO_TRUNC */ : 0;
6253 else
6254 error = EINVAL;
6255 break;
6256 case _PC_CASE_SENSITIVE:
6257 if (NFS_BITMAP_ISSET(nfsap->nfsa_bitmap, NFS_FATTR_CASE_INSENSITIVE))
6258 *ap->a_retval = (nfsap->nfsa_flags & NFS_FSFLAG_CASE_INSENSITIVE) ? 0 : 1;
6259 else
6260 error = EINVAL;
6261 break;
6262 case _PC_CASE_PRESERVING:
6263 if (NFS_BITMAP_ISSET(nfsap->nfsa_bitmap, NFS_FATTR_CASE_PRESERVING))
6264 *ap->a_retval = (nfsap->nfsa_flags & NFS_FSFLAG_CASE_PRESERVING) ? 1 : 0;
6265 else
6266 error = EINVAL;
6267 break;
6268 case _PC_XATTR_SIZE_BITS: /* same as file size bits if named attrs supported */
6269 case _PC_FILESIZEBITS:
6270 if (!NFS_BITMAP_ISSET(nfsap->nfsa_bitmap, NFS_FATTR_MAXFILESIZE)) {
6271 *ap->a_retval = 64;
6272 error = 0;
6273 break;
6274 }
6275 maxFileSize = nfsap->nfsa_maxfilesize;
6276 nbits = 1;
6277 if (maxFileSize & 0xffffffff00000000ULL) {
6278 nbits += 32;
6279 maxFileSize >>= 32;
6280 }
6281 if (maxFileSize & 0xffff0000) {
6282 nbits += 16;
6283 maxFileSize >>= 16;
6284 }
6285 if (maxFileSize & 0xff00) {
6286 nbits += 8;
6287 maxFileSize >>= 8;
6288 }
6289 if (maxFileSize & 0xf0) {
6290 nbits += 4;
6291 maxFileSize >>= 4;
6292 }
6293 if (maxFileSize & 0xc) {
6294 nbits += 2;
6295 maxFileSize >>= 2;
6296 }
6297 if (maxFileSize & 0x2) {
6298 nbits += 1;
6299 }
6300 *ap->a_retval = nbits;
6301 break;
6302 default:
6303 error = EINVAL;
6304 }
6305
6306 lck_mtx_unlock(&nmp->nm_lock);
6307
6308 return (error);
6309 }
6310
6311 /*
6312 * Read wrapper for special devices.
6313 */
6314 int
6315 nfsspec_vnop_read(
6316 struct vnop_read_args /* {
6317 struct vnodeop_desc *a_desc;
6318 vnode_t a_vp;
6319 struct uio *a_uio;
6320 int a_ioflag;
6321 vfs_context_t a_context;
6322 } */ *ap)
6323 {
6324 nfsnode_t np = VTONFS(ap->a_vp);
6325 struct timeval now;
6326 int error;
6327
6328 /*
6329 * Set access flag.
6330 */
6331 if ((error = nfs_node_lock(np)))
6332 return (error);
6333 np->n_flag |= NACC;
6334 microtime(&now);
6335 np->n_atim.tv_sec = now.tv_sec;
6336 np->n_atim.tv_nsec = now.tv_usec * 1000;
6337 nfs_node_unlock(np);
6338 return (VOCALL(spec_vnodeop_p, VOFFSET(vnop_read), ap));
6339 }
6340
6341 /*
6342 * Write wrapper for special devices.
6343 */
6344 int
6345 nfsspec_vnop_write(
6346 struct vnop_write_args /* {
6347 struct vnodeop_desc *a_desc;
6348 vnode_t a_vp;
6349 struct uio *a_uio;
6350 int a_ioflag;
6351 vfs_context_t a_context;
6352 } */ *ap)
6353 {
6354 nfsnode_t np = VTONFS(ap->a_vp);
6355 struct timeval now;
6356 int error;
6357
6358 /*
6359 * Set update flag.
6360 */
6361 if ((error = nfs_node_lock(np)))
6362 return (error);
6363 np->n_flag |= NUPD;
6364 microtime(&now);
6365 np->n_mtim.tv_sec = now.tv_sec;
6366 np->n_mtim.tv_nsec = now.tv_usec * 1000;
6367 nfs_node_unlock(np);
6368 return (VOCALL(spec_vnodeop_p, VOFFSET(vnop_write), ap));
6369 }
6370
6371 /*
6372 * Close wrapper for special devices.
6373 *
6374 * Update the times on the nfsnode then do device close.
6375 */
6376 int
6377 nfsspec_vnop_close(
6378 struct vnop_close_args /* {
6379 struct vnodeop_desc *a_desc;
6380 vnode_t a_vp;
6381 int a_fflag;
6382 vfs_context_t a_context;
6383 } */ *ap)
6384 {
6385 vnode_t vp = ap->a_vp;
6386 nfsnode_t np = VTONFS(vp);
6387 struct vnode_attr vattr;
6388 mount_t mp;
6389 int error;
6390
6391 if ((error = nfs_node_lock(np)))
6392 return (error);
6393 if (np->n_flag & (NACC | NUPD)) {
6394 np->n_flag |= NCHG;
6395 if (!vnode_isinuse(vp, 0) && (mp = vnode_mount(vp)) && !vfs_isrdonly(mp)) {
6396 VATTR_INIT(&vattr);
6397 if (np->n_flag & NACC) {
6398 vattr.va_access_time = np->n_atim;
6399 VATTR_SET_ACTIVE(&vattr, va_access_time);
6400 }
6401 if (np->n_flag & NUPD) {
6402 vattr.va_modify_time = np->n_mtim;
6403 VATTR_SET_ACTIVE(&vattr, va_modify_time);
6404 }
6405 nfs_node_unlock(np);
6406 vnode_setattr(vp, &vattr, ap->a_context);
6407 } else {
6408 nfs_node_unlock(np);
6409 }
6410 } else {
6411 nfs_node_unlock(np);
6412 }
6413 return (VOCALL(spec_vnodeop_p, VOFFSET(vnop_close), ap));
6414 }
6415
6416 #if FIFO
6417 extern vnop_t **fifo_vnodeop_p;
6418
6419 /*
6420 * Read wrapper for fifos.
6421 */
6422 int
6423 nfsfifo_vnop_read(
6424 struct vnop_read_args /* {
6425 struct vnodeop_desc *a_desc;
6426 vnode_t a_vp;
6427 struct uio *a_uio;
6428 int a_ioflag;
6429 vfs_context_t a_context;
6430 } */ *ap)
6431 {
6432 nfsnode_t np = VTONFS(ap->a_vp);
6433 struct timeval now;
6434 int error;
6435
6436 /*
6437 * Set access flag.
6438 */
6439 if ((error = nfs_node_lock(np)))
6440 return (error);
6441 np->n_flag |= NACC;
6442 microtime(&now);
6443 np->n_atim.tv_sec = now.tv_sec;
6444 np->n_atim.tv_nsec = now.tv_usec * 1000;
6445 nfs_node_unlock(np);
6446 return (VOCALL(fifo_vnodeop_p, VOFFSET(vnop_read), ap));
6447 }
6448
6449 /*
6450 * Write wrapper for fifos.
6451 */
6452 int
6453 nfsfifo_vnop_write(
6454 struct vnop_write_args /* {
6455 struct vnodeop_desc *a_desc;
6456 vnode_t a_vp;
6457 struct uio *a_uio;
6458 int a_ioflag;
6459 vfs_context_t a_context;
6460 } */ *ap)
6461 {
6462 nfsnode_t np = VTONFS(ap->a_vp);
6463 struct timeval now;
6464 int error;
6465
6466 /*
6467 * Set update flag.
6468 */
6469 if ((error = nfs_node_lock(np)))
6470 return (error);
6471 np->n_flag |= NUPD;
6472 microtime(&now);
6473 np->n_mtim.tv_sec = now.tv_sec;
6474 np->n_mtim.tv_nsec = now.tv_usec * 1000;
6475 nfs_node_unlock(np);
6476 return (VOCALL(fifo_vnodeop_p, VOFFSET(vnop_write), ap));
6477 }
6478
6479 /*
6480 * Close wrapper for fifos.
6481 *
6482 * Update the times on the nfsnode then do fifo close.
6483 */
6484 int
6485 nfsfifo_vnop_close(
6486 struct vnop_close_args /* {
6487 struct vnodeop_desc *a_desc;
6488 vnode_t a_vp;
6489 int a_fflag;
6490 vfs_context_t a_context;
6491 } */ *ap)
6492 {
6493 vnode_t vp = ap->a_vp;
6494 nfsnode_t np = VTONFS(vp);
6495 struct vnode_attr vattr;
6496 struct timeval now;
6497 mount_t mp;
6498 int error;
6499
6500 if ((error = nfs_node_lock(np)))
6501 return (error);
6502 if (np->n_flag & (NACC | NUPD)) {
6503 microtime(&now);
6504 if (np->n_flag & NACC) {
6505 np->n_atim.tv_sec = now.tv_sec;
6506 np->n_atim.tv_nsec = now.tv_usec * 1000;
6507 }
6508 if (np->n_flag & NUPD) {
6509 np->n_mtim.tv_sec = now.tv_sec;
6510 np->n_mtim.tv_nsec = now.tv_usec * 1000;
6511 }
6512 np->n_flag |= NCHG;
6513 if (!vnode_isinuse(vp, 1) && (mp = vnode_mount(vp)) && !vfs_isrdonly(mp)) {
6514 VATTR_INIT(&vattr);
6515 if (np->n_flag & NACC) {
6516 vattr.va_access_time = np->n_atim;
6517 VATTR_SET_ACTIVE(&vattr, va_access_time);
6518 }
6519 if (np->n_flag & NUPD) {
6520 vattr.va_modify_time = np->n_mtim;
6521 VATTR_SET_ACTIVE(&vattr, va_modify_time);
6522 }
6523 nfs_node_unlock(np);
6524 vnode_setattr(vp, &vattr, ap->a_context);
6525 } else {
6526 nfs_node_unlock(np);
6527 }
6528 } else {
6529 nfs_node_unlock(np);
6530 }
6531 return (VOCALL(fifo_vnodeop_p, VOFFSET(vnop_close), ap));
6532 }
6533 #endif /* FIFO */
6534
6535 /*ARGSUSED*/
6536 int
6537 nfs_vnop_ioctl(
6538 struct vnop_ioctl_args /* {
6539 struct vnodeop_desc *a_desc;
6540 vnode_t a_vp;
6541 u_int32_t a_command;
6542 caddr_t a_data;
6543 int a_fflag;
6544 vfs_context_t a_context;
6545 } */ *ap)
6546 {
6547 vfs_context_t ctx = ap->a_context;
6548 vnode_t vp = ap->a_vp;
6549 int error = ENOTTY;
6550
6551 switch (ap->a_command) {
6552
6553 case F_FULLFSYNC:
6554 if (vnode_vfsisrdonly(vp))
6555 return (EROFS);
6556 if (!VTONMP(vp))
6557 return (ENXIO);
6558 error = nfs_flush(VTONFS(vp), MNT_WAIT, vfs_context_thread(ctx), 0);
6559 break;
6560
6561 }
6562
6563 return (error);
6564 }
6565
6566 /*ARGSUSED*/
6567 int
6568 nfs_vnop_select(
6569 __unused struct vnop_select_args /* {
6570 struct vnodeop_desc *a_desc;
6571 vnode_t a_vp;
6572 int a_which;
6573 int a_fflags;
6574 void *a_wql;
6575 vfs_context_t a_context;
6576 } */ *ap)
6577 {
6578
6579 /*
6580 * We were once bogusly seltrue() which returns 1. Is this right?
6581 */
6582 return (1);
6583 }
6584
6585 /*
6586 * vnode OP for pagein using UPL
6587 *
6588 * No buffer I/O, just RPCs straight into the mapped pages.
6589 */
6590 int
6591 nfs_vnop_pagein(
6592 struct vnop_pagein_args /* {
6593 struct vnodeop_desc *a_desc;
6594 vnode_t a_vp;
6595 upl_t a_pl;
6596 vm_offset_t a_pl_offset;
6597 off_t a_f_offset;
6598 size_t a_size;
6599 int a_flags;
6600 vfs_context_t a_context;
6601 } */ *ap)
6602 {
6603 vnode_t vp = ap->a_vp;
6604 upl_t pl = ap->a_pl;
6605 size_t size = ap->a_size;
6606 off_t f_offset = ap->a_f_offset;
6607 vm_offset_t pl_offset = ap->a_pl_offset;
6608 int flags = ap->a_flags;
6609 thread_t thd;
6610 kauth_cred_t cred;
6611 nfsnode_t np = VTONFS(vp);
6612 size_t nmrsize, iosize, txsize, rxsize, retsize;
6613 off_t txoffset;
6614 struct nfsmount *nmp;
6615 int error = 0;
6616 vm_offset_t ioaddr, rxaddr;
6617 uio_t uio;
6618 char uio_buf [ UIO_SIZEOF(1) ];
6619 int nofreeupl = flags & UPL_NOCOMMIT;
6620 upl_page_info_t *plinfo;
6621 #define MAXPAGINGREQS 16 /* max outstanding RPCs for pagein/pageout */
6622 struct nfsreq *req[MAXPAGINGREQS];
6623 int nextsend, nextwait;
6624 uint32_t stategenid = 0, restart = 0;
6625 kern_return_t kret;
6626
6627 FSDBG(322, np, f_offset, size, flags);
6628 if (pl == (upl_t)NULL)
6629 panic("nfs_pagein: no upl");
6630
6631 if (size <= 0) {
6632 printf("nfs_pagein: invalid size %ld", size);
6633 if (!nofreeupl)
6634 (void) ubc_upl_abort(pl, 0);
6635 return (EINVAL);
6636 }
6637 if (f_offset < 0 || f_offset >= (off_t)np->n_size || (f_offset & PAGE_MASK_64)) {
6638 if (!nofreeupl)
6639 ubc_upl_abort_range(pl, pl_offset, size,
6640 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
6641 return (EINVAL);
6642 }
6643
6644 thd = vfs_context_thread(ap->a_context);
6645 cred = ubc_getcred(vp);
6646 if (!IS_VALID_CRED(cred))
6647 cred = vfs_context_ucred(ap->a_context);
6648
6649 uio = uio_createwithbuffer(1, f_offset, UIO_SYSSPACE, UIO_READ,
6650 &uio_buf, sizeof(uio_buf));
6651
6652 nmp = VTONMP(vp);
6653 if (!nmp) {
6654 if (!nofreeupl)
6655 ubc_upl_abort_range(pl, pl_offset, size,
6656 UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
6657 return (ENXIO);
6658 }
6659 nmrsize = nmp->nm_rsize;
6660
6661 plinfo = ubc_upl_pageinfo(pl);
6662 kret = ubc_upl_map(pl, &ioaddr);
6663 if (kret != KERN_SUCCESS)
6664 panic("nfs_vnop_pagein: ubc_upl_map() failed with (%d)", kret);
6665 ioaddr += pl_offset;
6666
6667 tryagain:
6668 if (nmp->nm_vers >= NFS_VER4)
6669 stategenid = nmp->nm_stategenid;
6670 txsize = rxsize = size;
6671 txoffset = f_offset;
6672 rxaddr = ioaddr;
6673
6674 bzero(req, sizeof(req));
6675 nextsend = nextwait = 0;
6676 do {
6677 if (np->n_flag & NREVOKE) {
6678 error = EIO;
6679 break;
6680 }
6681 /* send requests while we need to and have available slots */
6682 while ((txsize > 0) && (req[nextsend] == NULL)) {
6683 iosize = MIN(nmrsize, txsize);
6684 if ((error = nmp->nm_funcs->nf_read_rpc_async(np, txoffset, iosize, thd, cred, NULL, &req[nextsend]))) {
6685 req[nextsend] = NULL;
6686 break;
6687 }
6688 txoffset += iosize;
6689 txsize -= iosize;
6690 nextsend = (nextsend + 1) % MAXPAGINGREQS;
6691 }
6692 /* wait while we need to and break out if more requests to send */
6693 while ((rxsize > 0) && req[nextwait]) {
6694 iosize = retsize = MIN(nmrsize, rxsize);
6695 uio_reset(uio, uio_offset(uio), UIO_SYSSPACE, UIO_READ);
6696 uio_addiov(uio, CAST_USER_ADDR_T(rxaddr), iosize);
6697 FSDBG(322, uio_offset(uio), uio_resid(uio), rxaddr, rxsize);
6698 #if UPL_DEBUG
6699 upl_ubc_alias_set(pl, (uintptr_t) current_thread(), (uintptr_t) 2);
6700 #endif /* UPL_DEBUG */
6701 OSAddAtomic(1, &nfsstats.pageins);
6702 error = nmp->nm_funcs->nf_read_rpc_async_finish(np, req[nextwait], uio, &retsize, NULL);
6703 req[nextwait] = NULL;
6704 nextwait = (nextwait + 1) % MAXPAGINGREQS;
6705 if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error)) {
6706 lck_mtx_lock(&nmp->nm_lock);
6707 if ((error != NFSERR_GRACE) && (stategenid == nmp->nm_stategenid)) {
6708 NP(np, "nfs_vnop_pagein: error %d, initiating recovery", error);
6709 nfs_need_recover(nmp, error);
6710 }
6711 lck_mtx_unlock(&nmp->nm_lock);
6712 restart++;
6713 goto cancel;
6714 }
6715 if (error) {
6716 FSDBG(322, uio_offset(uio), uio_resid(uio), error, -1);
6717 break;
6718 }
6719 if (retsize < iosize) {
6720 /* Just zero fill the rest of the valid area. */
6721 int zcnt = iosize - retsize;
6722 bzero((char *)rxaddr + retsize, zcnt);
6723 FSDBG(324, uio_offset(uio), retsize, zcnt, rxaddr);
6724 uio_update(uio, zcnt);
6725 }
6726 rxaddr += iosize;
6727 rxsize -= iosize;
6728 if (txsize)
6729 break;
6730 }
6731 } while (!error && (txsize || rxsize));
6732
6733 restart = 0;
6734
6735 if (error) {
6736 cancel:
6737 /* cancel any outstanding requests */
6738 while (req[nextwait]) {
6739 nfs_request_async_cancel(req[nextwait]);
6740 req[nextwait] = NULL;
6741 nextwait = (nextwait + 1) % MAXPAGINGREQS;
6742 }
6743 if (np->n_flag & NREVOKE) {
6744 error = EIO;
6745 } else if (restart) {
6746 if (restart <= nfs_mount_state_max_restarts(nmp)) { /* guard against no progress */
6747 if (error == NFSERR_GRACE)
6748 tsleep(&nmp->nm_state, (PZERO-1), "nfsgrace", 2*hz);
6749 if (!(error = nfs_mount_state_wait_for_recovery(nmp)))
6750 goto tryagain;
6751 } else {
6752 NP(np, "nfs_pagein: too many restarts, aborting");
6753 }
6754 }
6755 }
6756
6757 ubc_upl_unmap(pl);
6758
6759 if (!nofreeupl) {
6760 if (error)
6761 ubc_upl_abort_range(pl, pl_offset, size,
6762 UPL_ABORT_ERROR |
6763 UPL_ABORT_FREE_ON_EMPTY);
6764 else
6765 ubc_upl_commit_range(pl, pl_offset, size,
6766 UPL_COMMIT_CLEAR_DIRTY |
6767 UPL_COMMIT_FREE_ON_EMPTY);
6768 }
6769 return (error);
6770 }
6771
6772
6773 /*
6774 * the following are needed only by nfs_pageout to know how to handle errors
6775 * see nfs_pageout comments on explanation of actions.
6776 * the errors here are copied from errno.h and errors returned by servers
6777 * are expected to match the same numbers here. If not, our actions maybe
6778 * erroneous.
6779 */
6780 char nfs_pageouterrorhandler(int);
6781 enum actiontype {NOACTION, DUMP, DUMPANDLOG, RETRY, RETRYWITHSLEEP, SEVER};
6782 #define NFS_ELAST 88
6783 static u_char errorcount[NFS_ELAST+1]; /* better be zeros when initialized */
6784 static const char errortooutcome[NFS_ELAST+1] = {
6785 NOACTION,
6786 DUMP, /* EPERM 1 Operation not permitted */
6787 DUMP, /* ENOENT 2 No such file or directory */
6788 DUMPANDLOG, /* ESRCH 3 No such process */
6789 RETRY, /* EINTR 4 Interrupted system call */
6790 DUMP, /* EIO 5 Input/output error */
6791 DUMP, /* ENXIO 6 Device not configured */
6792 DUMPANDLOG, /* E2BIG 7 Argument list too long */
6793 DUMPANDLOG, /* ENOEXEC 8 Exec format error */
6794 DUMPANDLOG, /* EBADF 9 Bad file descriptor */
6795 DUMPANDLOG, /* ECHILD 10 No child processes */
6796 DUMPANDLOG, /* EDEADLK 11 Resource deadlock avoided - was EAGAIN */
6797 RETRY, /* ENOMEM 12 Cannot allocate memory */
6798 DUMP, /* EACCES 13 Permission denied */
6799 DUMPANDLOG, /* EFAULT 14 Bad address */
6800 DUMPANDLOG, /* ENOTBLK 15 POSIX - Block device required */
6801 RETRY, /* EBUSY 16 Device busy */
6802 DUMP, /* EEXIST 17 File exists */
6803 DUMP, /* EXDEV 18 Cross-device link */
6804 DUMP, /* ENODEV 19 Operation not supported by device */
6805 DUMP, /* ENOTDIR 20 Not a directory */
6806 DUMP, /* EISDIR 21 Is a directory */
6807 DUMP, /* EINVAL 22 Invalid argument */
6808 DUMPANDLOG, /* ENFILE 23 Too many open files in system */
6809 DUMPANDLOG, /* EMFILE 24 Too many open files */
6810 DUMPANDLOG, /* ENOTTY 25 Inappropriate ioctl for device */
6811 DUMPANDLOG, /* ETXTBSY 26 Text file busy - POSIX */
6812 DUMP, /* EFBIG 27 File too large */
6813 DUMP, /* ENOSPC 28 No space left on device */
6814 DUMPANDLOG, /* ESPIPE 29 Illegal seek */
6815 DUMP, /* EROFS 30 Read-only file system */
6816 DUMP, /* EMLINK 31 Too many links */
6817 RETRY, /* EPIPE 32 Broken pipe */
6818 /* math software */
6819 DUMPANDLOG, /* EDOM 33 Numerical argument out of domain */
6820 DUMPANDLOG, /* ERANGE 34 Result too large */
6821 RETRY, /* EAGAIN/EWOULDBLOCK 35 Resource temporarily unavailable */
6822 DUMPANDLOG, /* EINPROGRESS 36 Operation now in progress */
6823 DUMPANDLOG, /* EALREADY 37 Operation already in progress */
6824 /* ipc/network software -- argument errors */
6825 DUMPANDLOG, /* ENOTSOC 38 Socket operation on non-socket */
6826 DUMPANDLOG, /* EDESTADDRREQ 39 Destination address required */
6827 DUMPANDLOG, /* EMSGSIZE 40 Message too long */
6828 DUMPANDLOG, /* EPROTOTYPE 41 Protocol wrong type for socket */
6829 DUMPANDLOG, /* ENOPROTOOPT 42 Protocol not available */
6830 DUMPANDLOG, /* EPROTONOSUPPORT 43 Protocol not supported */
6831 DUMPANDLOG, /* ESOCKTNOSUPPORT 44 Socket type not supported */
6832 DUMPANDLOG, /* ENOTSUP 45 Operation not supported */
6833 DUMPANDLOG, /* EPFNOSUPPORT 46 Protocol family not supported */
6834 DUMPANDLOG, /* EAFNOSUPPORT 47 Address family not supported by protocol family */
6835 DUMPANDLOG, /* EADDRINUSE 48 Address already in use */
6836 DUMPANDLOG, /* EADDRNOTAVAIL 49 Can't assign requested address */
6837 /* ipc/network software -- operational errors */
6838 RETRY, /* ENETDOWN 50 Network is down */
6839 RETRY, /* ENETUNREACH 51 Network is unreachable */
6840 RETRY, /* ENETRESET 52 Network dropped connection on reset */
6841 RETRY, /* ECONNABORTED 53 Software caused connection abort */
6842 RETRY, /* ECONNRESET 54 Connection reset by peer */
6843 RETRY, /* ENOBUFS 55 No buffer space available */
6844 RETRY, /* EISCONN 56 Socket is already connected */
6845 RETRY, /* ENOTCONN 57 Socket is not connected */
6846 RETRY, /* ESHUTDOWN 58 Can't send after socket shutdown */
6847 RETRY, /* ETOOMANYREFS 59 Too many references: can't splice */
6848 RETRY, /* ETIMEDOUT 60 Operation timed out */
6849 RETRY, /* ECONNREFUSED 61 Connection refused */
6850
6851 DUMPANDLOG, /* ELOOP 62 Too many levels of symbolic links */
6852 DUMP, /* ENAMETOOLONG 63 File name too long */
6853 RETRY, /* EHOSTDOWN 64 Host is down */
6854 RETRY, /* EHOSTUNREACH 65 No route to host */
6855 DUMP, /* ENOTEMPTY 66 Directory not empty */
6856 /* quotas & mush */
6857 DUMPANDLOG, /* PROCLIM 67 Too many processes */
6858 DUMPANDLOG, /* EUSERS 68 Too many users */
6859 DUMPANDLOG, /* EDQUOT 69 Disc quota exceeded */
6860 /* Network File System */
6861 DUMP, /* ESTALE 70 Stale NFS file handle */
6862 DUMP, /* EREMOTE 71 Too many levels of remote in path */
6863 DUMPANDLOG, /* EBADRPC 72 RPC struct is bad */
6864 DUMPANDLOG, /* ERPCMISMATCH 73 RPC version wrong */
6865 DUMPANDLOG, /* EPROGUNAVAIL 74 RPC prog. not avail */
6866 DUMPANDLOG, /* EPROGMISMATCH 75 Program version wrong */
6867 DUMPANDLOG, /* EPROCUNAVAIL 76 Bad procedure for program */
6868
6869 DUMPANDLOG, /* ENOLCK 77 No locks available */
6870 DUMPANDLOG, /* ENOSYS 78 Function not implemented */
6871 DUMPANDLOG, /* EFTYPE 79 Inappropriate file type or format */
6872 DUMPANDLOG, /* EAUTH 80 Authentication error */
6873 DUMPANDLOG, /* ENEEDAUTH 81 Need authenticator */
6874 /* Intelligent device errors */
6875 DUMPANDLOG, /* EPWROFF 82 Device power is off */
6876 DUMPANDLOG, /* EDEVERR 83 Device error, e.g. paper out */
6877 DUMPANDLOG, /* EOVERFLOW 84 Value too large to be stored in data type */
6878 /* Program loading errors */
6879 DUMPANDLOG, /* EBADEXEC 85 Bad executable */
6880 DUMPANDLOG, /* EBADARCH 86 Bad CPU type in executable */
6881 DUMPANDLOG, /* ESHLIBVERS 87 Shared library version mismatch */
6882 DUMPANDLOG, /* EBADMACHO 88 Malformed Macho file */
6883 };
6884
6885 char
6886 nfs_pageouterrorhandler(int error)
6887 {
6888 if (error > NFS_ELAST)
6889 return(DUMP);
6890 else
6891 return(errortooutcome[error]);
6892 }
6893
6894
6895 /*
6896 * vnode OP for pageout using UPL
6897 *
6898 * No buffer I/O, just RPCs straight from the mapped pages.
6899 * File size changes are not permitted in pageout.
6900 */
6901 int
6902 nfs_vnop_pageout(
6903 struct vnop_pageout_args /* {
6904 struct vnodeop_desc *a_desc;
6905 vnode_t a_vp;
6906 upl_t a_pl;
6907 vm_offset_t a_pl_offset;
6908 off_t a_f_offset;
6909 size_t a_size;
6910 int a_flags;
6911 vfs_context_t a_context;
6912 } */ *ap)
6913 {
6914 vnode_t vp = ap->a_vp;
6915 upl_t pl = ap->a_pl;
6916 size_t size = ap->a_size;
6917 off_t f_offset = ap->a_f_offset;
6918 vm_offset_t pl_offset = ap->a_pl_offset;
6919 int flags = ap->a_flags;
6920 nfsnode_t np = VTONFS(vp);
6921 thread_t thd;
6922 kauth_cred_t cred;
6923 struct nfsbuf *bp;
6924 struct nfsmount *nmp = VTONMP(vp);
6925 daddr64_t lbn;
6926 int error = 0, iomode;
6927 off_t off, txoffset, rxoffset;
6928 vm_offset_t ioaddr, txaddr, rxaddr;
6929 uio_t auio;
6930 char uio_buf [ UIO_SIZEOF(1) ];
6931 int nofreeupl = flags & UPL_NOCOMMIT;
6932 size_t nmwsize, biosize, iosize, pgsize, txsize, rxsize, xsize, remsize;
6933 struct nfsreq *req[MAXPAGINGREQS];
6934 int nextsend, nextwait, wverfset, commit;
6935 uint64_t wverf, wverf2;
6936 uint32_t stategenid = 0, vrestart = 0, restart = 0, vrestarts = 0, restarts = 0;
6937 kern_return_t kret;
6938
6939 FSDBG(323, f_offset, size, pl, pl_offset);
6940
6941 if (pl == (upl_t)NULL)
6942 panic("nfs_pageout: no upl");
6943
6944 if (size <= 0) {
6945 printf("nfs_pageout: invalid size %ld", size);
6946 if (!nofreeupl)
6947 ubc_upl_abort(pl, 0);
6948 return (EINVAL);
6949 }
6950
6951 if (!nmp) {
6952 if (!nofreeupl)
6953 ubc_upl_abort(pl, UPL_ABORT_DUMP_PAGES|UPL_ABORT_FREE_ON_EMPTY);
6954 return (ENXIO);
6955 }
6956 biosize = nmp->nm_biosize;
6957 nmwsize = nmp->nm_wsize;
6958
6959 nfs_data_lock_noupdate(np, NFS_DATA_LOCK_SHARED);
6960
6961 /*
6962 * Check to see whether the buffer is incore.
6963 * If incore and not busy, invalidate it from the cache.
6964 */
6965 for (iosize = 0; iosize < size; iosize += xsize) {
6966 off = f_offset + iosize;
6967 /* need make sure we do things on block boundaries */
6968 xsize = biosize - (off % biosize);
6969 if (off + xsize > f_offset + size)
6970 xsize = f_offset + size - off;
6971 lbn = (daddr64_t)(off / biosize);
6972 lck_mtx_lock(nfs_buf_mutex);
6973 if ((bp = nfs_buf_incore(np, lbn))) {
6974 FSDBG(323, off, bp, bp->nb_lflags, bp->nb_flags);
6975 if (nfs_buf_acquire(bp, NBAC_NOWAIT, 0, 0)) {
6976 lck_mtx_unlock(nfs_buf_mutex);
6977 nfs_data_unlock_noupdate(np);
6978 /* no panic. just tell vm we are busy */
6979 if (!nofreeupl)
6980 ubc_upl_abort(pl, 0);
6981 return (EBUSY);
6982 }
6983 if (bp->nb_dirtyend > 0) {
6984 /*
6985 * if there's a dirty range in the buffer, check
6986 * to see if it extends beyond the pageout region
6987 *
6988 * if the dirty region lies completely within the
6989 * pageout region, we just invalidate the buffer
6990 * because it's all being written out now anyway.
6991 *
6992 * if any of the dirty region lies outside the
6993 * pageout region, we'll try to clip the dirty
6994 * region to eliminate the portion that's being
6995 * paged out. If that's not possible, because
6996 * the dirty region extends before and after the
6997 * pageout region, then we'll just return EBUSY.
6998 */
6999 off_t boff, start, end;
7000 boff = NBOFF(bp);
7001 start = off;
7002 end = off + xsize;
7003 /* clip end to EOF */
7004 if (end > (off_t)np->n_size)
7005 end = np->n_size;
7006 start -= boff;
7007 end -= boff;
7008 if ((bp->nb_dirtyoff < start) &&
7009 (bp->nb_dirtyend > end)) {
7010 /*
7011 * not gonna be able to clip the dirty region
7012 *
7013 * But before returning the bad news, move the
7014 * buffer to the start of the delwri list and
7015 * give the list a push to try to flush the
7016 * buffer out.
7017 */
7018 FSDBG(323, np, bp, 0xd00deebc, EBUSY);
7019 nfs_buf_remfree(bp);
7020 TAILQ_INSERT_HEAD(&nfsbufdelwri, bp, nb_free);
7021 nfsbufdelwricnt++;
7022 nfs_buf_drop(bp);
7023 nfs_buf_delwri_push(1);
7024 lck_mtx_unlock(nfs_buf_mutex);
7025 nfs_data_unlock_noupdate(np);
7026 if (!nofreeupl)
7027 ubc_upl_abort(pl, 0);
7028 return (EBUSY);
7029 }
7030 if ((bp->nb_dirtyoff < start) ||
7031 (bp->nb_dirtyend > end)) {
7032 /* clip dirty region, if necessary */
7033 if (bp->nb_dirtyoff < start)
7034 bp->nb_dirtyend = min(bp->nb_dirtyend, start);
7035 if (bp->nb_dirtyend > end)
7036 bp->nb_dirtyoff = max(bp->nb_dirtyoff, end);
7037 FSDBG(323, bp, bp->nb_dirtyoff, bp->nb_dirtyend, 0xd00dee00);
7038 /* we're leaving this block dirty */
7039 nfs_buf_drop(bp);
7040 lck_mtx_unlock(nfs_buf_mutex);
7041 continue;
7042 }
7043 }
7044 nfs_buf_remfree(bp);
7045 lck_mtx_unlock(nfs_buf_mutex);
7046 SET(bp->nb_flags, NB_INVAL);
7047 nfs_node_lock_force(np);
7048 if (ISSET(bp->nb_flags, NB_NEEDCOMMIT)) {
7049 CLR(bp->nb_flags, NB_NEEDCOMMIT);
7050 np->n_needcommitcnt--;
7051 CHECK_NEEDCOMMITCNT(np);
7052 }
7053 nfs_node_unlock(np);
7054 nfs_buf_release(bp, 1);
7055 } else {
7056 lck_mtx_unlock(nfs_buf_mutex);
7057 }
7058 }
7059
7060 thd = vfs_context_thread(ap->a_context);
7061 cred = ubc_getcred(vp);
7062 if (!IS_VALID_CRED(cred))
7063 cred = vfs_context_ucred(ap->a_context);
7064
7065 nfs_node_lock_force(np);
7066 if (np->n_flag & NWRITEERR) {
7067 error = np->n_error;
7068 nfs_node_unlock(np);
7069 nfs_data_unlock_noupdate(np);
7070 if (!nofreeupl)
7071 ubc_upl_abort_range(pl, pl_offset, size,
7072 UPL_ABORT_FREE_ON_EMPTY);
7073 return (error);
7074 }
7075 nfs_node_unlock(np);
7076
7077 if (f_offset < 0 || f_offset >= (off_t)np->n_size ||
7078 f_offset & PAGE_MASK_64 || size & PAGE_MASK_64) {
7079 nfs_data_unlock_noupdate(np);
7080 if (!nofreeupl)
7081 ubc_upl_abort_range(pl, pl_offset, size,
7082 UPL_ABORT_FREE_ON_EMPTY);
7083 return (EINVAL);
7084 }
7085
7086 kret = ubc_upl_map(pl, &ioaddr);
7087 if (kret != KERN_SUCCESS)
7088 panic("nfs_vnop_pageout: ubc_upl_map() failed with (%d)", kret);
7089 ioaddr += pl_offset;
7090
7091 if ((u_quad_t)f_offset + size > np->n_size)
7092 xsize = np->n_size - f_offset;
7093 else
7094 xsize = size;
7095
7096 pgsize = round_page_64(xsize);
7097 if ((size > pgsize) && !nofreeupl)
7098 ubc_upl_abort_range(pl, pl_offset + pgsize, size - pgsize,
7099 UPL_ABORT_FREE_ON_EMPTY);
7100
7101 /*
7102 * check for partial page and clear the
7103 * contents past end of the file before
7104 * releasing it in the VM page cache
7105 */
7106 if ((u_quad_t)f_offset < np->n_size && (u_quad_t)f_offset + size > np->n_size) {
7107 size_t io = np->n_size - f_offset;
7108 bzero((caddr_t)(ioaddr + io), size - io);
7109 FSDBG(321, np->n_size, f_offset, f_offset + io, size - io);
7110 }
7111 nfs_data_unlock_noupdate(np);
7112
7113 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_WRITE,
7114 &uio_buf, sizeof(uio_buf));
7115
7116 tryagain:
7117 if (nmp->nm_vers >= NFS_VER4)
7118 stategenid = nmp->nm_stategenid;
7119 wverf = wverf2 = wverfset = 0;
7120 txsize = rxsize = xsize;
7121 txoffset = rxoffset = f_offset;
7122 txaddr = rxaddr = ioaddr;
7123 commit = NFS_WRITE_FILESYNC;
7124
7125 bzero(req, sizeof(req));
7126 nextsend = nextwait = 0;
7127 do {
7128 if (np->n_flag & NREVOKE) {
7129 error = EIO;
7130 break;
7131 }
7132 /* send requests while we need to and have available slots */
7133 while ((txsize > 0) && (req[nextsend] == NULL)) {
7134 iosize = MIN(nmwsize, txsize);
7135 uio_reset(auio, txoffset, UIO_SYSSPACE, UIO_WRITE);
7136 uio_addiov(auio, CAST_USER_ADDR_T(txaddr), iosize);
7137 FSDBG(323, uio_offset(auio), iosize, txaddr, txsize);
7138 OSAddAtomic(1, &nfsstats.pageouts);
7139 nfs_node_lock_force(np);
7140 np->n_numoutput++;
7141 nfs_node_unlock(np);
7142 vnode_startwrite(vp);
7143 iomode = NFS_WRITE_UNSTABLE;
7144 if ((error = nmp->nm_funcs->nf_write_rpc_async(np, auio, iosize, thd, cred, iomode, NULL, &req[nextsend]))) {
7145 req[nextsend] = NULL;
7146 vnode_writedone(vp);
7147 nfs_node_lock_force(np);
7148 np->n_numoutput--;
7149 nfs_node_unlock(np);
7150 break;
7151 }
7152 txaddr += iosize;
7153 txoffset += iosize;
7154 txsize -= iosize;
7155 nextsend = (nextsend + 1) % MAXPAGINGREQS;
7156 }
7157 /* wait while we need to and break out if more requests to send */
7158 while ((rxsize > 0) && req[nextwait]) {
7159 iosize = remsize = MIN(nmwsize, rxsize);
7160 error = nmp->nm_funcs->nf_write_rpc_async_finish(np, req[nextwait], &iomode, &iosize, &wverf2);
7161 req[nextwait] = NULL;
7162 nextwait = (nextwait + 1) % MAXPAGINGREQS;
7163 vnode_writedone(vp);
7164 nfs_node_lock_force(np);
7165 np->n_numoutput--;
7166 nfs_node_unlock(np);
7167 if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error)) {
7168 lck_mtx_lock(&nmp->nm_lock);
7169 if ((error != NFSERR_GRACE) && (stategenid == nmp->nm_stategenid)) {
7170 NP(np, "nfs_vnop_pageout: error %d, initiating recovery", error);
7171 nfs_need_recover(nmp, error);
7172 }
7173 lck_mtx_unlock(&nmp->nm_lock);
7174 restart = 1;
7175 goto cancel;
7176 }
7177 if (error) {
7178 FSDBG(323, rxoffset, rxsize, error, -1);
7179 break;
7180 }
7181 if (!wverfset) {
7182 wverf = wverf2;
7183 wverfset = 1;
7184 } else if (wverf != wverf2) {
7185 /* verifier changed, so we need to restart all the writes */
7186 vrestart = 1;
7187 goto cancel;
7188 }
7189 /* Retain the lowest commitment level returned. */
7190 if (iomode < commit)
7191 commit = iomode;
7192 rxaddr += iosize;
7193 rxoffset += iosize;
7194 rxsize -= iosize;
7195 remsize -= iosize;
7196 if (remsize > 0) {
7197 /* need to try sending the remainder */
7198 iosize = remsize;
7199 uio_reset(auio, rxoffset, UIO_SYSSPACE, UIO_WRITE);
7200 uio_addiov(auio, CAST_USER_ADDR_T(rxaddr), remsize);
7201 iomode = NFS_WRITE_UNSTABLE;
7202 error = nfs_write_rpc2(np, auio, thd, cred, &iomode, &wverf2);
7203 if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error)) {
7204 NP(np, "nfs_vnop_pageout: restart: error %d", error);
7205 lck_mtx_lock(&nmp->nm_lock);
7206 if ((error != NFSERR_GRACE) && (stategenid == nmp->nm_stategenid)) {
7207 NP(np, "nfs_vnop_pageout: error %d, initiating recovery", error);
7208 nfs_need_recover(nmp, error);
7209 }
7210 lck_mtx_unlock(&nmp->nm_lock);
7211 restart = 1;
7212 goto cancel;
7213 }
7214 if (error) {
7215 FSDBG(323, rxoffset, rxsize, error, -1);
7216 break;
7217 }
7218 if (wverf != wverf2) {
7219 /* verifier changed, so we need to restart all the writes */
7220 vrestart = 1;
7221 goto cancel;
7222 }
7223 if (iomode < commit)
7224 commit = iomode;
7225 rxaddr += iosize;
7226 rxoffset += iosize;
7227 rxsize -= iosize;
7228 }
7229 if (txsize)
7230 break;
7231 }
7232 } while (!error && (txsize || rxsize));
7233
7234 vrestart = 0;
7235
7236 if (!error && (commit != NFS_WRITE_FILESYNC)) {
7237 error = nmp->nm_funcs->nf_commit_rpc(np, f_offset, xsize, cred, wverf);
7238 if (error == NFSERR_STALEWRITEVERF) {
7239 vrestart = 1;
7240 error = EIO;
7241 }
7242 }
7243
7244 if (error) {
7245 cancel:
7246 /* cancel any outstanding requests */
7247 while (req[nextwait]) {
7248 nfs_request_async_cancel(req[nextwait]);
7249 req[nextwait] = NULL;
7250 nextwait = (nextwait + 1) % MAXPAGINGREQS;
7251 vnode_writedone(vp);
7252 nfs_node_lock_force(np);
7253 np->n_numoutput--;
7254 nfs_node_unlock(np);
7255 }
7256 if (np->n_flag & NREVOKE) {
7257 error = EIO;
7258 } else {
7259 if (vrestart) {
7260 if (++vrestarts <= 100) /* guard against no progress */
7261 goto tryagain;
7262 NP(np, "nfs_pageout: too many restarts, aborting");
7263 FSDBG(323, f_offset, xsize, ERESTART, -1);
7264 }
7265 if (restart) {
7266 if (restarts <= nfs_mount_state_max_restarts(nmp)) { /* guard against no progress */
7267 if (error == NFSERR_GRACE)
7268 tsleep(&nmp->nm_state, (PZERO-1), "nfsgrace", 2*hz);
7269 if (!(error = nfs_mount_state_wait_for_recovery(nmp)))
7270 goto tryagain;
7271 } else {
7272 NP(np, "nfs_pageout: too many restarts, aborting");
7273 FSDBG(323, f_offset, xsize, ERESTART, -1);
7274 }
7275 }
7276 }
7277 }
7278
7279 ubc_upl_unmap(pl);
7280
7281 /*
7282 * We've had several different solutions on what to do when the pageout
7283 * gets an error. If we don't handle it, and return an error to the
7284 * caller, vm, it will retry . This can end in endless looping
7285 * between vm and here doing retries of the same page. Doing a dump
7286 * back to vm, will get it out of vm's knowledge and we lose whatever
7287 * data existed. This is risky, but in some cases necessary. For
7288 * example, the initial fix here was to do that for ESTALE. In that case
7289 * the server is telling us that the file is no longer the same. We
7290 * would not want to keep paging out to that. We also saw some 151
7291 * errors from Auspex server and NFSv3 can return errors higher than
7292 * ELAST. Those along with NFS known server errors we will "dump" from
7293 * vm. Errors we don't expect to occur, we dump and log for further
7294 * analysis. Errors that could be transient, networking ones,
7295 * we let vm "retry". Lastly, errors that we retry, but may have potential
7296 * to storm the network, we "retrywithsleep". "sever" will be used in
7297 * in the future to dump all pages of object for cases like ESTALE.
7298 * All this is the basis for the states returned and first guesses on
7299 * error handling. Tweaking expected as more statistics are gathered.
7300 * Note, in the long run we may need another more robust solution to
7301 * have some kind of persistant store when the vm cannot dump nor keep
7302 * retrying as a solution, but this would be a file architectural change
7303 */
7304 if (!nofreeupl) { /* otherwise stacked file system has to handle this */
7305 if (error) {
7306 int abortflags = 0;
7307 char action = nfs_pageouterrorhandler(error);
7308
7309 switch (action) {
7310 case DUMP:
7311 abortflags = UPL_ABORT_DUMP_PAGES|UPL_ABORT_FREE_ON_EMPTY;
7312 break;
7313 case DUMPANDLOG:
7314 abortflags = UPL_ABORT_DUMP_PAGES|UPL_ABORT_FREE_ON_EMPTY;
7315 if (error <= NFS_ELAST) {
7316 if ((errorcount[error] % 100) == 0)
7317 NP(np, "nfs_pageout: unexpected error %d. dumping vm page", error);
7318 errorcount[error]++;
7319 }
7320 break;
7321 case RETRY:
7322 abortflags = UPL_ABORT_FREE_ON_EMPTY;
7323 break;
7324 case RETRYWITHSLEEP:
7325 abortflags = UPL_ABORT_FREE_ON_EMPTY;
7326 /* pri unused. PSOCK for placeholder. */
7327 tsleep(&lbolt, PSOCK, "nfspageout", 0);
7328 break;
7329 case SEVER: /* not implemented */
7330 default:
7331 NP(np, "nfs_pageout: action %d not expected", action);
7332 break;
7333 }
7334
7335 ubc_upl_abort_range(pl, pl_offset, pgsize, abortflags);
7336 /* return error in all cases above */
7337
7338 } else {
7339 ubc_upl_commit_range(pl, pl_offset, pgsize,
7340 UPL_COMMIT_CLEAR_DIRTY |
7341 UPL_COMMIT_FREE_ON_EMPTY);
7342 }
7343 }
7344 return (error);
7345 }
7346
7347 /* Blktooff derives file offset given a logical block number */
7348 int
7349 nfs_vnop_blktooff(
7350 struct vnop_blktooff_args /* {
7351 struct vnodeop_desc *a_desc;
7352 vnode_t a_vp;
7353 daddr64_t a_lblkno;
7354 off_t *a_offset;
7355 } */ *ap)
7356 {
7357 int biosize;
7358 vnode_t vp = ap->a_vp;
7359 struct nfsmount *nmp = VTONMP(vp);
7360
7361 if (!nmp)
7362 return (ENXIO);
7363 biosize = nmp->nm_biosize;
7364
7365 *ap->a_offset = (off_t)(ap->a_lblkno * biosize);
7366
7367 return (0);
7368 }
7369
7370 int
7371 nfs_vnop_offtoblk(
7372 struct vnop_offtoblk_args /* {
7373 struct vnodeop_desc *a_desc;
7374 vnode_t a_vp;
7375 off_t a_offset;
7376 daddr64_t *a_lblkno;
7377 } */ *ap)
7378 {
7379 int biosize;
7380 vnode_t vp = ap->a_vp;
7381 struct nfsmount *nmp = VTONMP(vp);
7382
7383 if (!nmp)
7384 return (ENXIO);
7385 biosize = nmp->nm_biosize;
7386
7387 *ap->a_lblkno = (daddr64_t)(ap->a_offset / biosize);
7388
7389 return (0);
7390 }
7391
7392 /*
7393 * vnode change monitoring
7394 */
7395 int
7396 nfs_vnop_monitor(
7397 struct vnop_monitor_args /* {
7398 struct vnodeop_desc *a_desc;
7399 vnode_t a_vp;
7400 uint32_t a_events;
7401 uint32_t a_flags;
7402 void *a_handle;
7403 vfs_context_t a_context;
7404 } */ *ap)
7405 {
7406 nfsnode_t np = VTONFS(ap->a_vp);
7407 struct nfsmount *nmp = VTONMP(ap->a_vp);
7408 int error = 0;
7409
7410 if (!nmp)
7411 return (ENXIO);
7412
7413 /* make sure that the vnode's monitoring status is up to date */
7414 lck_mtx_lock(&nmp->nm_lock);
7415 if (vnode_ismonitored(ap->a_vp)) {
7416 /* This vnode is currently being monitored, make sure we're tracking it. */
7417 if (np->n_monlink.le_next == NFSNOLIST) {
7418 LIST_INSERT_HEAD(&nmp->nm_monlist, np, n_monlink);
7419 nfs_mount_sock_thread_wake(nmp);
7420 }
7421 } else {
7422 /* This vnode is no longer being monitored, make sure we're not tracking it. */
7423 /* Wait for any in-progress getattr to complete first. */
7424 while (np->n_mflag & NMMONSCANINPROG) {
7425 struct timespec ts = { 1, 0 };
7426 np->n_mflag |= NMMONSCANWANT;
7427 msleep(&np->n_mflag, &nmp->nm_lock, PZERO-1, "nfswaitmonscan", &ts);
7428 }
7429 if (np->n_monlink.le_next != NFSNOLIST) {
7430 LIST_REMOVE(np, n_monlink);
7431 np->n_monlink.le_next = NFSNOLIST;
7432 }
7433 }
7434 lck_mtx_unlock(&nmp->nm_lock);
7435
7436 return (error);
7437 }
7438
7439 /*
7440 * Send a vnode notification for the given events.
7441 */
7442 void
7443 nfs_vnode_notify(nfsnode_t np, uint32_t events)
7444 {
7445 struct nfsmount *nmp = NFSTONMP(np);
7446 struct nfs_vattr nvattr;
7447 struct vnode_attr vattr, *vap = NULL;
7448 struct timeval now;
7449
7450 microuptime(&now);
7451 if ((np->n_evtstamp == now.tv_sec) || !nmp) {
7452 /* delay sending this notify */
7453 np->n_events |= events;
7454 return;
7455 }
7456 events |= np->n_events;
7457 np->n_events = 0;
7458 np->n_evtstamp = now.tv_sec;
7459
7460 vfs_get_notify_attributes(&vattr);
7461 if (!nfs_getattrcache(np, &nvattr, 0)) {
7462 vap = &vattr;
7463 VATTR_INIT(vap);
7464 VATTR_RETURN(vap, va_fsid, vfs_statfs(nmp->nm_mountp)->f_fsid.val[0]);
7465 VATTR_RETURN(vap, va_fileid, nvattr.nva_fileid);
7466 VATTR_RETURN(vap, va_mode, nvattr.nva_mode);
7467 VATTR_RETURN(vap, va_uid, nvattr.nva_uid);
7468 VATTR_RETURN(vap, va_gid, nvattr.nva_gid);
7469 VATTR_RETURN(vap, va_nlink, nvattr.nva_nlink);
7470 }
7471 vnode_notify(NFSTOV(np), events, vap);
7472 }