2 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1989, 1993
31 * The Regents of the University of California. All rights reserved.
33 * This code is derived from software contributed to Berkeley by
34 * Rick Macklem at The University of Guelph.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
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.
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
64 * @(#)nfs_serv.c 8.7 (Berkeley) 5/14/95
65 * FreeBSD-Id: nfs_serv.c,v 1.52 1997/10/28 15:59:05 bde Exp $
68 #include <sys/param.h>
69 #include <sys/systm.h>
71 #include <sys/kauth.h>
72 #include <sys/unistd.h>
73 #include <sys/malloc.h>
74 #include <sys/vnode.h>
75 #include <sys/mount_internal.h>
76 #include <sys/socket.h>
77 #include <sys/socketvar.h>
78 #include <sys/kpi_mbuf.h>
79 #include <sys/dirent.h>
81 #include <sys/kernel.h>
83 #include <sys/vnode_internal.h>
84 #include <sys/uio_internal.h>
85 #include <libkern/OSAtomic.h>
86 #include <sys/fsevents.h>
87 #include <kern/thread_call.h>
91 #include <sys/vmparam.h>
93 #include <sys/fcntl.h>
95 #include <netinet/in.h>
97 #include <nfs/nfsproto.h>
98 #include <nfs/rpcv2.h>
100 #include <nfs/xdr_subs.h>
101 #include <nfs/nfsm_subs.h>
102 #include <nfs/nfsrvcache.h>
103 #include <nfs/nfs_gss.h>
106 #include <security/mac.h>
107 #include <security/mac_framework.h>
116 int nfsd_thread_count
= 0;
117 int nfsd_thread_max
= 0;
118 lck_grp_t
*nfsd_lck_grp
;
119 lck_mtx_t
*nfsd_mutex
;
120 struct nfsd_head nfsd_head
, nfsd_queue
;
122 lck_grp_t
*nfsrv_slp_rwlock_group
;
123 lck_grp_t
*nfsrv_slp_mutex_group
;
124 struct nfsrv_sockhead nfsrv_socklist
, nfsrv_sockwg
,
125 nfsrv_sockwait
, nfsrv_sockwork
;
126 struct nfsrv_sock
*nfsrv_udpsock
= NULL
;
127 struct nfsrv_sock
*nfsrv_udp6sock
= NULL
;
130 struct nfsrv_expfs_list nfsrv_exports
;
131 struct nfsrv_export_hashhead
*nfsrv_export_hashtbl
= NULL
;
132 int nfsrv_export_hash_size
= NFSRVEXPHASHSZ
;
133 u_long nfsrv_export_hash
;
134 lck_grp_t
*nfsrv_export_rwlock_group
;
135 lck_rw_t nfsrv_export_rwlock
;
138 /* NFS server file modification event generator */
139 struct nfsrv_fmod_hashhead
*nfsrv_fmod_hashtbl
;
140 u_long nfsrv_fmod_hash
;
141 lck_grp_t
*nfsrv_fmod_grp
;
142 lck_mtx_t
*nfsrv_fmod_mutex
;
143 static int nfsrv_fmod_timer_on
= 0;
144 int nfsrv_fsevents_enabled
= 1;
147 /* NFS server timers */
149 thread_call_t nfsrv_fmod_timer_call
;
151 thread_call_t nfsrv_idlesock_timer_call
;
152 thread_call_t nfsrv_wg_timer_call
;
153 int nfsrv_wg_timer_on
;
155 /* globals for the active user list */
156 uint32_t nfsrv_user_stat_enabled
= 1;
157 uint32_t nfsrv_user_stat_node_count
= 0;
158 uint32_t nfsrv_user_stat_max_idle_sec
= NFSRV_USER_STAT_DEF_IDLE_SEC
;
159 uint32_t nfsrv_user_stat_max_nodes
= NFSRV_USER_STAT_DEF_MAX_NODES
;
160 lck_grp_t
*nfsrv_active_user_mutex_group
;
162 int nfsrv_wg_delay
= NFSRV_WGATHERDELAY
* 1000;
163 int nfsrv_wg_delay_v3
= 0;
167 int nfsrv_authorize(vnode_t
,vnode_t
,kauth_action_t
,vfs_context_t
,struct nfs_export_options
*,int);
168 int nfsrv_wg_coalesce(struct nfsrv_descript
*, struct nfsrv_descript
*);
169 void nfsrv_modified(vnode_t
, vfs_context_t
);
171 extern void IOSleep(int);
172 extern int safe_getpath(struct vnode
*dvp
, char *leafname
, char *path
, int _len
, int *truncated_path
);
175 * Initialize the data structures for the server.
178 #define NFSRV_NOT_INITIALIZED 0
179 #define NFSRV_INITIALIZING 1
180 #define NFSRV_INITIALIZED 2
181 static volatile UInt32 nfsrv_initted
= NFSRV_NOT_INITIALIZED
;
184 nfsrv_is_initialized(void)
186 return (nfsrv_initted
== NFSRV_INITIALIZED
);
192 /* make sure we init only once */
193 if (!OSCompareAndSwap(NFSRV_NOT_INITIALIZED
, NFSRV_INITIALIZING
, &nfsrv_initted
)) {
194 /* wait until initialization is complete */
195 while (!nfsrv_is_initialized())
200 if (sizeof (struct nfsrv_sock
) > NFS_SVCALLOC
)
201 printf("struct nfsrv_sock bloated (> %dbytes)\n",NFS_SVCALLOC
);
203 /* init nfsd mutex */
204 nfsd_lck_grp
= lck_grp_alloc_init("nfsd", LCK_GRP_ATTR_NULL
);
205 nfsd_mutex
= lck_mtx_alloc_init(nfsd_lck_grp
, LCK_ATTR_NULL
);
207 /* init slp rwlock */
208 nfsrv_slp_rwlock_group
= lck_grp_alloc_init("nfsrv-slp-rwlock", LCK_GRP_ATTR_NULL
);
209 nfsrv_slp_mutex_group
= lck_grp_alloc_init("nfsrv-slp-mutex", LCK_GRP_ATTR_NULL
);
211 /* init export data structures */
212 LIST_INIT(&nfsrv_exports
);
213 nfsrv_export_rwlock_group
= lck_grp_alloc_init("nfsrv-export-rwlock", LCK_GRP_ATTR_NULL
);
214 lck_rw_init(&nfsrv_export_rwlock
, nfsrv_export_rwlock_group
, LCK_ATTR_NULL
);
216 /* init active user list mutex structures */
217 nfsrv_active_user_mutex_group
= lck_grp_alloc_init("nfs-active-user-mutex", LCK_GRP_ATTR_NULL
);
219 /* init nfs server request cache mutex */
220 nfsrv_reqcache_lck_grp
= lck_grp_alloc_init("nfsrv_reqcache", LCK_GRP_ATTR_NULL
);
221 nfsrv_reqcache_mutex
= lck_mtx_alloc_init(nfsrv_reqcache_lck_grp
, LCK_ATTR_NULL
);
224 /* init NFS server file modified event generation */
225 nfsrv_fmod_hashtbl
= hashinit(NFSRVFMODHASHSZ
, M_TEMP
, &nfsrv_fmod_hash
);
226 nfsrv_fmod_grp
= lck_grp_alloc_init("nfsrv_fmod", LCK_GRP_ATTR_NULL
);
227 nfsrv_fmod_mutex
= lck_mtx_alloc_init(nfsrv_fmod_grp
, LCK_ATTR_NULL
);
230 /* initialize NFS server timer callouts */
232 nfsrv_fmod_timer_call
= thread_call_allocate(nfsrv_fmod_timer
, NULL
);
234 nfsrv_idlesock_timer_call
= thread_call_allocate(nfsrv_idlesock_timer
, NULL
);
235 nfsrv_wg_timer_call
= thread_call_allocate(nfsrv_wg_timer
, NULL
);
237 /* Init server data structures */
238 TAILQ_INIT(&nfsrv_socklist
);
239 TAILQ_INIT(&nfsrv_sockwait
);
240 TAILQ_INIT(&nfsrv_sockwork
);
241 TAILQ_INIT(&nfsrv_sockwg
);
242 TAILQ_INIT(&nfsd_head
);
243 TAILQ_INIT(&nfsd_queue
);
244 nfsrv_udpsock
= NULL
;
245 nfsrv_udp6sock
= NULL
;
247 /* Setup the up-call handling */
250 /* initialization complete */
251 nfsrv_initted
= NFSRV_INITIALIZED
;
257 * NFS version 2 and 3 server request processing functions
259 * These functions take the following parameters:
261 * struct nfsrv_descript *nd - the NFS request descriptor
262 * struct nfsrv_sock *slp - the NFS socket the request came in on
263 * vfs_context_t ctx - VFS context
264 * mbuf_t *mrepp - pointer to hold the reply mbuf list
266 * These routines generally have 3 phases:
268 * 1 - break down and validate the RPC request in the mbuf chain
269 * provided in nd->nd_nmreq.
270 * 2 - perform the vnode operations for the request
271 * (many are very similar to syscalls in vfs_syscalls.c and
272 * should therefore be kept in sync with those implementations)
273 * 3 - build the RPC reply in an mbuf chain (nmrep) and return the mbuf chain
278 * nfs v3 access service
282 struct nfsrv_descript
*nd
,
283 struct nfsrv_sock
*slp
,
287 struct nfsm_chain
*nmreq
, nmrep
;
290 struct vnode_attr vattr
;
291 struct nfs_filehandle nfh
;
293 kauth_action_t testaction
;
294 struct nfs_export
*nx
;
295 struct nfs_export_options
*nxo
;
300 nmreq
= &nd
->nd_nmreq
;
301 nfsm_chain_null(&nmrep
);
305 nfsm_chain_get_fh_ptr(error
, nmreq
, NFS_VER3
, nfh
.nfh_fhp
, nfh
.nfh_len
);
306 nfsm_chain_get_32(error
, nmreq
, nfsmode
);
308 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
311 /* update export stats */
312 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
314 /* update active user stats */
315 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
317 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
321 * Each NFS mode bit is tested separately.
323 * XXX this code is nominally correct, but returns a pessimistic
324 * rather than optimistic result. It will be necessary to add
325 * an NFS-specific interface to the vnode_authorize code to
326 * obtain good performance in the optimistic mode.
328 if (nfsmode
& NFS_ACCESS_READ
) {
329 testaction
= vnode_isdir(vp
) ? KAUTH_VNODE_LIST_DIRECTORY
: KAUTH_VNODE_READ_DATA
;
330 if (nfsrv_authorize(vp
, NULL
, testaction
, ctx
, nxo
, 0))
331 nfsmode
&= ~NFS_ACCESS_READ
;
333 if ((nfsmode
& NFS_ACCESS_LOOKUP
) &&
335 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
, nxo
, 0)))
336 nfsmode
&= ~NFS_ACCESS_LOOKUP
;
337 if (nfsmode
& NFS_ACCESS_MODIFY
) {
338 if (vnode_isdir(vp
)) {
340 KAUTH_VNODE_ADD_FILE
|
341 KAUTH_VNODE_ADD_SUBDIRECTORY
|
342 KAUTH_VNODE_DELETE_CHILD
;
345 KAUTH_VNODE_WRITE_DATA
;
347 if (nfsrv_authorize(vp
, NULL
, testaction
, ctx
, nxo
, 0))
348 nfsmode
&= ~NFS_ACCESS_MODIFY
;
350 if (nfsmode
& NFS_ACCESS_EXTEND
) {
351 if (vnode_isdir(vp
)) {
353 KAUTH_VNODE_ADD_FILE
|
354 KAUTH_VNODE_ADD_SUBDIRECTORY
;
357 KAUTH_VNODE_WRITE_DATA
|
358 KAUTH_VNODE_APPEND_DATA
;
360 if (nfsrv_authorize(vp
, NULL
, testaction
, ctx
, nxo
, 0))
361 nfsmode
&= ~NFS_ACCESS_EXTEND
;
365 * Note concerning NFS_ACCESS_DELETE:
366 * For hard links, the answer may be wrong if the vnode
367 * has multiple parents with different permissions.
368 * Also, some clients (e.g. MacOSX 10.3) may incorrectly
369 * interpret the missing/cleared DELETE bit.
370 * So we'll just leave the DELETE bit alone. At worst,
371 * we're telling the client it might be able to do
372 * something it really can't.
375 if ((nfsmode
& NFS_ACCESS_EXECUTE
) &&
377 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, ctx
, nxo
, 0)))
378 nfsmode
&= ~NFS_ACCESS_EXECUTE
;
380 /* get postop attributes */
381 nfsm_srv_vattr_init(&vattr
, NFS_VER3
);
382 attrerr
= vnode_getattr(vp
, &vattr
, ctx
);
386 nd
->nd_repstat
= error
;
387 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(NFS_VER3
) + NFSX_UNSIGNED
);
389 *mrepp
= nmrep
.nmc_mhead
;
390 nfsmout_on_status(nd
, error
);
391 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &vattr
);
393 nfsm_chain_add_32(error
, &nmrep
, nfsmode
);
395 nfsm_chain_build_done(error
, &nmrep
);
399 nfsm_chain_cleanup(&nmrep
);
406 * nfs getattr service
410 struct nfsrv_descript
*nd
,
411 struct nfsrv_sock
*slp
,
415 struct nfsm_chain
*nmreq
, nmrep
;
416 struct vnode_attr vattr
;
419 struct nfs_filehandle nfh
;
420 struct nfs_export
*nx
;
421 struct nfs_export_options
*nxo
;
424 nmreq
= &nd
->nd_nmreq
;
425 nfsm_chain_null(&nmrep
);
429 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
431 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
434 /* update export stats */
435 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
437 /* update active user stats */
438 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
440 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
444 if (mac_vnode_check_open(ctx
, vp
, FREAD
))
449 nfsm_srv_vattr_init(&vattr
, nd
->nd_vers
);
450 error
= vnode_getattr(vp
, &vattr
, ctx
);
453 /* XXXab: Comment in the VFS code makes it sound like
454 * some arguments can be filtered out, but not
455 * what it actually means. Hopefully not like
456 * they gonna set mtime to 0 or something. For
457 * now trust there are no shenanigans here.
459 error
= mac_vnode_check_getattr(ctx
, NOCRED
, vp
, &vattr
);
468 nd
->nd_repstat
= error
;
469 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_FATTR(nd
->nd_vers
));
471 *mrepp
= nmrep
.nmc_mhead
;
472 nfsmout_if(nd
->nd_repstat
);
473 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &vattr
);
475 nfsm_chain_build_done(error
, &nmrep
);
479 nfsm_chain_cleanup(&nmrep
);
486 * nfs setattr service
490 struct nfsrv_descript
*nd
,
491 struct nfsrv_sock
*slp
,
495 struct nfsm_chain
*nmreq
, nmrep
;
496 struct vnode_attr preattr
, postattr
;
497 struct vnode_attr vattr
, *vap
= &vattr
;
499 struct nfs_export
*nx
;
500 struct nfs_export_options
*nxo
;
501 int error
, preattrerr
, postattrerr
, gcheck
;
502 struct nfs_filehandle nfh
;
503 struct timespec guard
= { 0, 0 };
504 kauth_action_t action
;
508 preattrerr
= postattrerr
= ENOENT
;
510 nmreq
= &nd
->nd_nmreq
;
511 nfsm_chain_null(&nmrep
);
515 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
519 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
520 if (nd
->nd_vers
== NFS_VER3
) {
521 nfsm_chain_get_32(error
, nmreq
, gcheck
);
523 nfsm_chain_get_time(error
, nmreq
, nd
->nd_vers
, guard
.tv_sec
, guard
.tv_nsec
);
528 * Save the original credential UID in case they are
529 * mapped and we need to map the IDs in the attributes.
531 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
534 * Now that we have all the fields, lets do it.
536 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
539 /* update export stats */
540 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
542 /* update active user stats */
543 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
545 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
548 if (nd
->nd_vers
== NFS_VER3
) {
549 nfsm_srv_pre_vattr_init(&preattr
);
550 error
= preattrerr
= vnode_getattr(vp
, &preattr
, ctx
);
551 if (!error
&& gcheck
&& VATTR_IS_SUPPORTED(&preattr
, va_change_time
) &&
552 (preattr
.va_change_time
.tv_sec
!= guard
.tv_sec
||
553 preattr
.va_change_time
.tv_nsec
!= guard
.tv_nsec
))
554 error
= NFSERR_NOT_SYNC
;
555 if (!preattrerr
&& !VATTR_ALL_SUPPORTED(&preattr
))
561 * If the credentials were mapped, we should
562 * map the same values in the attributes.
564 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nd
->nd_cr
) != saved_uid
)) {
566 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nd
->nd_cr
));
567 if (kauth_cred_ismember_gid(nd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
568 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nd
->nd_cr
));
571 /* Authorize the attribute changes. */
572 error
= vnode_authattr(vp
, vap
, &action
, ctx
);
574 error
= nfsrv_authorize(vp
, NULL
, action
, ctx
, nxo
, 0);
577 if (!error
&& mac_vnode_check_open(ctx
, vp
, FREAD
|FWRITE
))
582 if (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
)) {
583 error
= mac_vnode_check_setowner(ctx
, vp
,
584 VATTR_IS_ACTIVE(vap
, va_uid
) ? vap
->va_uid
: -1,
585 VATTR_IS_ACTIVE(vap
, va_gid
) ? vap
->va_gid
: -1);
588 if (!error
&& VATTR_IS_ACTIVE(vap
, va_mode
)) {
589 error
= mac_vnode_check_setmode(ctx
, vp
, (mode_t
)vap
->va_mode
);
592 if (!error
&& VATTR_IS_ACTIVE(vap
, va_data_size
)) {
593 /* NOTE: File has not been open for NFS case, so NOCRED for filecred */
594 error
= mac_vnode_check_truncate(ctx
, NOCRED
, vp
);
596 /* set utimes case */
597 if (!error
&& (VATTR_IS_ACTIVE(vap
, va_access_time
) || VATTR_IS_ACTIVE(vap
, va_modify_time
))) {
598 struct timespec current_time
;
599 nanotime(¤t_time
);
601 error
= mac_vnode_check_setutimes(ctx
, vp
,
602 VATTR_IS_ACTIVE(vap
, va_access_time
) ? vap
->va_access_time
: current_time
,
603 VATTR_IS_ACTIVE(vap
, va_modify_time
) ? vap
->va_modify_time
: current_time
);
607 /* set the new attributes */
609 error
= vnode_setattr(vp
, vap
, ctx
);
611 if (!error
|| (nd
->nd_vers
== NFS_VER3
)) {
612 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
613 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
623 nd
->nd_repstat
= error
;
624 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCORFATTR(nd
->nd_vers
));
626 *mrepp
= nmrep
.nmc_mhead
;
627 nfsmout_on_status(nd
, error
);
628 if (nd
->nd_vers
== NFS_VER3
)
629 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
630 preattrerr
, &preattr
, postattrerr
, &postattr
);
632 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
634 nfsm_chain_build_done(error
, &nmrep
);
636 nfsm_chain_cleanup(&nmrep
);
647 struct nfsrv_descript
*nd
,
648 struct nfsrv_sock
*slp
,
653 vnode_t vp
, dirp
= NULL
;
654 struct nfs_filehandle dnfh
, nfh
;
655 struct nfs_export
*nx
= NULL
;
656 struct nfs_export_options
*nxo
;
657 int error
, attrerr
, dirattrerr
, isdotdot
;
660 struct vnode_attr va
, dirattr
, *vap
= &va
;
661 struct nfsm_chain
*nmreq
, nmrep
;
664 attrerr
= dirattrerr
= ENOENT
;
665 nmreq
= &nd
->nd_nmreq
;
666 nfsm_chain_null(&nmrep
);
667 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
669 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, dnfh
.nfh_fhp
, dnfh
.nfh_len
);
670 nfsm_chain_get_32(error
, nmreq
, len
);
671 nfsm_name_len_check(error
, nd
, len
);
674 ni
.ni_cnd
.cn_nameiop
= LOOKUP
;
676 ni
.ni_op
= OP_LOOKUP
;
678 ni
.ni_cnd
.cn_flags
= LOCKLEAF
;
679 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
680 isdotdot
= ((len
== 2) && (ni
.ni_cnd
.cn_pnbuf
[0] == '.') && (ni
.ni_cnd
.cn_pnbuf
[1] == '.'));
682 error
= nfsrv_namei(nd
, ctx
, &ni
, &dnfh
, &dirp
, &nx
, &nxo
);
684 /* update export stats */
685 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
687 /* update active user stats */
688 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
690 if (!error
&& mac_vnode_check_open(ctx
, ni
.ni_vp
, FREAD
)) {
705 if (nd
->nd_vers
== NFS_VER3
) {
706 nfsm_srv_vattr_init(&dirattr
, NFS_VER3
);
707 dirattrerr
= vnode_getattr(dirp
, &dirattr
, ctx
);
716 error
= nfsrv_vptofh(nx
, nd
->nd_vers
, (isdotdot
? &dnfh
: NULL
), vp
, ctx
, &nfh
);
718 nfsm_srv_vattr_init(vap
, nd
->nd_vers
);
719 attrerr
= vnode_getattr(vp
, vap
, ctx
);
725 nd
->nd_repstat
= error
;
726 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(nd
->nd_vers
, &nfh
) +
727 NFSX_POSTOPORFATTR(nd
->nd_vers
) + NFSX_POSTOPATTR(nd
->nd_vers
));
729 *mrepp
= nmrep
.nmc_mhead
;
730 if (nd
->nd_repstat
) {
731 if (nd
->nd_vers
== NFS_VER3
)
732 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, dirattrerr
, &dirattr
);
735 nfsm_chain_add_fh(error
, &nmrep
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
736 if (nd
->nd_vers
== NFS_VER3
) {
737 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, vap
);
738 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, dirattrerr
, &dirattr
);
740 error
= nfsm_chain_add_fattr(nd
, &nmrep
, vap
);
743 nfsm_chain_build_done(error
, &nmrep
);
745 nfsm_chain_cleanup(&nmrep
);
752 * nfs readlink service
756 struct nfsrv_descript
*nd
,
757 struct nfsrv_sock
*slp
,
761 int error
, mpcnt
, tlen
, len
, attrerr
;
763 struct vnode_attr vattr
;
764 struct nfs_filehandle nfh
;
765 struct nfs_export
*nx
;
766 struct nfs_export_options
*nxo
;
767 struct nfsm_chain
*nmreq
, nmrep
;
770 char uio_buf
[ UIO_SIZEOF(4) ];
771 char *uio_bufp
= &uio_buf
[0];
772 int uio_buflen
= UIO_SIZEOF(4);
776 nmreq
= &nd
->nd_nmreq
;
777 nfsm_chain_null(&nmrep
);
780 len
= NFS_MAXPATHLEN
;
782 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
785 /* get mbuf list to hold symlink path */
786 error
= nfsm_mbuf_get_list(len
, &mpath
, &mpcnt
);
789 uio_buflen
= UIO_SIZEOF(mpcnt
);
790 MALLOC(uio_bufp
, char*, uio_buflen
, M_TEMP
, M_WAITOK
);
795 auio
= uio_createwithbuffer(mpcnt
, 0, UIO_SYSSPACE
, UIO_READ
, uio_bufp
, uio_buflen
);
800 for (mp
= mpath
; mp
; mp
= mbuf_next(mp
))
801 uio_addiov(auio
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), mbuf_len(mp
));
803 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
806 /* update export stats */
807 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
809 /* update active user stats */
810 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
812 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
815 if (vnode_vtype(vp
) != VLNK
) {
816 if (nd
->nd_vers
== NFS_VER3
)
823 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, ctx
, nxo
, 0);
825 if (mac_vnode_check_open(ctx
, vp
, FREAD
))
829 error
= mac_vnode_check_readlink(ctx
, vp
);
832 error
= VNOP_READLINK(vp
, auio
, ctx
);
834 if (nd
->nd_vers
== NFS_VER3
) {
835 nfsm_srv_vattr_init(&vattr
, NFS_VER3
);
836 attrerr
= vnode_getattr(vp
, &vattr
, ctx
);
848 nd
->nd_repstat
= error
;
849 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_UNSIGNED
);
851 *mrepp
= nmrep
.nmc_mhead
;
852 nfsmout_on_status(nd
, error
);
853 if (nd
->nd_vers
== NFS_VER3
)
854 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &vattr
);
855 if (error
|| nd
->nd_repstat
) {
856 nfsm_chain_build_done(error
, &nmrep
);
859 if (auio
&& (uio_resid(auio
) > 0)) {
860 len
-= uio_resid(auio
);
861 tlen
= nfsm_rndup(len
);
862 nfsm_adj(mpath
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
864 nfsm_chain_add_32(error
, &nmrep
, len
);
865 nfsm_chain_build_done(error
, &nmrep
);
867 error
= mbuf_setnext(nmrep
.nmc_mcur
, mpath
);
875 if (uio_bufp
!= &uio_buf
[0])
876 FREE(uio_bufp
, M_TEMP
);
878 nfsm_chain_cleanup(&nmrep
);
889 struct nfsrv_descript
*nd
,
890 struct nfsrv_sock
*slp
,
894 int error
, attrerr
, mreadcnt
;
895 uint32_t reqlen
, maxlen
, count
, len
, tlen
, left
;
898 struct nfs_filehandle nfh
;
899 struct nfs_export
*nx
;
900 struct nfs_export_options
*nxo
;
902 char *uio_bufp
= NULL
;
903 struct vnode_attr vattr
, *vap
= &vattr
;
906 char uio_buf
[ UIO_SIZEOF(0) ];
907 struct nfsm_chain
*nmreq
, nmrep
;
911 nmreq
= &nd
->nd_nmreq
;
912 nfsm_chain_null(&nmrep
);
916 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
918 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
920 if (nd
->nd_vers
== NFS_VER3
)
921 nfsm_chain_get_64(error
, nmreq
, off
);
923 nfsm_chain_get_32(error
, nmreq
, off
);
924 nfsm_chain_get_32(error
, nmreq
, reqlen
);
925 maxlen
= NFSRV_NDMAXDATA(nd
);
929 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
932 /* update export stats */
933 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
935 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
938 if (vnode_vtype(vp
) != VREG
) {
939 if (nd
->nd_vers
== NFS_VER3
)
942 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
946 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, ctx
, nxo
, 1)))
947 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, ctx
, nxo
, 1);
951 error
= mac_vnode_check_open(ctx
, vp
, FREAD
);
955 /* XXXab: Do we need to do this?! */
956 error
= mac_vnode_check_read(ctx
, vfs_context_ucred(ctx
), vp
);
959 /* mac_vnode_check_exec() can't be done here. */
964 nfsm_srv_vattr_init(vap
, nd
->nd_vers
);
965 attrerr
= vnode_getattr(vp
, vap
, ctx
);
970 if ((u_quad_t
)off
>= vap
->va_data_size
)
972 else if (((u_quad_t
)off
+ reqlen
) > vap
->va_data_size
)
973 count
= nfsm_rndup(vap
->va_data_size
- off
);
979 /* get mbuf list to hold read data */
980 error
= nfsm_mbuf_get_list(count
, &mread
, &mreadcnt
);
982 MALLOC(uio_bufp
, char *, UIO_SIZEOF(mreadcnt
), M_TEMP
, M_WAITOK
);
984 auio
= uio_createwithbuffer(mreadcnt
, off
, UIO_SYSSPACE
,
985 UIO_READ
, uio_bufp
, UIO_SIZEOF(mreadcnt
));
986 if (!uio_bufp
|| !auio
) {
990 for (m
= mread
; m
; m
= mbuf_next(m
))
991 uio_addiov(auio
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(m
)), mbuf_len(m
));
992 error
= VNOP_READ(vp
, auio
, IO_NODELOCKED
, ctx
);
994 auio
= uio_createwithbuffer(0, 0, UIO_SYSSPACE
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
1002 if (!error
|| (nd
->nd_vers
== NFS_VER3
)) {
1003 nfsm_srv_vattr_init(vap
, nd
->nd_vers
);
1004 attrerr
= vnode_getattr(vp
, vap
, ctx
);
1005 if (!error
&& (nd
->nd_vers
== NFS_VER2
))
1006 error
= attrerr
; /* NFSv2 must have attributes to return */
1013 /* trim off any data not actually read */
1014 len
-= uio_resid(auio
);
1015 tlen
= nfsm_rndup(len
);
1016 if (count
!= tlen
|| tlen
!= len
)
1017 nfsm_adj(mread
, count
- tlen
, tlen
- len
);
1020 /* assemble reply */
1021 nd
->nd_repstat
= error
;
1022 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPORFATTR(nd
->nd_vers
) + 3 * NFSX_UNSIGNED
);
1024 *mrepp
= nmrep
.nmc_mhead
;
1025 nfsmout_on_status(nd
, error
);
1026 if (nd
->nd_vers
== NFS_VER3
)
1027 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, vap
);
1028 if (error
|| nd
->nd_repstat
) {
1029 nfsm_chain_build_done(error
, &nmrep
);
1032 if (nd
->nd_vers
== NFS_VER3
) {
1033 nfsm_chain_add_32(error
, &nmrep
, len
);
1034 nfsm_chain_add_32(error
, &nmrep
, (len
< reqlen
) ? TRUE
: FALSE
);
1036 error
= nfsm_chain_add_fattr(nd
, &nmrep
, vap
);
1038 nfsm_chain_add_32(error
, &nmrep
, len
);
1039 nfsm_chain_build_done(error
, &nmrep
);
1041 error
= mbuf_setnext(nmrep
.nmc_mcur
, mread
);
1045 /* update export stats */
1046 NFSStatAdd64(&nx
->nx_stats
.bytes_read
, len
);
1048 /* update active user stats */
1049 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, len
, 0);
1055 if (uio_bufp
!= NULL
)
1056 FREE(uio_bufp
, M_TEMP
);
1058 nfsm_chain_cleanup(&nmrep
);
1066 * NFS File modification reporting
1068 * When the contents of a file are changed, a "content modified"
1069 * fsevent needs to be issued. Normally this would be done at
1070 * file close time. This is difficult for NFS because the protocol
1071 * has no "close" operation. The client sends a stream of write
1072 * requests that just stop. So we keep a hash table full of
1073 * vnodes that have been written to recently, and issue a
1074 * "content modified" fsevent only if there are no writes to
1075 * a vnode for nfsrv_fmod_pendtime milliseconds.
1077 int nfsrv_fmod_pending
; /* count of vnodes being written to */
1078 int nfsrv_fmod_pendtime
= 1000; /* msec to wait */
1079 int nfsrv_fmod_min_interval
= 100; /* msec min interval between callbacks */
1082 * This function is called via the kernel's callout
1083 * mechanism. Calls are made only when there are
1084 * vnodes pending a fsevent creation, and no more
1085 * frequently than every nfsrv_fmod_min_interval ms.
1088 nfsrv_fmod_timer(__unused
void *param0
, __unused
void *param1
)
1090 struct nfsrv_fmod_hashhead
*headp
, firehead
;
1091 struct nfsrv_fmod
*fp
, *nfp
, *pfp
;
1092 uint64_t timenow
, next_deadline
;
1093 int interval
= 0, i
, fmod_fire
;
1095 LIST_INIT(&firehead
);
1096 lck_mtx_lock(nfsrv_fmod_mutex
);
1098 clock_get_uptime(&timenow
);
1099 clock_interval_to_deadline(nfsrv_fmod_pendtime
, 1000 * 1000,
1103 * Scan all the hash chains
1106 for (i
= 0; i
< NFSRVFMODHASHSZ
; i
++) {
1108 * For each hash chain, look for an entry
1109 * that has exceeded the deadline.
1111 headp
= &nfsrv_fmod_hashtbl
[i
];
1112 LIST_FOREACH(fp
, headp
, fm_link
) {
1113 if (timenow
>= fp
->fm_deadline
)
1115 if (fp
->fm_deadline
< next_deadline
)
1116 next_deadline
= fp
->fm_deadline
;
1120 * If we have an entry that's exceeded the
1121 * deadline, then the same is true for all
1122 * following entries in the chain, since they're
1123 * sorted in time order.
1127 /* move each entry to the fire list */
1128 nfp
= LIST_NEXT(fp
, fm_link
);
1129 LIST_REMOVE(fp
, fm_link
);
1132 LIST_INSERT_AFTER(pfp
, fp
, fm_link
);
1134 LIST_INSERT_HEAD(&firehead
, fp
, fm_link
);
1141 lck_mtx_unlock(nfsrv_fmod_mutex
);
1143 * Fire off the content modified fsevent for each
1144 * entry and free it.
1146 LIST_FOREACH_SAFE(fp
, &firehead
, fm_link
, nfp
) {
1147 if (nfsrv_fsevents_enabled
) {
1148 fp
->fm_context
.vc_thread
= current_thread();
1149 add_fsevent(FSE_CONTENT_MODIFIED
, &fp
->fm_context
,
1150 FSE_ARG_VNODE
, fp
->fm_vp
,
1153 vnode_put(fp
->fm_vp
);
1154 kauth_cred_unref(&fp
->fm_context
.vc_ucred
);
1155 LIST_REMOVE(fp
, fm_link
);
1158 lck_mtx_lock(nfsrv_fmod_mutex
);
1159 nfsrv_fmod_pending
-= fmod_fire
;
1164 * If there are still pending entries, set up another
1165 * callout to handle them later. Set the timeout deadline
1166 * so that the callout happens when the oldest pending
1167 * entry is ready to send its fsevent.
1169 if (nfsrv_fmod_pending
> 0) {
1170 interval
= (next_deadline
- timenow
) / (1000 * 1000);
1171 if (interval
< nfsrv_fmod_min_interval
)
1172 interval
= nfsrv_fmod_min_interval
;
1175 nfsrv_fmod_timer_on
= interval
> 0;
1176 if (nfsrv_fmod_timer_on
)
1177 nfs_interval_timer_start(nfsrv_fmod_timer_call
, interval
);
1179 lck_mtx_unlock(nfsrv_fmod_mutex
);
1183 * When a vnode has been written to, enter it in the hash
1184 * table of vnodes pending creation of an fsevent. If the
1185 * callout timer isn't already running, schedule a callback
1186 * for nfsrv_fmod_pendtime msec from now.
1189 nfsrv_modified(vnode_t vp
, vfs_context_t ctx
)
1192 struct nfsrv_fmod
*fp
;
1193 struct nfsrv_fmod_hashhead
*head
;
1195 lck_mtx_lock(nfsrv_fmod_mutex
);
1198 * Compute the time in the future when the
1199 * content modified fsevent is to be issued.
1201 clock_interval_to_deadline(nfsrv_fmod_pendtime
, 1000 * 1000, &deadline
);
1204 * Check if there's already a file content change fsevent
1205 * pending for this vnode. If there is, update its
1206 * timestamp and make sure it's at the front of the hash chain.
1208 head
= &nfsrv_fmod_hashtbl
[NFSRVFMODHASH(vp
)];
1209 LIST_FOREACH(fp
, head
, fm_link
) {
1210 if (vp
== fp
->fm_vp
) {
1211 fp
->fm_deadline
= deadline
;
1212 if (fp
!= LIST_FIRST(head
)) {
1213 LIST_REMOVE(fp
, fm_link
);
1214 LIST_INSERT_HEAD(head
, fp
, fm_link
);
1216 lck_mtx_unlock(nfsrv_fmod_mutex
);
1222 * First content change fsevent for this vnode.
1223 * Allocate a new file mod entry and add it
1224 * on the front of the hash chain.
1226 if (vnode_get(vp
) != 0)
1228 MALLOC(fp
, struct nfsrv_fmod
*, sizeof(*fp
), M_TEMP
, M_WAITOK
);
1234 kauth_cred_ref(vfs_context_ucred(ctx
));
1235 fp
->fm_context
= *ctx
;
1236 fp
->fm_deadline
= deadline
;
1237 LIST_INSERT_HEAD(head
, fp
, fm_link
);
1240 * If added to an empty hash table, then set the
1241 * callout timer to go off after nfsrv_fmod_pendtime.
1243 nfsrv_fmod_pending
++;
1244 if (!nfsrv_fmod_timer_on
) {
1245 nfsrv_fmod_timer_on
= 1;
1246 nfs_interval_timer_start(nfsrv_fmod_timer_call
,
1247 nfsrv_fmod_pendtime
);
1250 lck_mtx_unlock(nfsrv_fmod_mutex
);
1253 #endif /* CONFIG_FSE */
1260 struct nfsrv_descript
*nd
,
1261 struct nfsrv_sock
*slp
,
1265 struct vnode_attr preattr
, postattr
;
1266 int error
, preattrerr
, postattrerr
;
1267 int ioflags
, len
, retlen
;
1269 int stable
= NFS_WRITE_FILESYNC
;
1272 struct nfs_filehandle nfh
;
1273 struct nfs_export
*nx
;
1274 struct nfs_export_options
*nxo
;
1276 char *uio_bufp
= NULL
;
1279 struct nfsm_chain
*nmreq
, nmrep
;
1281 if (nd
->nd_nmreq
.nmc_mhead
== NULL
) {
1287 preattrerr
= postattrerr
= ENOENT
;
1288 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
1289 nmreq
= &nd
->nd_nmreq
;
1290 nfsm_chain_null(&nmrep
);
1294 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
1296 if (nd
->nd_vers
== NFS_VER3
) {
1297 nfsm_chain_get_64(error
, nmreq
, off
);
1298 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1299 nfsm_chain_get_32(error
, nmreq
, stable
);
1301 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1302 nfsm_chain_get_32(error
, nmreq
, off
);
1303 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1305 stable
= NFS_WRITE_UNSTABLE
;
1307 nfsm_chain_get_32(error
, nmreq
, len
);
1312 * For NFS Version 2, it is not obvious what a write of zero length
1313 * should do, but I might as well be consistent with Version 3,
1314 * which is to return ok so long as there are no permission problems.
1318 error
= nfsm_chain_trim_data(nmreq
, len
, &mlen
);
1323 if ((len
> NFSRV_MAXDATA
) || (len
< 0) || (mlen
< len
)) {
1327 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
1330 /* update export stats */
1331 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
1333 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
1336 if (nd
->nd_vers
== NFS_VER3
) {
1337 nfsm_srv_pre_vattr_init(&preattr
);
1338 preattrerr
= vnode_getattr(vp
, &preattr
, ctx
);
1340 if (vnode_vtype(vp
) != VREG
) {
1341 if (nd
->nd_vers
== NFS_VER3
)
1344 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1347 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, ctx
, nxo
, 1);
1352 error
= mac_vnode_check_open(ctx
, vp
, FWRITE
);
1356 /* XXXab: Do we need to do this?! */
1357 error
= mac_vnode_check_write(ctx
, vfs_context_ucred(ctx
), vp
);
1366 for (mcount
=0, m
=nmreq
->nmc_mcur
; m
; m
= mbuf_next(m
))
1367 if (mbuf_len(m
) > 0)
1369 MALLOC(uio_bufp
, char *, UIO_SIZEOF(mcount
), M_TEMP
, M_WAITOK
);
1371 auio
= uio_createwithbuffer(mcount
, off
, UIO_SYSSPACE
, UIO_WRITE
, uio_bufp
, UIO_SIZEOF(mcount
));
1372 if (!uio_bufp
|| !auio
)
1375 for (m
= nmreq
->nmc_mcur
; m
; m
= mbuf_next(m
))
1376 if ((mlen
= mbuf_len(m
)) > 0)
1377 uio_addiov(auio
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(m
)), mlen
);
1379 * XXX The IO_METASYNC flag indicates that all metadata (and not just
1380 * enough to ensure data integrity) mus be written to stable storage
1381 * synchronously. (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1383 if (stable
== NFS_WRITE_UNSTABLE
)
1384 ioflags
= IO_NODELOCKED
;
1385 else if (stable
== NFS_WRITE_DATASYNC
)
1386 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1388 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1390 error
= VNOP_WRITE(vp
, auio
, ioflags
, ctx
);
1391 OSAddAtomic64(1, &nfsstats
.srvvop_writes
);
1393 /* update export stats */
1394 NFSStatAdd64(&nx
->nx_stats
.bytes_written
, len
);
1396 /* update active user stats */
1397 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, len
);
1400 if (nfsrv_fsevents_enabled
&& !error
&& need_fsevent(FSE_CONTENT_MODIFIED
, vp
))
1401 nfsrv_modified(vp
, ctx
);
1404 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
1405 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
1406 if (!error
&& (nd
->nd_vers
== NFS_VER2
))
1407 error
= postattrerr
; /* NFSv2 must have attributes to return */
1412 /* assemble reply */
1413 nd
->nd_repstat
= error
;
1414 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_PREOPATTR(nd
->nd_vers
) +
1415 NFSX_POSTOPORFATTR(nd
->nd_vers
) + 2 * NFSX_UNSIGNED
+
1416 NFSX_WRITEVERF(nd
->nd_vers
));
1418 *mrepp
= nmrep
.nmc_mhead
;
1419 nfsmout_on_status(nd
, error
);
1420 if (nd
->nd_vers
== NFS_VER3
) {
1421 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
1422 preattrerr
, &preattr
, postattrerr
, &postattr
);
1423 nfsmout_if(error
|| nd
->nd_repstat
);
1424 nfsm_chain_add_32(error
, &nmrep
, retlen
);
1425 /* If nfsrv_async is set, then pretend the write was FILESYNC. */
1426 if ((stable
== NFS_WRITE_UNSTABLE
) && !nfsrv_async
)
1427 nfsm_chain_add_32(error
, &nmrep
, stable
);
1429 nfsm_chain_add_32(error
, &nmrep
, NFS_WRITE_FILESYNC
);
1430 /* write verifier */
1431 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_sec
);
1432 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_usec
);
1434 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
1437 nfsm_chain_build_done(error
, &nmrep
);
1440 if (uio_bufp
!= NULL
)
1441 FREE(uio_bufp
, M_TEMP
);
1443 nfsm_chain_cleanup(&nmrep
);
1450 * NFS write service with write gathering support. Called when
1451 * nfsrv_wg_delay > 0.
1452 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1453 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1457 #define NWDELAYHASH(sock, f) \
1458 (&(sock)->ns_wdelayhashtbl[(*((u_int32_t *)(f))) % NFS_WDELAYHASHSIZ])
1459 /* These macros compare nfsrv_descript structures. */
1460 #define NFSW_CONTIG(o, n) \
1461 (((o)->nd_eoff >= (n)->nd_off) && nfsrv_fhmatch(&(o)->nd_fh, &(n)->nd_fh))
1463 * XXX The following is an incorrect comparison; it fails to take into account
1464 * XXX scoping of MAC labels, but we currently lack KPI for credential
1467 #define NFSW_SAMECRED(o, n) \
1468 (!bcmp((caddr_t)(o)->nd_cr, (caddr_t)(n)->nd_cr, \
1469 sizeof (struct ucred)))
1473 struct nfsrv_descript
**ndp
,
1474 struct nfsrv_sock
*slp
,
1478 struct nfsrv_descript
*nd
, *wp
, *owp
, *swp
;
1479 struct nfs_export
*nx
;
1480 struct nfs_export_options
*nxo
;
1481 struct nfsrv_wg_delayhash
*wpp
;
1483 struct vnode_attr preattr
, postattr
;
1484 int error
, mlen
, i
, ioflags
, tlen
;
1485 int preattrerr
, postattrerr
;
1489 char *uio_bufp
= NULL
;
1492 struct nfsm_chain
*nmreq
, nmrep
;
1495 preattrerr
= postattrerr
= ENOENT
;
1496 nfsm_chain_null(&nmrep
);
1503 nmreq
= &nd
->nd_nmreq
;
1504 LIST_INIT(&nd
->nd_coalesce
);
1506 nd
->nd_stable
= NFS_WRITE_FILESYNC
;
1508 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1509 nd
->nd_time
= cur_usec
+
1510 ((nd
->nd_vers
== NFS_VER3
) ? nfsrv_wg_delay_v3
: nfsrv_wg_delay
);
1512 /* Now, get the write header... */
1513 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nd
->nd_fh
.nfh_fhp
, nd
->nd_fh
.nfh_len
);
1514 /* XXX shouldn't we be checking for invalid FHs before doing any more work? */
1516 if (nd
->nd_vers
== NFS_VER3
) {
1517 nfsm_chain_get_64(error
, nmreq
, nd
->nd_off
);
1518 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1519 nfsm_chain_get_32(error
, nmreq
, nd
->nd_stable
);
1521 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1522 nfsm_chain_get_32(error
, nmreq
, nd
->nd_off
);
1523 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1525 nd
->nd_stable
= NFS_WRITE_UNSTABLE
;
1527 nfsm_chain_get_32(error
, nmreq
, nd
->nd_len
);
1529 nd
->nd_eoff
= nd
->nd_off
+ nd
->nd_len
;
1531 if (nd
->nd_len
> 0) {
1532 error
= nfsm_chain_trim_data(nmreq
, nd
->nd_len
, &mlen
);
1538 if ((nd
->nd_len
> NFSRV_MAXDATA
) || (nd
->nd_len
< 0) || (mlen
< nd
->nd_len
)) {
1541 nd
->nd_repstat
= error
;
1542 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCDATA(nd
->nd_vers
));
1544 nd
->nd_mrep
= nmrep
.nmc_mhead
;
1545 if (nd
->nd_vers
== NFS_VER3
)
1546 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
1547 preattrerr
, &preattr
, postattrerr
, &postattr
);
1549 nfsm_chain_build_done(error
, &nmrep
);
1554 * Add this entry to the hash and time queues.
1556 lck_mtx_lock(&slp
->ns_wgmutex
);
1558 wp
= slp
->ns_tq
.lh_first
;
1559 while (wp
&& wp
->nd_time
< nd
->nd_time
) {
1561 wp
= wp
->nd_tq
.le_next
;
1564 LIST_INSERT_AFTER(owp
, nd
, nd_tq
);
1566 LIST_INSERT_HEAD(&slp
->ns_tq
, nd
, nd_tq
);
1569 wpp
= NWDELAYHASH(slp
, nd
->nd_fh
.nfh_fid
);
1572 while (wp
&& !nfsrv_fhmatch(&nd
->nd_fh
, &wp
->nd_fh
)) {
1574 wp
= wp
->nd_hash
.le_next
;
1576 while (wp
&& (wp
->nd_off
< nd
->nd_off
) &&
1577 nfsrv_fhmatch(&nd
->nd_fh
, &wp
->nd_fh
)) {
1579 wp
= wp
->nd_hash
.le_next
;
1582 LIST_INSERT_AFTER(owp
, nd
, nd_hash
);
1584 * Search the hash list for overlapping entries and
1587 for(; nd
&& NFSW_CONTIG(owp
, nd
); nd
= wp
) {
1588 wp
= nd
->nd_hash
.le_next
;
1589 if (NFSW_SAMECRED(owp
, nd
))
1590 nfsrv_wg_coalesce(owp
, nd
);
1593 LIST_INSERT_HEAD(wpp
, nd
, nd_hash
);
1597 lck_mtx_lock(&slp
->ns_wgmutex
);
1601 * Now, do VNOP_WRITE()s for any one(s) that need to be done now
1602 * and generate the associated reply mbuf list(s).
1606 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1607 for (nd
= slp
->ns_tq
.lh_first
; nd
; nd
= owp
) {
1608 owp
= nd
->nd_tq
.le_next
;
1609 if (nd
->nd_time
> cur_usec
)
1613 LIST_REMOVE(nd
, nd_tq
);
1614 LIST_REMOVE(nd
, nd_hash
);
1615 nmreq
= &nd
->nd_nmreq
;
1616 preattrerr
= postattrerr
= ENOENT
;
1618 /* save the incoming uid before mapping, */
1619 /* for updating active user stats later */
1620 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
1622 error
= nfsrv_fhtovp(&nd
->nd_fh
, nd
, &vp
, &nx
, &nxo
);
1624 /* update per-export stats */
1625 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
1627 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
1632 if (nd
->nd_vers
== NFS_VER3
) {
1633 nfsm_srv_pre_vattr_init(&preattr
);
1634 preattrerr
= vnode_getattr(vp
, &preattr
, ctx
);
1636 if (vnode_vtype(vp
) != VREG
) {
1637 if (nd
->nd_vers
== NFS_VER3
)
1640 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1645 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, ctx
, nxo
, 1);
1647 if (nd
->nd_stable
== NFS_WRITE_UNSTABLE
)
1648 ioflags
= IO_NODELOCKED
;
1649 else if (nd
->nd_stable
== NFS_WRITE_DATASYNC
)
1650 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1652 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1654 if (!error
&& ((nd
->nd_eoff
- nd
->nd_off
) > 0)) {
1655 for (i
=0, m
=nmreq
->nmc_mhead
; m
; m
= mbuf_next(m
))
1656 if (mbuf_len(m
) > 0)
1659 MALLOC(uio_bufp
, char *, UIO_SIZEOF(i
), M_TEMP
, M_WAITOK
);
1661 auio
= uio_createwithbuffer(i
, nd
->nd_off
, UIO_SYSSPACE
,
1662 UIO_WRITE
, uio_bufp
, UIO_SIZEOF(i
));
1663 if (!uio_bufp
|| !auio
)
1666 for (m
= nmreq
->nmc_mhead
; m
; m
= mbuf_next(m
))
1667 if ((tlen
= mbuf_len(m
)) > 0)
1668 uio_addiov(auio
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(m
)), tlen
);
1669 error
= VNOP_WRITE(vp
, auio
, ioflags
, ctx
);
1670 OSAddAtomic64(1, &nfsstats
.srvvop_writes
);
1672 /* update export stats */
1673 NFSStatAdd64(&nx
->nx_stats
.bytes_written
, nd
->nd_len
);
1674 /* update active user stats */
1675 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, nd
->nd_len
);
1678 if (nfsrv_fsevents_enabled
&& !error
&& need_fsevent(FSE_CONTENT_MODIFIED
, vp
))
1679 nfsrv_modified(vp
, ctx
);
1683 FREE(uio_bufp
, M_TEMP
);
1688 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
1689 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
1694 * Loop around generating replies for all write rpcs that have
1695 * now been completed.
1700 nd
->nd_repstat
= error
;
1701 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCDATA(nd
->nd_vers
));
1702 if (!error
&& (nd
->nd_vers
== NFS_VER3
)) {
1703 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
1704 preattrerr
, &preattr
, postattrerr
, &postattr
);
1707 nd
->nd_repstat
= error
;
1708 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_PREOPATTR(nd
->nd_vers
) +
1709 NFSX_POSTOPORFATTR(nd
->nd_vers
) + 2 * NFSX_UNSIGNED
+
1710 NFSX_WRITEVERF(nd
->nd_vers
));
1711 if (!error
&& (nd
->nd_vers
== NFS_VER3
)) {
1712 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
1713 preattrerr
, &preattr
, postattrerr
, &postattr
);
1714 nfsm_chain_add_32(error
, &nmrep
, nd
->nd_len
);
1715 nfsm_chain_add_32(error
, &nmrep
, nd
->nd_stable
);
1716 /* write verifier */
1717 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_sec
);
1718 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_usec
);
1719 } else if (!error
) {
1720 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
1723 nfsm_chain_build_done(error
, &nmrep
);
1725 nd
->nd_mrep
= nmrep
.nmc_mhead
;
1728 * Done. Put it at the head of the timer queue so that
1729 * the final phase can return the reply.
1733 LIST_INSERT_HEAD(&slp
->ns_tq
, nd
, nd_tq
);
1735 nd
= swp
->nd_coalesce
.lh_first
;
1737 LIST_REMOVE(nd
, nd_tq
);
1741 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1746 * Search for a reply to return.
1748 for (nd
= slp
->ns_tq
.lh_first
; nd
; nd
= nd
->nd_tq
.le_next
)
1750 LIST_REMOVE(nd
, nd_tq
);
1751 *mrepp
= nd
->nd_mrep
;
1755 slp
->ns_wgtime
= slp
->ns_tq
.lh_first
? slp
->ns_tq
.lh_first
->nd_time
: 0;
1756 lck_mtx_unlock(&slp
->ns_wgmutex
);
1759 * If we've just created a write pending gather,
1760 * start the timer to check on it soon to make sure
1761 * the write will be completed.
1763 * Add/Remove the socket in the nfsrv_sockwg queue as needed.
1765 lck_mtx_lock(nfsd_mutex
);
1766 if (slp
->ns_wgtime
) {
1767 if (slp
->ns_wgq
.tqe_next
== SLPNOLIST
) {
1768 TAILQ_INSERT_HEAD(&nfsrv_sockwg
, slp
, ns_wgq
);
1770 if (!nfsrv_wg_timer_on
) {
1771 nfsrv_wg_timer_on
= 1;
1772 nfs_interval_timer_start(nfsrv_wg_timer_call
,
1773 NFSRV_WGATHERDELAY
);
1775 } else if (slp
->ns_wgq
.tqe_next
!= SLPNOLIST
) {
1776 TAILQ_REMOVE(&nfsrv_sockwg
, slp
, ns_wgq
);
1777 slp
->ns_wgq
.tqe_next
= SLPNOLIST
;
1779 lck_mtx_unlock(nfsd_mutex
);
1785 * Coalesce the write request nd into owp. To do this we must:
1786 * - remove nd from the queues
1787 * - merge nd->nd_nmreq into owp->nd_nmreq
1788 * - update the nd_eoff and nd_stable for owp
1789 * - put nd on owp's nd_coalesce list
1792 nfsrv_wg_coalesce(struct nfsrv_descript
*owp
, struct nfsrv_descript
*nd
)
1796 struct nfsrv_descript
*p
;
1798 LIST_REMOVE(nd
, nd_hash
);
1799 LIST_REMOVE(nd
, nd_tq
);
1800 if (owp
->nd_eoff
< nd
->nd_eoff
) {
1801 overlap
= owp
->nd_eoff
- nd
->nd_off
;
1805 mbuf_adj(nd
->nd_nmreq
.nmc_mhead
, overlap
);
1806 mp
= owp
->nd_nmreq
.nmc_mhead
;
1807 while ((mpnext
= mbuf_next(mp
)))
1809 error
= mbuf_setnext(mp
, nd
->nd_nmreq
.nmc_mhead
);
1812 owp
->nd_eoff
= nd
->nd_eoff
;
1814 mbuf_freem(nd
->nd_nmreq
.nmc_mhead
);
1816 nd
->nd_nmreq
.nmc_mhead
= NULL
;
1817 nd
->nd_nmreq
.nmc_mcur
= NULL
;
1818 if (nd
->nd_stable
== NFS_WRITE_FILESYNC
)
1819 owp
->nd_stable
= NFS_WRITE_FILESYNC
;
1820 else if ((nd
->nd_stable
== NFS_WRITE_DATASYNC
) &&
1821 (owp
->nd_stable
== NFS_WRITE_UNSTABLE
))
1822 owp
->nd_stable
= NFS_WRITE_DATASYNC
;
1823 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nd
, nd_tq
);
1826 * If nd had anything else coalesced into it, transfer them
1827 * to owp, otherwise their replies will never get sent.
1829 while ((p
= nd
->nd_coalesce
.lh_first
)) {
1830 LIST_REMOVE(p
, nd_tq
);
1831 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1837 * Scan the write gathering queues for writes that need to be
1841 nfsrv_wg_timer(__unused
void *param0
, __unused
void *param1
)
1844 uint64_t cur_usec
, next_usec
;
1846 struct nfsrv_sock
*slp
;
1847 int writes_pending
= 0;
1850 cur_usec
= (uint64_t)now
.tv_sec
* 1000000 + (uint64_t)now
.tv_usec
;
1851 next_usec
= cur_usec
+ (NFSRV_WGATHERDELAY
* 1000);
1853 lck_mtx_lock(nfsd_mutex
);
1854 TAILQ_FOREACH(slp
, &nfsrv_sockwg
, ns_wgq
) {
1855 if (slp
->ns_wgtime
) {
1857 if (slp
->ns_wgtime
<= cur_usec
) {
1858 lck_rw_lock_exclusive(&slp
->ns_rwlock
);
1859 slp
->ns_flag
|= SLP_DOWRITES
;
1860 lck_rw_done(&slp
->ns_rwlock
);
1861 nfsrv_wakenfsd(slp
);
1864 if (slp
->ns_wgtime
< next_usec
)
1865 next_usec
= slp
->ns_wgtime
;
1869 if (writes_pending
== 0) {
1870 nfsrv_wg_timer_on
= 0;
1871 lck_mtx_unlock(nfsd_mutex
);
1874 lck_mtx_unlock(nfsd_mutex
);
1877 * Return the number of msec to wait again
1879 interval
= (next_usec
- cur_usec
) / 1000;
1882 nfs_interval_timer_start(nfsrv_wg_timer_call
, interval
);
1886 * Sort the group list in increasing numerical order.
1887 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1888 * that used to be here.)
1891 nfsrv_group_sort(gid_t
*list
, int num
)
1896 /* Insertion sort. */
1897 for (i
= 1; i
< num
; i
++) {
1899 /* find correct slot for value v, moving others up */
1900 for (j
= i
; --j
>= 0 && v
< list
[j
];)
1901 list
[j
+ 1] = list
[j
];
1907 * nfs create service
1908 * now does a truncate to 0 length via. setattr if it already exists
1912 struct nfsrv_descript
*nd
,
1913 struct nfsrv_sock
*slp
,
1917 struct vnode_attr dpreattr
, dpostattr
, postattr
;
1918 struct vnode_attr va
, *vap
= &va
;
1919 struct nameidata ni
;
1920 int error
, rdev
, dpreattrerr
, dpostattrerr
, postattrerr
;
1921 int how
, exclusive_flag
;
1922 uint32_t len
= 0, cnflags
;
1923 vnode_t vp
, dvp
, dirp
;
1924 struct nfs_filehandle nfh
;
1925 struct nfs_export
*nx
= NULL
;
1926 struct nfs_export_options
*nxo
;
1928 u_char cverf
[NFSX_V3CREATEVERF
];
1930 struct nfsm_chain
*nmreq
, nmrep
;
1933 dpreattrerr
= dpostattrerr
= postattrerr
= ENOENT
;
1934 nmreq
= &nd
->nd_nmreq
;
1935 nfsm_chain_null(&nmrep
);
1936 vp
= dvp
= dirp
= NULL
;
1938 ni
.ni_cnd
.cn_nameiop
= 0;
1941 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
1943 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
1944 nfsm_chain_get_32(error
, nmreq
, len
);
1945 nfsm_name_len_check(error
, nd
, len
);
1948 ni
.ni_cnd
.cn_nameiop
= CREATE
;
1952 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1953 ni
.ni_cnd
.cn_ndp
= &ni
;
1955 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
1957 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
1959 /* update export stats */
1960 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
1962 /* update active user stats */
1963 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
1967 if (nd
->nd_vers
== NFS_VER3
) {
1968 nfsm_srv_pre_vattr_init(&dpreattr
);
1969 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
1977 ni
.ni_cnd
.cn_nameiop
= 0;
1985 if (nd
->nd_vers
== NFS_VER3
) {
1986 nfsm_chain_get_32(error
, nmreq
, how
);
1989 case NFS_CREATE_GUARDED
:
1994 case NFS_CREATE_UNCHECKED
:
1995 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
1997 case NFS_CREATE_EXCLUSIVE
:
1998 nfsm_chain_get_opaque(error
, nmreq
, NFSX_V3CREATEVERF
, cverf
);
2001 VATTR_SET(vap
, va_mode
, 0);
2004 VATTR_SET(vap
, va_type
, VREG
);
2008 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
2010 v_type
= vap
->va_type
;
2013 VATTR_SET(vap
, va_type
, v_type
);
2019 rdev
= vap
->va_data_size
;
2020 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
2029 * If it doesn't exist, create it
2030 * otherwise just truncate to 0 length
2031 * should I set the mode too ??
2034 kauth_acl_t xacl
= NULL
;
2036 /* authorize before creating */
2037 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
, nxo
, 0);
2039 /* construct ACL and handle inheritance */
2041 error
= kauth_acl_inherit(dvp
,
2047 if (!error
&& xacl
!= NULL
)
2048 VATTR_SET(vap
, va_acl
, xacl
);
2050 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
2051 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
2053 * Server policy is to alway use the mapped rpc credential for
2054 * file system object creation. This has the nice side effect of
2055 * enforcing BSD creation semantics
2057 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
2058 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
2060 /* validate new-file security information */
2062 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
2065 error
= vn_authorize_create(dvp
, &ni
.ni_cnd
, vap
, ctx
, NULL
);
2070 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
2073 error
= VNOP_CREATE(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
);
2075 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
2077 * If some of the requested attributes weren't handled by the VNOP,
2078 * use our fallback code.
2080 error
= vnode_setattr_fallback(vp
, vap
, ctx
);
2083 kauth_acl_free(xacl
);
2086 if (exclusive_flag
) {
2089 bcopy(cverf
, (caddr_t
)&vap
->va_access_time
,
2091 VATTR_SET_ACTIVE(vap
, va_access_time
);
2092 // skip authorization, as this is an
2093 // NFS internal implementation detail.
2094 error
= vnode_setattr(vp
, vap
, ctx
);
2098 if (nfsrv_fsevents_enabled
&& need_fsevent(FSE_CREATE_FILE
, vp
)) {
2099 add_fsevent(FSE_CREATE_FILE
, ctx
,
2106 } else if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
||
2107 vap
->va_type
== VFIFO
) {
2108 if (vap
->va_type
== VCHR
&& rdev
== (int)0xffffffff)
2109 VATTR_SET(vap
, va_type
, VFIFO
);
2110 if (vap
->va_type
!= VFIFO
) {
2111 error
= suser(nd
->nd_cr
, NULL
);
2114 VATTR_SET(vap
, va_rdev
, (dev_t
)rdev
);
2116 error
= VNOP_MKNOD(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
);
2119 kauth_acl_free(xacl
);
2128 ni
.ni_cnd
.cn_nameiop
= LOOKUP
;
2130 ni
.ni_op
= OP_LOOKUP
;
2132 ni
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
2133 ni
.ni_cnd
.cn_context
= ctx
;
2134 ni
.ni_startdir
= dvp
;
2136 ni
.ni_rootdir
= rootvnode
;
2137 cnflags
= ni
.ni_cnd
.cn_flags
; /* store in case we have to restore */
2138 while ((error
= lookup(&ni
)) == ERECYCLE
) {
2139 ni
.ni_cnd
.cn_flags
= cnflags
;
2140 ni
.ni_cnd
.cn_nameptr
= ni
.ni_cnd
.cn_pnbuf
;
2141 ni
.ni_usedvp
= ni
.ni_dvp
= ni
.ni_startdir
= dvp
;
2144 if (ni
.ni_cnd
.cn_flags
& ISSYMLINK
)
2153 * nameidone has to happen before we vnode_put(dvp)
2154 * since it may need to release the fs_nodelock on the dvp
2157 ni
.ni_cnd
.cn_nameiop
= 0;
2162 * nameidone has to happen before we vnode_put(dvp)
2163 * since it may need to release the fs_nodelock on the dvp
2166 ni
.ni_cnd
.cn_nameiop
= 0;
2171 if (!error
&& VATTR_IS_ACTIVE(vap
, va_data_size
)) {
2172 /* NOTE: File has not been open for NFS case, so NOCRED for filecred */
2173 error
= mac_vnode_check_truncate(ctx
, NOCRED
, vp
);
2178 if (!error
&& VATTR_IS_ACTIVE(vap
, va_data_size
)) {
2179 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
,
2182 tempsize
= vap
->va_data_size
;
2184 VATTR_SET(vap
, va_data_size
, tempsize
);
2185 error
= vnode_setattr(vp
, vap
, ctx
);
2190 error
= nfsrv_vptofh(nx
, nd
->nd_vers
, NULL
, vp
, ctx
, &nfh
);
2192 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
2193 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
2194 if (nd
->nd_vers
== NFS_VER2
)
2195 error
= postattrerr
;
2201 if (nd
->nd_vers
== NFS_VER3
) {
2202 if (exclusive_flag
&& !error
&&
2203 bcmp(cverf
, &postattr
.va_access_time
, NFSX_V3CREATEVERF
))
2205 nfsm_srv_vattr_init(&dpostattr
, NFS_VER3
);
2206 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
2212 /* assemble reply */
2213 nd
->nd_repstat
= error
;
2214 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(nd
->nd_vers
, &nfh
) +
2215 NFSX_FATTR(nd
->nd_vers
) + NFSX_WCCDATA(nd
->nd_vers
));
2217 *mrepp
= nmrep
.nmc_mhead
;
2218 nfsmout_on_status(nd
, error
);
2219 if (nd
->nd_vers
== NFS_VER3
) {
2220 if (!nd
->nd_repstat
) {
2221 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2222 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, postattrerr
, &postattr
);
2224 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
2225 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
2227 nfsm_chain_add_fh(error
, &nmrep
, NFS_VER2
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2229 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
2232 nfsm_chain_build_done(error
, &nmrep
);
2233 if (ni
.ni_cnd
.cn_nameiop
) {
2235 * nameidone has to happen before we vnode_put(dvp)
2236 * since it may need to release the fs_nodelock on the dvp
2247 nfsm_chain_cleanup(&nmrep
);
2254 * nfs v3 mknod service
2258 struct nfsrv_descript
*nd
,
2259 struct nfsrv_sock
*slp
,
2263 struct vnode_attr dpreattr
, dpostattr
, postattr
;
2264 struct vnode_attr va
, *vap
= &va
;
2265 struct nameidata ni
;
2266 int error
, dpreattrerr
, dpostattrerr
, postattrerr
;
2267 uint32_t len
= 0, cnflags
;
2268 u_int32_t major
= 0, minor
= 0;
2271 vnode_t vp
, dvp
, dirp
;
2272 struct nfs_filehandle nfh
;
2273 struct nfs_export
*nx
= NULL
;
2274 struct nfs_export_options
*nxo
;
2276 kauth_acl_t xacl
= NULL
;
2277 struct nfsm_chain
*nmreq
, nmrep
;
2280 dpreattrerr
= dpostattrerr
= postattrerr
= ENOENT
;
2281 nmreq
= &nd
->nd_nmreq
;
2282 nfsm_chain_null(&nmrep
);
2283 vp
= dvp
= dirp
= NULL
;
2284 ni
.ni_cnd
.cn_nameiop
= 0;
2286 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
2288 nfsm_chain_get_fh_ptr(error
, nmreq
, NFS_VER3
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2289 nfsm_chain_get_32(error
, nmreq
, len
);
2290 nfsm_name_len_check(error
, nd
, len
);
2293 ni
.ni_cnd
.cn_nameiop
= CREATE
;
2297 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2298 ni
.ni_cnd
.cn_ndp
= &ni
;
2299 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
2301 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
2303 /* update export stats */
2304 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
2306 /* update active user stats */
2307 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
2311 nfsm_srv_pre_vattr_init(&dpreattr
);
2312 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
2315 ni
.ni_cnd
.cn_nameiop
= 0;
2322 nfsm_chain_get_32(error
, nmreq
, nvtype
);
2324 vtyp
= nfstov_type(nvtype
, NFS_VER3
);
2325 if (!error
&& (vtyp
!= VCHR
) && (vtyp
!= VBLK
) && (vtyp
!= VSOCK
) && (vtyp
!= VFIFO
)) {
2326 error
= NFSERR_BADTYPE
;
2331 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
2332 if ((vtyp
== VCHR
) || (vtyp
== VBLK
)) {
2333 nfsm_chain_get_32(error
, nmreq
, major
);
2334 nfsm_chain_get_32(error
, nmreq
, minor
);
2336 VATTR_SET(vap
, va_rdev
, makedev(major
, minor
));
2341 * If it doesn't exist, create it.
2347 VATTR_SET(vap
, va_type
, vtyp
);
2349 /* authorize before creating */
2350 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
, nxo
, 0);
2352 /* construct ACL and handle inheritance */
2354 error
= kauth_acl_inherit(dvp
,
2360 if (!error
&& xacl
!= NULL
)
2361 VATTR_SET(vap
, va_acl
, xacl
);
2363 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
2364 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
2366 * Server policy is to alway use the mapped rpc credential for
2367 * file system object creation. This has the nice side effect of
2368 * enforcing BSD creation semantics
2370 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
2371 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
2373 /* validate new-file security information */
2375 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
2377 error
= vn_authorize_create(dvp
, &ni
.ni_cnd
, vap
, ctx
, NULL
);
2384 if (vtyp
== VSOCK
) {
2385 error
= VNOP_CREATE(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
);
2387 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
2389 * If some of the requested attributes weren't handled by the VNOP,
2390 * use our fallback code.
2392 error
= vnode_setattr_fallback(vp
, vap
, ctx
);
2394 if (vtyp
!= VFIFO
&& (error
= suser(nd
->nd_cr
, (u_short
*)0)))
2396 if ((error
= VNOP_MKNOD(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
)))
2403 ni
.ni_cnd
.cn_nameiop
= LOOKUP
;
2405 ni
.ni_op
= OP_LOOKUP
;
2407 ni
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
2408 ni
.ni_cnd
.cn_context
= vfs_context_current();
2409 ni
.ni_startdir
= dvp
;
2411 ni
.ni_rootdir
= rootvnode
;
2412 cnflags
= ni
.ni_cnd
.cn_flags
; /* store in case we have to restore */
2413 while ((error
= lookup(&ni
)) == ERECYCLE
) {
2414 ni
.ni_cnd
.cn_flags
= cnflags
;
2415 ni
.ni_cnd
.cn_nameptr
= ni
.ni_cnd
.cn_pnbuf
;
2416 ni
.ni_usedvp
= ni
.ni_dvp
= ni
.ni_startdir
= dvp
;
2420 if (ni
.ni_cnd
.cn_flags
& ISSYMLINK
)
2426 kauth_acl_free(xacl
);
2429 * nameidone has to happen before we vnode_put(dvp)
2430 * since it may need to release the fs_nodelock on the dvp
2433 ni
.ni_cnd
.cn_nameiop
= 0;
2439 error
= nfsrv_vptofh(nx
, NFS_VER3
, NULL
, vp
, ctx
, &nfh
);
2441 nfsm_srv_vattr_init(&postattr
, NFS_VER3
);
2442 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
2450 nfsm_srv_vattr_init(&dpostattr
, NFS_VER3
);
2451 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
2456 /* assemble reply */
2457 nd
->nd_repstat
= error
;
2458 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(NFS_VER3
, &nfh
) +
2459 NFSX_POSTOPATTR(NFS_VER3
) + NFSX_WCCDATA(NFS_VER3
));
2461 *mrepp
= nmrep
.nmc_mhead
;
2462 nfsmout_on_status(nd
, error
);
2463 if (!nd
->nd_repstat
) {
2464 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2465 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, postattrerr
, &postattr
);
2467 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
2468 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
2470 nfsm_chain_build_done(error
, &nmrep
);
2471 if (ni
.ni_cnd
.cn_nameiop
) {
2473 * nameidone has to happen before we vnode_put(dvp)
2474 * since it may need to release the fs_nodelock on the dvp
2489 nfsm_chain_cleanup(&nmrep
);
2496 * nfs remove service
2500 struct nfsrv_descript
*nd
,
2501 struct nfsrv_sock
*slp
,
2505 struct nameidata ni
;
2506 int error
, dpreattrerr
, dpostattrerr
;
2509 vnode_t vp
, dvp
, dirp
= NULL
;
2510 struct vnode_attr dpreattr
, dpostattr
;
2511 struct nfs_filehandle nfh
;
2512 struct nfs_export
*nx
= NULL
;
2513 struct nfs_export_options
*nxo
;
2514 struct nfsm_chain
*nmreq
, nmrep
;
2517 dpreattrerr
= dpostattrerr
= ENOENT
;
2518 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
2519 dvp
= vp
= dirp
= NULL
;
2520 nmreq
= &nd
->nd_nmreq
;
2521 nfsm_chain_null(&nmrep
);
2523 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2524 nfsm_chain_get_32(error
, nmreq
, len
);
2525 nfsm_name_len_check(error
, nd
, len
);
2528 ni
.ni_cnd
.cn_nameiop
= DELETE
;
2530 ni
.ni_op
= OP_UNLINK
;
2532 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2533 ni
.ni_cnd
.cn_ndp
= &ni
;
2534 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
2536 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
2538 /* update export stats */
2539 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
2541 /* update active user stats */
2542 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
2546 if (nd
->nd_vers
== NFS_VER3
) {
2547 nfsm_srv_pre_vattr_init(&dpreattr
);
2548 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
2559 if (vnode_vtype(vp
) == VDIR
)
2560 error
= EPERM
; /* POSIX */
2561 else if (vnode_isvroot(vp
))
2563 * The root of a mounted filesystem cannot be deleted.
2567 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, ctx
, nxo
, 0);
2570 error
= vn_authorize_unlink(dvp
, vp
, &ni
.ni_cnd
, ctx
, NULL
);
2581 if (nfsrv_fsevents_enabled
&& need_fsevent(FSE_DELETE
, dvp
)) {
2583 if ((path
= get_pathbuff()) && !vn_getpath(vp
, path
, &plen
)) {
2584 get_fse_info(vp
, &finfo
, ctx
);
2586 release_pathbuff(path
);
2591 error
= VNOP_REMOVE(dvp
, vp
, &ni
.ni_cnd
, 0, ctx
);
2596 add_fsevent(FSE_DELETE
, ctx
,
2597 FSE_ARG_STRING
, plen
, path
,
2598 FSE_ARG_FINFO
, &finfo
,
2600 release_pathbuff(path
);
2606 * nameidone has to happen before we vnode_put(dvp)
2607 * since it may need to release the fs_nodelock on the dvp
2617 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
2618 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
2622 /* assemble reply */
2623 nd
->nd_repstat
= error
;
2624 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCDATA(nd
->nd_vers
));
2626 *mrepp
= nmrep
.nmc_mhead
;
2627 nfsmout_on_status(nd
, error
);
2628 if (nd
->nd_vers
== NFS_VER3
)
2629 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
2630 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
2632 nfsm_chain_build_done(error
, &nmrep
);
2634 nfsm_chain_cleanup(&nmrep
);
2641 * nfs rename service
2645 struct nfsrv_descript
*nd
,
2646 struct nfsrv_sock
*slp
,
2650 kauth_cred_t saved_cred
= NULL
;
2653 uint32_t fromlen
, tolen
;
2654 int fdpreattrerr
, fdpostattrerr
;
2655 int tdpreattrerr
, tdpostattrerr
;
2656 char *frompath
= NULL
, *topath
= NULL
;
2657 struct nameidata fromni
, toni
;
2658 vnode_t fvp
, tvp
, tdvp
, fdvp
, fdirp
, tdirp
;
2659 struct vnode_attr fdpreattr
, fdpostattr
;
2660 struct vnode_attr tdpreattr
, tdpostattr
;
2661 struct nfs_filehandle fnfh
, tnfh
;
2662 struct nfs_export
*fnx
, *tnx
;
2663 struct nfs_export_options
*fnxo
, *tnxo
;
2664 enum vtype fvtype
, tvtype
;
2665 int holding_mntlock
;
2667 struct nfsm_chain
*nmreq
, nmrep
;
2668 char *from_name
, *to_name
;
2670 int from_len
=0, to_len
=0;
2671 fse_info from_finfo
, to_finfo
;
2673 u_char didstats
= 0;
2677 fdpreattrerr
= fdpostattrerr
= ENOENT
;
2678 tdpreattrerr
= tdpostattrerr
= ENOENT
;
2679 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
2680 fromlen
= tolen
= 0;
2681 frompath
= topath
= NULL
;
2682 fdirp
= tdirp
= NULL
;
2683 nmreq
= &nd
->nd_nmreq
;
2684 nfsm_chain_null(&nmrep
);
2687 * these need to be set before calling any code
2688 * that they may take us out through the error path.
2690 holding_mntlock
= 0;
2695 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, fnfh
.nfh_fhp
, fnfh
.nfh_len
);
2696 nfsm_chain_get_32(error
, nmreq
, fromlen
);
2697 nfsm_name_len_check(error
, nd
, fromlen
);
2699 error
= nfsm_chain_get_path_namei(nmreq
, fromlen
, &fromni
);
2701 frompath
= fromni
.ni_cnd
.cn_pnbuf
;
2703 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, tnfh
.nfh_fhp
, tnfh
.nfh_len
);
2704 nfsm_chain_get_32(error
, nmreq
, tolen
);
2705 nfsm_name_len_check(error
, nd
, tolen
);
2707 error
= nfsm_chain_get_path_namei(nmreq
, tolen
, &toni
);
2709 topath
= toni
.ni_cnd
.cn_pnbuf
;
2712 * Remember our original uid so that we can reset cr_uid before
2713 * the second nfsrv_namei() call, in case it is remapped.
2715 saved_cred
= nd
->nd_cr
;
2716 kauth_cred_ref(saved_cred
);
2718 fromni
.ni_cnd
.cn_nameiop
= DELETE
;
2720 fromni
.ni_op
= OP_UNLINK
;
2722 fromni
.ni_cnd
.cn_flags
= WANTPARENT
;
2724 fromni
.ni_cnd
.cn_pnbuf
= frompath
;
2726 fromni
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2727 fromni
.ni_cnd
.cn_flags
|= HASBUF
;
2728 fromni
.ni_cnd
.cn_ndp
= &fromni
;
2730 error
= nfsrv_namei(nd
, ctx
, &fromni
, &fnfh
, &fdirp
, &fnx
, &fnxo
);
2733 fdvp
= fromni
.ni_dvp
;
2737 if (nd
->nd_vers
== NFS_VER3
) {
2738 nfsm_srv_pre_vattr_init(&fdpreattr
);
2739 fdpreattrerr
= vnode_getattr(fdirp
, &fdpreattr
, ctx
);
2745 fvtype
= vnode_vtype(fvp
);
2747 /* reset credential if it was remapped */
2748 if (nd
->nd_cr
!= saved_cred
) {
2749 kauth_cred_ref(saved_cred
);
2750 kauth_cred_unref(&nd
->nd_cr
);
2751 ctx
->vc_ucred
= nd
->nd_cr
= saved_cred
;
2754 toni
.ni_cnd
.cn_nameiop
= RENAME
;
2756 toni
.ni_op
= OP_RENAME
;
2758 toni
.ni_cnd
.cn_flags
= WANTPARENT
;
2760 toni
.ni_cnd
.cn_pnbuf
= topath
;
2762 toni
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2763 toni
.ni_cnd
.cn_flags
|= HASBUF
;
2764 toni
.ni_cnd
.cn_ndp
= &toni
;
2767 toni
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2770 error
= nfsrv_namei(nd
, ctx
, &toni
, &tnfh
, &tdirp
, &tnx
, &tnxo
);
2773 * Translate error code for rename("dir1", "dir2/.").
2775 if (error
== EISDIR
&& fvtype
== VDIR
) {
2776 if (nd
->nd_vers
== NFS_VER3
)
2787 /* update export stats once only */
2789 /* update export stats */
2790 NFSStatAdd64(&tnx
->nx_stats
.ops
, 1);
2792 /* update active user stats */
2793 nfsrv_update_user_stat(tnx
, nd
, saved_uid
, 1, 0, 0);
2799 if (nd
->nd_vers
== NFS_VER3
) {
2800 nfsm_srv_pre_vattr_init(&tdpreattr
);
2801 tdpreattrerr
= vnode_getattr(tdirp
, &tdpreattr
, ctx
);
2809 tvtype
= vnode_vtype(tvp
);
2811 if (fvtype
== VDIR
&& tvtype
!= VDIR
) {
2812 if (nd
->nd_vers
== NFS_VER3
)
2817 } else if (fvtype
!= VDIR
&& tvtype
== VDIR
) {
2818 if (nd
->nd_vers
== NFS_VER3
)
2824 if (tvtype
== VDIR
&& vnode_mountedhere(tvp
)) {
2825 if (nd
->nd_vers
== NFS_VER3
)
2833 if (nd
->nd_vers
== NFS_VER3
)
2843 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
2844 * the node is moving between directories and we need rights to remove from the
2845 * old and add to the new.
2847 * If tvp already exists and is not a directory, we need to be allowed to delete it.
2849 * Note that we do not inherit when renaming. XXX this needs to be revisited to
2850 * implement the deferred-inherit bit.
2856 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
2859 } else if (tdvp
!= fdvp
) {
2863 /* moving out of fdvp, must have delete rights */
2864 if ((error
= nfsrv_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, ctx
, fnxo
, 0)) != 0)
2866 /* moving into tdvp or tvp, must have rights to add */
2867 if ((error
= nfsrv_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
2869 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2870 ctx
, tnxo
, 0)) != 0)
2873 /* node staying in same directory, must be allowed to add new name */
2874 if ((error
= nfsrv_authorize(fdvp
, NULL
,
2875 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2876 ctx
, fnxo
, 0)) != 0)
2879 /* overwriting tvp */
2880 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
2881 ((error
= nfsrv_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, ctx
, tnxo
, 0)) != 0))
2885 ((error
= vn_authorize_rename(fdvp
, fvp
, &fromni
.ni_cnd
, tdvp
, tvp
, &toni
.ni_cnd
, ctx
, NULL
)) != 0)) {
2890 /* XXX more checks? */
2893 /* authorization denied */
2898 if ((vnode_mount(fvp
) != vnode_mount(tdvp
)) ||
2899 (tvp
&& (vnode_mount(fvp
) != vnode_mount(tvp
)))) {
2900 if (nd
->nd_vers
== NFS_VER3
)
2907 * The following edge case is caught here:
2908 * (to cannot be a descendent of from)
2921 if (tdvp
->v_parent
== fvp
) {
2922 if (nd
->nd_vers
== NFS_VER3
)
2928 if (fvtype
== VDIR
&& vnode_mountedhere(fvp
)) {
2929 if (nd
->nd_vers
== NFS_VER3
)
2936 * If source is the same as the destination (that is the
2937 * same vnode) then there is nothing to do...
2938 * EXCEPT if the underlying file system supports case
2939 * insensitivity and is case preserving. In this case
2940 * the file system needs to handle the special case of
2941 * getting the same vnode as target (fvp) and source (tvp).
2943 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2944 * and _PC_CASE_PRESERVING can have this exception, and they need to
2945 * handle the special case of getting the same vnode as target and
2946 * source. NOTE: Then the target is unlocked going into vnop_rename,
2947 * so not to cause locking problems. There is a single reference on tvp.
2949 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2950 * that correct behaviour then is just to remove the source (link)
2952 if ((fvp
== tvp
) && (fdvp
== tdvp
)) {
2953 if (fromni
.ni_cnd
.cn_namelen
== toni
.ni_cnd
.cn_namelen
&&
2954 !bcmp(fromni
.ni_cnd
.cn_nameptr
, toni
.ni_cnd
.cn_nameptr
,
2955 fromni
.ni_cnd
.cn_namelen
)) {
2960 if (holding_mntlock
&& vnode_mount(fvp
) != locked_mp
) {
2962 * we're holding a reference and lock
2963 * on locked_mp, but it no longer matches
2964 * what we want to do... so drop our hold
2966 mount_unlock_renames(locked_mp
);
2967 mount_drop(locked_mp
, 0);
2968 holding_mntlock
= 0;
2970 if (tdvp
!= fdvp
&& fvtype
== VDIR
) {
2972 * serialize renames that re-shape
2973 * the tree... if holding_mntlock is
2974 * set, then we're ready to go...
2976 * first need to drop the iocounts
2977 * we picked up, second take the
2978 * lock to serialize the access,
2979 * then finally start the lookup
2980 * process over with the lock held
2982 if (!holding_mntlock
) {
2984 * need to grab a reference on
2985 * the mount point before we
2986 * drop all the iocounts... once
2987 * the iocounts are gone, the mount
2990 locked_mp
= vnode_mount(fvp
);
2991 mount_ref(locked_mp
, 0);
2993 /* make a copy of to path to pass to nfsrv_namei() again */
2994 MALLOC_ZONE(topath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2996 bcopy(toni
.ni_cnd
.cn_pnbuf
, topath
, tolen
+ 1);
2999 * nameidone has to happen before we vnode_put(tdvp)
3000 * since it may need to release the fs_nodelock on the tdvp
3008 /* make a copy of from path to pass to nfsrv_namei() again */
3009 MALLOC_ZONE(frompath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
3011 bcopy(fromni
.ni_cnd
.cn_pnbuf
, frompath
, fromlen
+ 1);
3014 * nameidone has to happen before we vnode_put(fdvp)
3015 * since it may need to release the fs_nodelock on the fdvp
3030 mount_lock_renames(locked_mp
);
3031 holding_mntlock
= 1;
3036 fdpreattrerr
= tdpreattrerr
= ENOENT
;
3038 if (!topath
|| !frompath
) {
3039 /* we couldn't allocate a path, so bail */
3044 /* reset credential if it was remapped */
3045 if (nd
->nd_cr
!= saved_cred
) {
3046 kauth_cred_ref(saved_cred
);
3047 kauth_cred_unref(&nd
->nd_cr
);
3048 ctx
->vc_ucred
= nd
->nd_cr
= saved_cred
;
3055 * when we dropped the iocounts to take
3056 * the lock, we allowed the identity of
3057 * the various vnodes to change... if they did,
3058 * we may no longer be dealing with a rename
3059 * that reshapes the tree... once we're holding
3060 * the iocounts, the vnodes can't change type
3061 * so we're free to drop the lock at this point
3064 if (holding_mntlock
) {
3065 mount_unlock_renames(locked_mp
);
3066 mount_drop(locked_mp
, 0);
3067 holding_mntlock
= 0;
3071 // save these off so we can later verify that fvp is the same
3073 oname
= fvp
->v_name
;
3074 oparent
= fvp
->v_parent
;
3077 * If generating an fsevent, then
3078 * stash any pre-rename info we may need.
3081 if (nfsrv_fsevents_enabled
&& need_fsevent(FSE_RENAME
, fvp
)) {
3082 int from_truncated
= 0, to_truncated
= 0;
3084 get_fse_info(fvp
, &from_finfo
, ctx
);
3086 get_fse_info(tvp
, &to_finfo
, ctx
);
3088 from_name
= get_pathbuff();
3090 from_len
= safe_getpath(fdvp
, fromni
.ni_cnd
.cn_nameptr
, from_name
, MAXPATHLEN
, &from_truncated
);
3093 to_name
= from_name
? get_pathbuff() : NULL
;
3095 to_len
= safe_getpath(tdvp
, toni
.ni_cnd
.cn_nameptr
, to_name
, MAXPATHLEN
, &to_truncated
);
3098 if (from_truncated
|| to_truncated
) {
3099 from_finfo
.mode
|= FSE_TRUNCATED_PATH
;
3106 #else /* CONFIG_FSE */
3109 #endif /* CONFIG_FSE */
3111 error
= VNOP_RENAME(fromni
.ni_dvp
, fromni
.ni_vp
, &fromni
.ni_cnd
,
3112 toni
.ni_dvp
, toni
.ni_vp
, &toni
.ni_cnd
, ctx
);
3114 * fix up name & parent pointers. note that we first
3115 * check that fvp has the same name/parent pointers it
3116 * had before the rename call... this is a 'weak' check
3119 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
3121 update_flags
= VNODE_UPDATE_NAME
;
3123 update_flags
|= VNODE_UPDATE_PARENT
;
3124 vnode_update_identity(fvp
, tdvp
, toni
.ni_cnd
.cn_nameptr
,
3125 toni
.ni_cnd
.cn_namelen
, toni
.ni_cnd
.cn_hash
, update_flags
);
3129 * If the rename is OK and we've got the paths
3130 * then add an fsevent.
3133 if (nfsrv_fsevents_enabled
&& !error
&& from_name
&& to_name
) {
3135 add_fsevent(FSE_RENAME
, ctx
,
3136 FSE_ARG_STRING
, from_len
, from_name
,
3137 FSE_ARG_FINFO
, &from_finfo
,
3138 FSE_ARG_STRING
, to_len
, to_name
,
3139 FSE_ARG_FINFO
, &to_finfo
,
3142 add_fsevent(FSE_RENAME
, ctx
,
3143 FSE_ARG_STRING
, from_len
, from_name
,
3144 FSE_ARG_FINFO
, &from_finfo
,
3145 FSE_ARG_STRING
, to_len
, to_name
,
3150 release_pathbuff(from_name
);
3152 release_pathbuff(to_name
);
3153 #endif /* CONFIG_FSE */
3154 from_name
= to_name
= NULL
;
3157 if (holding_mntlock
) {
3158 mount_unlock_renames(locked_mp
);
3159 mount_drop(locked_mp
, 0);
3160 holding_mntlock
= 0;
3164 * nameidone has to happen before we vnode_put(tdvp)
3165 * since it may need to release the fs_nodelock on the tdvp
3176 * nameidone has to happen before we vnode_put(fdvp)
3177 * since it may need to release the fs_nodelock on the fdvp
3188 nfsm_srv_vattr_init(&fdpostattr
, nd
->nd_vers
);
3189 fdpostattrerr
= vnode_getattr(fdirp
, &fdpostattr
, ctx
);
3194 nfsm_srv_vattr_init(&tdpostattr
, nd
->nd_vers
);
3195 tdpostattrerr
= vnode_getattr(tdirp
, &tdpostattr
, ctx
);
3201 /* assemble reply */
3202 nd
->nd_repstat
= error
;
3203 error
= nfsrv_rephead(nd
, slp
, &nmrep
, 2 * NFSX_WCCDATA(nd
->nd_vers
));
3205 *mrepp
= nmrep
.nmc_mhead
;
3206 nfsmout_on_status(nd
, error
);
3207 if (nd
->nd_vers
== NFS_VER3
) {
3208 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3209 fdpreattrerr
, &fdpreattr
, fdpostattrerr
, &fdpostattr
);
3210 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3211 tdpreattrerr
, &tdpreattr
, tdpostattrerr
, &tdpostattr
);
3214 nfsm_chain_build_done(error
, &nmrep
);
3215 if (holding_mntlock
) {
3216 mount_unlock_renames(locked_mp
);
3217 mount_drop(locked_mp
, 0);
3221 * nameidone has to happen before we vnode_put(tdvp)
3222 * since it may need to release the fs_nodelock on the tdvp
3232 * nameidone has to happen before we vnode_put(fdvp)
3233 * since it may need to release the fs_nodelock on the fdvp
3246 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
3248 FREE_ZONE(topath
, MAXPATHLEN
, M_NAMEI
);
3250 kauth_cred_unref(&saved_cred
);
3252 nfsm_chain_cleanup(&nmrep
);
3263 struct nfsrv_descript
*nd
,
3264 struct nfsrv_sock
*slp
,
3268 struct nameidata ni
;
3269 int error
, dpreattrerr
, dpostattrerr
, attrerr
;
3271 vnode_t vp
, xp
, dvp
, dirp
;
3272 struct vnode_attr dpreattr
, dpostattr
, attr
;
3273 struct nfs_filehandle nfh
, dnfh
;
3274 struct nfs_export
*nx
;
3275 struct nfs_export_options
*nxo
;
3276 struct nfsm_chain
*nmreq
, nmrep
;
3279 dpreattrerr
= dpostattrerr
= attrerr
= ENOENT
;
3280 vp
= xp
= dvp
= dirp
= NULL
;
3281 nmreq
= &nd
->nd_nmreq
;
3282 nfsm_chain_null(&nmrep
);
3284 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3285 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, dnfh
.nfh_fhp
, dnfh
.nfh_len
);
3286 nfsm_chain_get_32(error
, nmreq
, len
);
3287 nfsm_name_len_check(error
, nd
, len
);
3289 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
3292 /* update export stats */
3293 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3295 /* update active user stats */
3296 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
3298 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
3301 /* we're not allowed to link to directories... */
3302 if (vnode_vtype(vp
) == VDIR
) {
3303 error
= EPERM
; /* POSIX */
3307 /* ...or to anything that kauth doesn't want us to (eg. immutable items) */
3308 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, ctx
, nxo
, 0)) != 0)
3311 ni
.ni_cnd
.cn_nameiop
= CREATE
;
3315 ni
.ni_cnd
.cn_flags
= LOCKPARENT
;
3316 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
3318 error
= nfsrv_namei(nd
, ctx
, &ni
, &dnfh
, &dirp
, &nx
, &nxo
);
3320 if (nd
->nd_vers
== NFS_VER3
) {
3321 nfsm_srv_pre_vattr_init(&dpreattr
);
3322 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
3335 else if (vnode_mount(vp
) != vnode_mount(dvp
))
3338 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
, nxo
, 0);
3342 error
= mac_vnode_check_link(ctx
, dvp
, vp
, &ni
.ni_cnd
);
3348 error
= VNOP_LINK(vp
, dvp
, &ni
.ni_cnd
, ctx
);
3351 if (nfsrv_fsevents_enabled
&& !error
&& need_fsevent(FSE_CREATE_FILE
, dvp
)) {
3352 char *target_path
= NULL
;
3353 int plen
, truncated
=0;
3356 /* build the path to the new link file */
3357 target_path
= get_pathbuff();
3359 plen
= safe_getpath(dvp
, ni
.ni_cnd
.cn_nameptr
, target_path
, MAXPATHLEN
, &truncated
);
3361 if (get_fse_info(vp
, &finfo
, ctx
) == 0) {
3363 finfo
.mode
|= FSE_TRUNCATED_PATH
;
3365 add_fsevent(FSE_CREATE_FILE
, ctx
,
3366 FSE_ARG_STRING
, plen
, target_path
,
3367 FSE_ARG_FINFO
, &finfo
,
3371 release_pathbuff(target_path
);
3377 * nameidone has to happen before we vnode_put(dvp)
3378 * since it may need to release the fs_nodelock on the dvp
3386 if (nd
->nd_vers
== NFS_VER3
) {
3387 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
3388 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
3391 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
3392 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
3400 /* assemble reply */
3401 nd
->nd_repstat
= error
;
3402 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_WCCDATA(nd
->nd_vers
));
3404 *mrepp
= nmrep
.nmc_mhead
;
3405 nfsmout_on_status(nd
, error
);
3406 if (nd
->nd_vers
== NFS_VER3
) {
3407 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
3408 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3409 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
3412 nfsm_chain_build_done(error
, &nmrep
);
3416 nfsm_chain_cleanup(&nmrep
);
3423 * nfs symbolic link service
3427 struct nfsrv_descript
*nd
,
3428 struct nfsrv_sock
*slp
,
3432 struct vnode_attr dpreattr
, dpostattr
, postattr
;
3433 struct vnode_attr va
, *vap
= &va
;
3434 struct nameidata ni
;
3435 int error
, dpreattrerr
, dpostattrerr
, postattrerr
;
3436 uint32_t len
= 0, linkdatalen
, cnflags
;
3439 vnode_t vp
, dvp
, dirp
;
3440 struct nfs_filehandle nfh
;
3441 struct nfs_export
*nx
= NULL
;
3442 struct nfs_export_options
*nxo
;
3444 char uio_buf
[ UIO_SIZEOF(1) ];
3445 struct nfsm_chain
*nmreq
, nmrep
;
3448 dpreattrerr
= dpostattrerr
= postattrerr
= ENOENT
;
3449 nmreq
= &nd
->nd_nmreq
;
3450 nfsm_chain_null(&nmrep
);
3454 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
3456 ni
.ni_cnd
.cn_nameiop
= 0;
3459 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3460 nfsm_chain_get_32(error
, nmreq
, len
);
3461 nfsm_name_len_check(error
, nd
, len
);
3464 ni
.ni_cnd
.cn_nameiop
= CREATE
;
3468 ni
.ni_cnd
.cn_flags
= LOCKPARENT
;
3470 ni
.ni_cnd
.cn_ndp
= &ni
;
3471 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
3473 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
3475 /* update export stats */
3476 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3478 /* update active user stats */
3479 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
3483 if (nd
->nd_vers
== NFS_VER3
) {
3484 nfsm_srv_pre_vattr_init(&dpreattr
);
3485 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
3492 ni
.ni_cnd
.cn_nameiop
= 0;
3499 if (nd
->nd_vers
== NFS_VER3
)
3500 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
3501 nfsm_chain_get_32(error
, nmreq
, linkdatalen
);
3502 if (!error
&& (((nd
->nd_vers
== NFS_VER2
) && (linkdatalen
> NFS_MAXPATHLEN
)) ||
3503 ((nd
->nd_vers
== NFS_VER3
) && (linkdatalen
> MAXPATHLEN
))))
3504 error
= NFSERR_NAMETOL
;
3506 MALLOC(linkdata
, caddr_t
, linkdatalen
+ 1, M_TEMP
, M_WAITOK
);
3508 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3509 &uio_buf
[0], sizeof(uio_buf
));
3510 if (!linkdata
|| !auio
) {
3514 uio_addiov(auio
, CAST_USER_ADDR_T(linkdata
), linkdatalen
);
3515 error
= nfsm_chain_get_uio(nmreq
, linkdatalen
, auio
);
3516 if (!error
&& (nd
->nd_vers
== NFS_VER2
))
3517 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
3519 *(linkdata
+ linkdatalen
) = '\0';
3525 VATTR_SET(vap
, va_type
, VLNK
);
3526 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3527 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3529 * Server policy is to alway use the mapped rpc credential for
3530 * file system object creation. This has the nice side effect of
3531 * enforcing BSD creation semantics
3533 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3534 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3536 /* authorize before creating */
3537 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
, nxo
, 0);
3539 /* validate given attributes */
3541 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
3543 error
= vn_authorize_create(dvp
, &ni
.ni_cnd
, vap
, ctx
, NULL
);
3549 error
= VNOP_SYMLINK(dvp
, &vp
, &ni
.ni_cnd
, vap
, linkdata
, ctx
);
3551 if (!error
&& (nd
->nd_vers
== NFS_VER3
)) {
3553 ni
.ni_cnd
.cn_nameiop
= LOOKUP
;
3555 ni
.ni_op
= OP_LOOKUP
;
3557 ni
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| FOLLOW
);
3558 ni
.ni_cnd
.cn_flags
|= (NOFOLLOW
| LOCKLEAF
);
3559 ni
.ni_cnd
.cn_context
= ctx
;
3560 ni
.ni_startdir
= dvp
;
3562 ni
.ni_rootdir
= rootvnode
;
3563 cnflags
= ni
.ni_cnd
.cn_flags
; /* store in case we have to restore */
3564 while ((error
= lookup(&ni
)) == ERECYCLE
) {
3565 ni
.ni_cnd
.cn_flags
= cnflags
;
3566 ni
.ni_cnd
.cn_nameptr
= ni
.ni_cnd
.cn_pnbuf
;
3567 ni
.ni_usedvp
= ni
.ni_dvp
= ni
.ni_startdir
= dvp
;
3573 error
= nfsrv_vptofh(nx
, NFS_VER3
, NULL
, vp
, ctx
, &nfh
);
3575 nfsm_srv_vattr_init(&postattr
, NFS_VER3
);
3576 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
3582 if (nfsrv_fsevents_enabled
&& !error
&& vp
) {
3583 add_fsevent(FSE_CREATE_FILE
, ctx
,
3590 * nameidone has to happen before we vnode_put(dvp)
3591 * since it may need to release the fs_nodelock on the dvp
3594 ni
.ni_cnd
.cn_nameiop
= 0;
3600 FREE(linkdata
, M_TEMP
);
3604 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
3605 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
3611 /* assemble reply */
3612 nd
->nd_repstat
= error
;
3613 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(nd
->nd_vers
, &nfh
) +
3614 NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_WCCDATA(nd
->nd_vers
));
3616 *mrepp
= nmrep
.nmc_mhead
;
3617 nfsmout_on_status(nd
, error
);
3618 if (nd
->nd_vers
== NFS_VER3
) {
3619 if (!nd
->nd_repstat
) {
3620 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3621 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, postattrerr
, &postattr
);
3623 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3624 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
3627 nfsm_chain_build_done(error
, &nmrep
);
3628 if (ni
.ni_cnd
.cn_nameiop
) {
3630 * nameidone has to happen before we vnode_put(dvp)
3631 * since it may need to release the fs_nodelock on the dvp
3642 FREE(linkdata
, M_TEMP
);
3644 nfsm_chain_cleanup(&nmrep
);
3656 struct nfsrv_descript
*nd
,
3657 struct nfsrv_sock
*slp
,
3661 struct vnode_attr dpreattr
, dpostattr
, postattr
;
3662 struct vnode_attr va
, *vap
= &va
;
3663 struct nameidata ni
;
3664 int error
, dpreattrerr
, dpostattrerr
, postattrerr
;
3666 vnode_t vp
, dvp
, dirp
;
3667 struct nfs_filehandle nfh
;
3668 struct nfs_export
*nx
= NULL
;
3669 struct nfs_export_options
*nxo
;
3671 kauth_acl_t xacl
= NULL
;
3672 struct nfsm_chain
*nmreq
, nmrep
;
3675 dpreattrerr
= dpostattrerr
= postattrerr
= ENOENT
;
3676 nmreq
= &nd
->nd_nmreq
;
3677 nfsm_chain_null(&nmrep
);
3679 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
3681 ni
.ni_cnd
.cn_nameiop
= 0;
3682 vp
= dvp
= dirp
= NULL
;
3684 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3685 nfsm_chain_get_32(error
, nmreq
, len
);
3686 nfsm_name_len_check(error
, nd
, len
);
3689 ni
.ni_cnd
.cn_nameiop
= CREATE
;
3693 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| WILLBEDIR
;
3694 ni
.ni_cnd
.cn_ndp
= &ni
;
3695 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
3697 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
3699 /* update export stats */
3700 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3702 /* update active user stats */
3703 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
3707 if (nd
->nd_vers
== NFS_VER3
) {
3708 nfsm_srv_pre_vattr_init(&dpreattr
);
3709 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
3716 ni
.ni_cnd
.cn_nameiop
= 0;
3723 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
3725 VATTR_SET(vap
, va_type
, VDIR
);
3729 * nameidone has to happen before we vnode_put(dvp)
3730 * since it may need to release the fs_nodelock on the dvp
3739 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
, nxo
, 0);
3741 /* construct ACL and handle inheritance */
3743 error
= kauth_acl_inherit(dvp
,
3749 if (!error
&& xacl
!= NULL
)
3750 VATTR_SET(vap
, va_acl
, xacl
);
3753 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3754 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3756 * We don't support the S_ISGID bit for directories. Solaris and other
3757 * SRV4 derived systems might set this to get BSD semantics, which we enforce
3760 if (VATTR_IS_ACTIVE(vap
, va_mode
))
3761 vap
->va_mode
&= ~S_ISGID
;
3763 * Server policy is to alway use the mapped rpc credential for
3764 * file system object creation. This has the nice side effect of
3765 * enforcing BSD creation semantics
3767 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3768 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3770 /* validate new-file security information */
3772 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
3774 * vnode_authattr_new can return errors other than EPERM, but that's not going to
3775 * sit well with our clients so we map all errors to EPERM.
3781 error
= vn_authorize_mkdir(dvp
, &ni
.ni_cnd
, vap
, ctx
, NULL
);
3787 error
= VNOP_MKDIR(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
);
3790 if (nfsrv_fsevents_enabled
&& !error
)
3791 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
3794 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
3796 * If some of the requested attributes weren't handled by the VNOP,
3797 * use our fallback code.
3799 error
= vnode_setattr_fallback(vp
, vap
, ctx
);
3802 kauth_acl_free(xacl
);
3805 error
= nfsrv_vptofh(nx
, nd
->nd_vers
, NULL
, vp
, ctx
, &nfh
);
3807 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
3808 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
3809 if (nd
->nd_vers
== NFS_VER2
)
3810 error
= postattrerr
;
3816 * nameidone has to happen before we vnode_put(dvp)
3817 * since it may need to release the fs_nodelock on the dvp
3822 ni
.ni_cnd
.cn_nameiop
= 0;
3825 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
3826 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
3832 /* assemble reply */
3833 nd
->nd_repstat
= error
;
3834 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(nd
->nd_vers
, &nfh
) +
3835 NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_WCCDATA(nd
->nd_vers
));
3837 *mrepp
= nmrep
.nmc_mhead
;
3838 nfsmout_on_status(nd
, error
);
3839 if (nd
->nd_vers
== NFS_VER3
) {
3840 if (!nd
->nd_repstat
) {
3841 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3842 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, postattrerr
, &postattr
);
3844 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3845 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
3847 nfsm_chain_add_fh(error
, &nmrep
, NFS_VER2
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3849 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
3852 nfsm_chain_build_done(error
, &nmrep
);
3853 if (ni
.ni_cnd
.cn_nameiop
) {
3855 * nameidone has to happen before we vnode_put(dvp)
3856 * since it may need to release the fs_nodelock on the dvp
3866 nfsm_chain_cleanup(&nmrep
);
3877 struct nfsrv_descript
*nd
,
3878 struct nfsrv_sock
*slp
,
3882 int error
, dpreattrerr
, dpostattrerr
;
3885 vnode_t vp
, dvp
, dirp
;
3886 struct vnode_attr dpreattr
, dpostattr
;
3887 struct nfs_filehandle nfh
;
3888 struct nfs_export
*nx
= NULL
;
3889 struct nfs_export_options
*nxo
;
3890 struct nameidata ni
;
3891 struct nfsm_chain
*nmreq
, nmrep
;
3894 dpreattrerr
= dpostattrerr
= ENOENT
;
3895 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
3896 nmreq
= &nd
->nd_nmreq
;
3897 nfsm_chain_null(&nmrep
);
3899 vp
= dvp
= dirp
= NULL
;
3901 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3902 nfsm_chain_get_32(error
, nmreq
, len
);
3903 nfsm_name_len_check(error
, nd
, len
);
3906 ni
.ni_cnd
.cn_nameiop
= DELETE
;
3908 ni
.ni_op
= OP_UNLINK
;
3910 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
3911 ni
.ni_cnd
.cn_ndp
= &ni
;
3912 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
3914 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
3916 /* update export stats */
3917 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3919 /* update active user stats */
3920 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
3924 if (nd
->nd_vers
== NFS_VER3
) {
3925 nfsm_srv_pre_vattr_init(&dpreattr
);
3926 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
3937 if (vnode_vtype(vp
) != VDIR
) {
3942 * No rmdir "." please.
3949 * The root of a mounted filesystem cannot be deleted.
3951 if (vnode_isvroot(vp
))
3954 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, ctx
, nxo
, 0);
3956 error
= vn_authorize_rmdir(dvp
, vp
, &ni
.ni_cnd
, ctx
, NULL
);
3967 if (nfsrv_fsevents_enabled
&& need_fsevent(FSE_DELETE
, dvp
)) {
3969 if ((path
= get_pathbuff()) && !vn_getpath(vp
, path
, &plen
)) {
3970 get_fse_info(vp
, &finfo
, ctx
);
3972 release_pathbuff(path
);
3976 #endif /* CONFIG_FSE */
3978 error
= VNOP_RMDIR(dvp
, vp
, &ni
.ni_cnd
, ctx
);
3983 add_fsevent(FSE_DELETE
, ctx
,
3984 FSE_ARG_STRING
, plen
, path
,
3985 FSE_ARG_FINFO
, &finfo
,
3987 release_pathbuff(path
);
3989 #endif /* CONFIG_FSE */
3993 * nameidone has to happen before we vnode_put(dvp)
3994 * since it may need to release the fs_nodelock on the dvp
4002 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
4003 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
4009 /* assemble reply */
4010 nd
->nd_repstat
= error
;
4011 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCDATA(nd
->nd_vers
));
4013 *mrepp
= nmrep
.nmc_mhead
;
4014 nfsmout_on_status(nd
, error
);
4015 if (nd
->nd_vers
== NFS_VER3
)
4016 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
4017 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
4019 nfsm_chain_build_done(error
, &nmrep
);
4023 nfsm_chain_cleanup(&nmrep
);
4030 * nfs readdir service
4031 * - mallocs what it thinks is enough to read
4032 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
4033 * - calls VNOP_READDIR()
4034 * - loops around building the reply
4035 * if the output generated exceeds count break out of loop
4036 * The nfsm_clget macro is used here so that the reply will be packed
4037 * tightly in mbuf clusters.
4038 * - it only knows that it has encountered eof when the VNOP_READDIR()
4040 * - as such one readdir rpc will return eof false although you are there
4041 * and then the next will return eof
4042 * - it trims out records with d_fileno == 0
4043 * this doesn't matter for Unix clients, but they might confuse clients
4045 * NB: It is tempting to set eof to true if the VNOP_READDIR() reads less
4046 * than requested, but this may not apply to all filesystems. For
4047 * example, client NFS does not { although it is never remote mounted
4049 * The alternate call nfsrv_readdirplus() does lookups as well.
4050 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
4051 * are supposed to cover. For readdir, the count is the total number of
4052 * bytes included in everything from the directory's postopattr through
4053 * the EOF flag. For readdirplus, the maxcount is the same, and the
4054 * dircount includes all that except for the entry attributes and handles.
4058 struct nfsrv_descript
*nd
,
4059 struct nfsrv_sock
*slp
,
4063 struct direntry
*dp
;
4064 char *cpos
, *cend
, *rbuf
;
4066 struct vnode_attr attr
;
4067 struct nfs_filehandle nfh
;
4068 struct nfs_export
*nx
;
4069 struct nfs_export_options
*nxo
;
4071 char uio_buf
[ UIO_SIZEOF(1) ];
4072 int len
, nlen
, rem
, xfer
, error
, attrerr
;
4073 int siz
, count
, fullsiz
, eofflag
, nentries
;
4074 u_quad_t off
, toff
, verf
;
4076 struct nfsm_chain
*nmreq
, nmrep
;
4080 count
= nentries
= 0;
4081 nmreq
= &nd
->nd_nmreq
;
4082 nfsm_chain_null(&nmrep
);
4086 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
4088 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4089 if (nd
->nd_vers
== NFS_VER3
) {
4090 nfsm_chain_get_64(error
, nmreq
, toff
);
4091 nfsm_chain_get_64(error
, nmreq
, verf
);
4093 nfsm_chain_get_32(error
, nmreq
, toff
);
4095 nfsm_chain_get_32(error
, nmreq
, count
);
4099 siz
= ((count
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
4100 xfer
= NFSRV_NDMAXDATA(nd
);
4105 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4108 /* update export stats */
4109 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4111 /* update active user stats */
4112 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4114 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4117 if (nxo
->nxo_flags
& NX_MANGLEDNAMES
|| nd
->nd_vers
== NFS_VER2
)
4118 vnopflag
|= VNODE_READDIR_NAMEMAX
;
4120 if ((nd
->nd_vers
== NFS_VER2
) || (nxo
->nxo_flags
& NX_32BITCLIENTS
))
4121 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
4123 if (nd
->nd_vers
== NFS_VER3
) {
4124 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4125 error
= attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4126 if (!error
&& toff
&& verf
&& (verf
!= attr
.va_filerev
))
4127 error
= NFSERR_BAD_COOKIE
;
4130 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, ctx
, nxo
, 0);
4133 if (!error
&& mac_vnode_check_open(ctx
, vp
, FREAD
))
4137 error
= mac_vnode_check_readdir(ctx
, vp
);
4142 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
4144 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
4145 &uio_buf
[0], sizeof(uio_buf
));
4146 if (!rbuf
|| !auio
) {
4151 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
4152 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
4154 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, ctx
);
4155 off
= uio_offset(auio
);
4157 if (nd
->nd_vers
== NFS_VER3
) {
4158 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4159 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4163 if (uio_resid(auio
) != 0) {
4164 siz
-= uio_resid(auio
);
4166 /* If nothing read, return empty reply with eof set */
4171 /* assemble reply */
4172 nd
->nd_repstat
= error
;
4173 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) +
4174 NFSX_COOKIEVERF(nd
->nd_vers
) + 2 * NFSX_UNSIGNED
);
4176 *mrepp
= nmrep
.nmc_mhead
;
4177 nfsmout_on_status(nd
, error
);
4178 if (nd
->nd_vers
== NFS_VER3
) {
4179 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4180 nfsm_chain_add_64(error
, &nmrep
, attr
.va_filerev
);
4182 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4183 nfsm_chain_add_32(error
, &nmrep
, TRUE
);
4184 nfsm_chain_build_done(error
, &nmrep
);
4190 * Check for degenerate cases of nothing useful read.
4191 * If so go try again
4195 dp
= (struct direntry
*)cpos
;
4196 while ((dp
->d_fileno
== 0) && (cpos
< cend
) && (nentries
> 0)) {
4197 cpos
+= dp
->d_reclen
;
4198 dp
= (struct direntry
*)cpos
;
4201 if ((cpos
>= cend
) || (nentries
== 0)) {
4210 /* assemble reply */
4211 nd
->nd_repstat
= error
;
4212 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) +
4213 NFSX_COOKIEVERF(nd
->nd_vers
) + siz
);
4215 *mrepp
= nmrep
.nmc_mhead
;
4216 nfsmout_on_status(nd
, error
);
4217 nmrep
.nmc_flags
|= NFSM_CHAIN_FLAG_ADD_CLUSTERS
;
4219 len
= 2 * NFSX_UNSIGNED
;
4220 if (nd
->nd_vers
== NFS_VER3
) {
4221 len
+= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
;
4222 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4223 nfsm_chain_add_64(error
, &nmrep
, attr
.va_filerev
);
4227 /* Loop through the records and build reply */
4228 while ((cpos
< cend
) && (nentries
> 0)) {
4229 if (dp
->d_fileno
!= 0) {
4230 nlen
= dp
->d_namlen
;
4231 if ((nd
->nd_vers
== NFS_VER2
) && (nlen
> NFS_MAXNAMLEN
))
4232 nlen
= NFS_MAXNAMLEN
;
4233 rem
= nfsm_rndup(nlen
)-nlen
;
4234 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
4235 if (nd
->nd_vers
== NFS_VER3
)
4236 len
+= 2 * NFSX_UNSIGNED
;
4241 /* Build the directory record xdr from the direntry. */
4242 nfsm_chain_add_32(error
, &nmrep
, TRUE
);
4243 if (nd
->nd_vers
== NFS_VER3
) {
4244 nfsm_chain_add_64(error
, &nmrep
, dp
->d_fileno
);
4246 nfsm_chain_add_32(error
, &nmrep
, dp
->d_fileno
);
4248 nfsm_chain_add_string(error
, &nmrep
, dp
->d_name
, nlen
);
4249 if (nd
->nd_vers
== NFS_VER3
) {
4250 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
4251 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
4252 nfsm_chain_add_64(error
, &nmrep
, dp
->d_seekoff
);
4254 nfsm_chain_add_32(error
, &nmrep
, dp
->d_seekoff
);
4258 cpos
+= dp
->d_reclen
;
4259 dp
= (struct direntry
*)cpos
;
4262 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4263 nfsm_chain_add_32(error
, &nmrep
, eofflag
? TRUE
: FALSE
);
4271 nd
->nd_repstat
= error
;
4272 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
));
4274 *mrepp
= nmrep
.nmc_mhead
;
4275 nfsmout_on_status(nd
, error
);
4276 if (nd
->nd_vers
== NFS_VER3
)
4277 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4279 nfsm_chain_build_done(error
, &nmrep
);
4281 nfsm_chain_cleanup(&nmrep
);
4289 struct nfsrv_descript
*nd
,
4290 struct nfsrv_sock
*slp
,
4294 struct direntry
*dp
;
4295 char *cpos
, *cend
, *rbuf
;
4297 struct nfs_filehandle dnfh
, nfh
;
4298 struct nfs_export
*nx
;
4299 struct nfs_export_options
*nxo
;
4301 char uio_buf
[ UIO_SIZEOF(1) ];
4302 struct vnode_attr attr
, va
, *vap
= &va
;
4303 int len
, nlen
, rem
, xfer
, error
, attrerr
, gotfh
, gotattr
;
4304 int siz
, dircount
, maxcount
, fullsiz
, eofflag
, dirlen
, nentries
, isdotdot
;
4305 u_quad_t off
, toff
, verf
;
4307 struct nfsm_chain
*nmreq
, nmrep
;
4312 nmreq
= &nd
->nd_nmreq
;
4313 nfsm_chain_null(&nmrep
);
4316 dircount
= maxcount
= 0;
4318 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
4320 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, dnfh
.nfh_fhp
, dnfh
.nfh_len
);
4321 nfsm_chain_get_64(error
, nmreq
, toff
);
4322 nfsm_chain_get_64(error
, nmreq
, verf
);
4323 nfsm_chain_get_32(error
, nmreq
, dircount
);
4324 nfsm_chain_get_32(error
, nmreq
, maxcount
);
4328 xfer
= NFSRV_NDMAXDATA(nd
);
4329 dircount
= ((dircount
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
4330 if (dircount
> xfer
)
4332 fullsiz
= siz
= dircount
;
4333 maxcount
= ((maxcount
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
4334 if (maxcount
> xfer
)
4337 error
= nfsrv_fhtovp(&dnfh
, nd
, &vp
, &nx
, &nxo
);
4340 /* update export stats */
4341 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4343 /* update active user stats */
4344 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4346 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4349 if (nxo
->nxo_flags
& NX_32BITCLIENTS
)
4350 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
4352 if (nxo
->nxo_flags
& NX_MANGLEDNAMES
)
4353 vnopflag
|= VNODE_READDIR_NAMEMAX
;
4355 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4356 error
= attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4357 if (!error
&& toff
&& verf
&& (verf
!= attr
.va_filerev
))
4358 error
= NFSERR_BAD_COOKIE
;
4360 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, ctx
, nxo
, 0);
4363 if (!error
&& mac_vnode_check_open(ctx
, vp
, FREAD
))
4367 error
= mac_vnode_check_readdir(ctx
, vp
);
4372 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
4374 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
4375 &uio_buf
[0], sizeof(uio_buf
));
4376 if (!rbuf
|| !auio
) {
4382 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
4383 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
4385 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, ctx
);
4386 off
= uio_offset(auio
);
4387 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4388 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4391 if (uio_resid(auio
) != 0) {
4392 siz
-= uio_resid(auio
);
4394 /* If nothing read, return empty reply with eof set */
4399 /* assemble reply */
4400 nd
->nd_repstat
= error
;
4401 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3POSTOPATTR
+
4402 NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
);
4404 *mrepp
= nmrep
.nmc_mhead
;
4405 nfsmout_on_status(nd
, error
);
4406 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4407 nfsm_chain_add_64(error
, &nmrep
, attr
.va_filerev
);
4408 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4409 nfsm_chain_add_32(error
, &nmrep
, TRUE
);
4410 nfsm_chain_build_done(error
, &nmrep
);
4416 * Check for degenerate cases of nothing useful read.
4417 * If so go try again
4421 dp
= (struct direntry
*)cpos
;
4422 while ((dp
->d_fileno
== 0) && (cpos
< cend
) && (nentries
> 0)) {
4423 cpos
+= dp
->d_reclen
;
4424 dp
= (struct direntry
*)cpos
;
4427 if ((cpos
>= cend
) || (nentries
== 0)) {
4434 * Probe one of the directory entries to see if the filesystem
4437 if ((error
= VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, ctx
))) {
4438 if (error
== ENOTSUP
) /* let others get passed back */
4439 error
= NFSERR_NOTSUPP
;
4444 /* assemble reply */
4445 nd
->nd_repstat
= error
;
4446 error
= nfsrv_rephead(nd
, slp
, &nmrep
, maxcount
);
4448 *mrepp
= nmrep
.nmc_mhead
;
4449 nfsmout_on_status(nd
, error
);
4450 nmrep
.nmc_flags
|= NFSM_CHAIN_FLAG_ADD_CLUSTERS
;
4452 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
4453 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4454 nfsm_chain_add_64(error
, &nmrep
, attr
.va_filerev
);
4457 /* Loop through the records and build reply */
4458 while ((cpos
< cend
) && (nentries
> 0)) {
4459 if (dp
->d_fileno
!= 0) {
4460 nlen
= dp
->d_namlen
;
4461 rem
= nfsm_rndup(nlen
)-nlen
;
4462 gotfh
= gotattr
= 1;
4464 /* Got to get the vnode for lookup per entry. */
4465 if (VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, ctx
)) {
4466 /* Can't get the vnode... so no fh or attrs */
4467 gotfh
= gotattr
= 0;
4469 isdotdot
= ((dp
->d_namlen
== 2) &&
4470 (dp
->d_name
[0] == '.') && (dp
->d_name
[1] == '.'));
4471 if (nfsrv_vptofh(nx
, 0, (isdotdot
? &dnfh
: NULL
), nvp
, ctx
, &nfh
))
4473 nfsm_srv_vattr_init(vap
, NFS_VER3
);
4474 if (vnode_getattr(nvp
, vap
, ctx
))
4480 * If either the dircount or maxcount will be
4481 * exceeded, get out now. Both of these lengths
4482 * are calculated conservatively, including all
4485 len
+= 8 * NFSX_UNSIGNED
+ nlen
+ rem
;
4487 len
+= NFSX_V3FATTR
;
4489 len
+= NFSX_UNSIGNED
+ nfsm_rndup(nfh
.nfh_len
);
4490 dirlen
+= 6 * NFSX_UNSIGNED
+ nlen
+ rem
;
4491 if ((len
> maxcount
) || (dirlen
> dircount
)) {
4496 /* Build the directory record xdr from the direntry. */
4497 nfsm_chain_add_32(error
, &nmrep
, TRUE
);
4498 nfsm_chain_add_64(error
, &nmrep
, dp
->d_fileno
);
4499 nfsm_chain_add_string(error
, &nmrep
, dp
->d_name
, nlen
);
4500 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
4501 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
4502 nfsm_chain_add_64(error
, &nmrep
, dp
->d_seekoff
);
4503 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, (gotattr
? 0 : ENOENT
), vap
);
4505 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4507 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4510 cpos
+= dp
->d_reclen
;
4511 dp
= (struct direntry
*)cpos
;
4516 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4517 nfsm_chain_add_32(error
, &nmrep
, eofflag
? TRUE
: FALSE
);
4523 nd
->nd_repstat
= error
;
4524 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3POSTOPATTR
);
4526 *mrepp
= nmrep
.nmc_mhead
;
4527 nfsmout_on_status(nd
, error
);
4528 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4530 nfsm_chain_build_done(error
, &nmrep
);
4534 nfsm_chain_cleanup(&nmrep
);
4541 * nfs commit service
4545 struct nfsrv_descript
*nd
,
4546 struct nfsrv_sock
*slp
,
4551 struct nfs_filehandle nfh
;
4552 struct nfs_export
*nx
;
4553 struct nfs_export_options
*nxo
;
4554 int error
, preattrerr
, postattrerr
, count
;
4555 struct vnode_attr preattr
, postattr
;
4557 struct nfsm_chain
*nmreq
, nmrep
;
4560 preattrerr
= postattrerr
= ENOENT
;
4561 nmreq
= &nd
->nd_nmreq
;
4562 nfsm_chain_null(&nmrep
);
4566 * XXX At this time VNOP_FSYNC() does not accept offset and byte
4567 * count parameters, so those arguments are useless (someday maybe).
4570 nfsm_chain_get_fh_ptr(error
, nmreq
, NFS_VER3
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4571 nfsm_chain_get_64(error
, nmreq
, off
);
4572 nfsm_chain_get_32(error
, nmreq
, count
);
4575 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4578 /* update export stats */
4579 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4581 /* update active user stats */
4582 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4584 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4587 nfsm_srv_pre_vattr_init(&preattr
);
4588 preattrerr
= vnode_getattr(vp
, &preattr
, ctx
);
4590 error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
);
4592 nfsm_srv_vattr_init(&postattr
, 1);
4593 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
4599 /* assemble reply */
4600 nd
->nd_repstat
= error
;
4601 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
4603 *mrepp
= nmrep
.nmc_mhead
;
4604 nfsmout_on_status(nd
, error
);
4605 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
4606 preattrerr
, &preattr
, postattrerr
, &postattr
);
4607 if (!nd
->nd_repstat
) {
4608 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_sec
);
4609 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_usec
);
4612 nfsm_chain_build_done(error
, &nmrep
);
4614 nfsm_chain_cleanup(&nmrep
);
4621 * nfs statfs service
4625 struct nfsrv_descript
*nd
,
4626 struct nfsrv_sock
*slp
,
4633 struct vnode_attr attr
;
4634 struct nfs_filehandle nfh
;
4635 struct nfs_export
*nx
;
4636 struct nfs_export_options
*nxo
;
4638 struct nfsm_chain
*nmreq
, nmrep
;
4642 nmreq
= &nd
->nd_nmreq
;
4643 nfsm_chain_null(&nmrep
);
4647 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4649 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4652 /* update export stats */
4653 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4655 /* update active user stats */
4656 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4658 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4662 VFSATTR_WANTED(&va
, f_blocks
);
4663 VFSATTR_WANTED(&va
, f_bavail
);
4664 VFSATTR_WANTED(&va
, f_files
);
4665 VFSATTR_WANTED(&va
, f_ffree
);
4666 error
= vfs_getattr(vnode_mount(vp
), &va
, ctx
);
4667 blksize
= vnode_mount(vp
)->mnt_vfsstat
.f_bsize
;
4669 if (nd
->nd_vers
== NFS_VER3
) {
4670 nfsm_srv_vattr_init(&attr
, nd
->nd_vers
);
4671 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4678 /* assemble reply */
4679 nd
->nd_repstat
= error
;
4680 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_STATFS(nd
->nd_vers
));
4682 *mrepp
= nmrep
.nmc_mhead
;
4683 nfsmout_on_status(nd
, error
);
4684 if (nd
->nd_vers
== NFS_VER3
)
4685 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4686 nfsmout_if(nd
->nd_repstat
);
4688 if (nd
->nd_vers
== NFS_VER3
) {
4689 nfsm_chain_add_64(error
, &nmrep
, va
.f_blocks
* blksize
);
4690 nfsm_chain_add_64(error
, &nmrep
, va
.f_bfree
* blksize
);
4691 nfsm_chain_add_64(error
, &nmrep
, va
.f_bavail
* blksize
);
4692 nfsm_chain_add_64(error
, &nmrep
, va
.f_files
);
4693 nfsm_chain_add_64(error
, &nmrep
, va
.f_ffree
);
4694 nfsm_chain_add_64(error
, &nmrep
, va
.f_ffree
);
4695 nfsm_chain_add_32(error
, &nmrep
, 0); /* invarsec */
4697 nfsm_chain_add_32(error
, &nmrep
, NFS_V2MAXDATA
);
4698 nfsm_chain_add_32(error
, &nmrep
, blksize
);
4699 nfsm_chain_add_32(error
, &nmrep
, va
.f_blocks
);
4700 nfsm_chain_add_32(error
, &nmrep
, va
.f_bfree
);
4701 nfsm_chain_add_32(error
, &nmrep
, va
.f_bavail
);
4704 nfsm_chain_build_done(error
, &nmrep
);
4706 nfsm_chain_cleanup(&nmrep
);
4713 * nfs fsinfo service
4717 struct nfsrv_descript
*nd
,
4718 struct nfsrv_sock
*slp
,
4722 int error
, attrerr
, prefsize
, maxsize
;
4724 struct vnode_attr attr
;
4725 struct nfs_filehandle nfh
;
4726 struct nfs_export
*nx
;
4727 struct nfs_export_options
*nxo
;
4728 struct nfsm_chain
*nmreq
, nmrep
;
4732 nmreq
= &nd
->nd_nmreq
;
4733 nfsm_chain_null(&nmrep
);
4736 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4738 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4741 /* update export stats */
4742 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4744 /* update active user stats */
4745 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4747 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4750 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4751 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4757 /* assemble reply */
4758 nd
->nd_repstat
= error
;
4759 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
4761 *mrepp
= nmrep
.nmc_mhead
;
4762 nfsmout_on_status(nd
, error
);
4763 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4764 nfsmout_if(nd
->nd_repstat
);
4767 * XXX There should be file system VFS OP(s) to get this information.
4768 * For now, assume our usual NFS defaults.
4770 if (slp
->ns_sotype
== SOCK_DGRAM
) {
4771 maxsize
= NFS_MAXDGRAMDATA
;
4772 prefsize
= NFS_PREFDGRAMDATA
;
4774 maxsize
= prefsize
= NFSRV_MAXDATA
;
4776 nfsm_chain_add_32(error
, &nmrep
, maxsize
);
4777 nfsm_chain_add_32(error
, &nmrep
, prefsize
);
4778 nfsm_chain_add_32(error
, &nmrep
, NFS_FABLKSIZE
);
4779 nfsm_chain_add_32(error
, &nmrep
, maxsize
);
4780 nfsm_chain_add_32(error
, &nmrep
, prefsize
);
4781 nfsm_chain_add_32(error
, &nmrep
, NFS_FABLKSIZE
);
4782 nfsm_chain_add_32(error
, &nmrep
, prefsize
);
4783 nfsm_chain_add_64(error
, &nmrep
, 0xffffffffffffffffULL
);
4784 nfsm_chain_add_32(error
, &nmrep
, 0);
4785 nfsm_chain_add_32(error
, &nmrep
, 1);
4786 /* XXX link/symlink support should be taken from volume capabilities */
4787 nfsm_chain_add_32(error
, &nmrep
,
4788 NFSV3FSINFO_LINK
| NFSV3FSINFO_SYMLINK
|
4789 NFSV3FSINFO_HOMOGENEOUS
| NFSV3FSINFO_CANSETTIME
);
4792 nfsm_chain_build_done(error
, &nmrep
);
4794 nfsm_chain_cleanup(&nmrep
);
4801 * nfs pathconf service
4805 struct nfsrv_descript
*nd
,
4806 struct nfsrv_sock
*slp
,
4810 int error
, attrerr
, linkmax
, namemax
;
4811 int chownres
, notrunc
, case_sensitive
, case_preserving
;
4813 struct vnode_attr attr
;
4814 struct nfs_filehandle nfh
;
4815 struct nfs_export
*nx
;
4816 struct nfs_export_options
*nxo
;
4817 struct nfsm_chain
*nmreq
, nmrep
;
4821 nmreq
= &nd
->nd_nmreq
;
4822 nfsm_chain_null(&nmrep
);
4825 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4827 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4830 /* update export stats */
4831 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4833 /* update active user stats */
4834 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4836 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4839 error
= VNOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
, ctx
);
4841 error
= VNOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
, ctx
);
4843 error
= VNOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
, ctx
);
4845 error
= VNOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
, ctx
);
4847 error
= VNOP_PATHCONF(vp
, _PC_CASE_SENSITIVE
, &case_sensitive
, ctx
);
4849 error
= VNOP_PATHCONF(vp
, _PC_CASE_PRESERVING
, &case_preserving
, ctx
);
4851 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4852 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4858 /* assemble reply */
4859 nd
->nd_repstat
= error
;
4860 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
4862 *mrepp
= nmrep
.nmc_mhead
;
4863 nfsmout_on_status(nd
, error
);
4864 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4865 nfsmout_if(nd
->nd_repstat
);
4867 nfsm_chain_add_32(error
, &nmrep
, linkmax
);
4868 nfsm_chain_add_32(error
, &nmrep
, namemax
);
4869 nfsm_chain_add_32(error
, &nmrep
, notrunc
);
4870 nfsm_chain_add_32(error
, &nmrep
, chownres
);
4871 nfsm_chain_add_32(error
, &nmrep
, !case_sensitive
);
4872 nfsm_chain_add_32(error
, &nmrep
, case_preserving
);
4875 nfsm_chain_build_done(error
, &nmrep
);
4877 nfsm_chain_cleanup(&nmrep
);
4884 * Null operation, used by clients to ping server
4889 struct nfsrv_descript
*nd
,
4890 struct nfsrv_sock
*slp
,
4891 __unused vfs_context_t ctx
,
4894 int error
= NFSERR_RETVOID
;
4895 struct nfsm_chain nmrep
;
4898 * RPCSEC_GSS context setup ?
4900 if (nd
->nd_gss_context
)
4901 return(nfs_gss_svc_ctx_init(nd
, slp
, mrepp
));
4903 nfsm_chain_null(&nmrep
);
4905 /* assemble reply */
4906 nd
->nd_repstat
= error
;
4907 error
= nfsrv_rephead(nd
, slp
, &nmrep
, 0);
4909 *mrepp
= nmrep
.nmc_mhead
;
4911 nfsm_chain_build_done(error
, &nmrep
);
4913 nfsm_chain_cleanup(&nmrep
);
4920 * No operation, used for obsolete procedures
4925 struct nfsrv_descript
*nd
,
4926 struct nfsrv_sock
*slp
,
4927 __unused vfs_context_t ctx
,
4931 struct nfsm_chain nmrep
;
4933 nfsm_chain_null(&nmrep
);
4936 error
= nd
->nd_repstat
;
4938 error
= EPROCUNAVAIL
;
4940 /* assemble reply */
4941 nd
->nd_repstat
= error
;
4942 error
= nfsrv_rephead(nd
, slp
, &nmrep
, 0);
4944 *mrepp
= nmrep
.nmc_mhead
;
4946 nfsm_chain_build_done(error
, &nmrep
);
4948 nfsm_chain_cleanup(&nmrep
);
4954 const nfsrv_proc_t nfsrv_procs
[NFS_NPROCS
] = {
4981 * Perform access checking for vnodes obtained from file handles that would
4982 * refer to files already opened by a Unix client. You cannot just use
4983 * vnode_authorize() for two reasons.
4984 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4985 * 2 - The owner is to be given access irrespective of mode bits so that
4986 * processes that chmod after opening a file don't break. I don't like
4987 * this because it opens a security hole, but since the nfs server opens
4988 * a security hole the size of a barn door anyhow, what the heck.
4990 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, vnode_authorize()
4991 * will return EPERM instead of EACCESS. EPERM is always an error.
4998 kauth_action_t action
,
5000 struct nfs_export_options
*nxo
,
5003 struct vnode_attr vattr
;
5006 if (action
& KAUTH_VNODE_WRITE_RIGHTS
) {
5008 * Disallow write attempts on read-only exports;
5009 * unless the file is a socket or a block or character
5010 * device resident on the file system.
5012 if (nxo
->nxo_flags
& NX_READONLY
) {
5013 switch (vnode_vtype(vp
)) {
5014 case VREG
: case VDIR
: case VLNK
: case VCPLX
:
5021 error
= vnode_authorize(vp
, dvp
, action
, ctx
);
5023 * Allow certain operations for the owner (reads and writes
5024 * on files that are already open). Picking up from FreeBSD.
5026 if (override
&& (error
== EACCES
)) {
5028 VATTR_WANTED(&vattr
, va_uid
);
5029 if ((vnode_getattr(vp
, &vattr
, ctx
) == 0) &&
5030 (kauth_cred_getuid(vfs_context_ucred(ctx
)) == vattr
.va_uid
))
5036 #endif /* NFSSERVER */