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