2 * Copyright (c) 2000-2009 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>
90 #include <sys/vmparam.h>
92 #include <nfs/nfsproto.h>
93 #include <nfs/rpcv2.h>
95 #include <nfs/xdr_subs.h>
96 #include <nfs/nfsm_subs.h>
97 #include <nfs/nfsrvcache.h>
98 #include <nfs/nfs_gss.h>
106 int nfsd_thread_count
= 0;
107 int nfsd_thread_max
= 0;
108 lck_grp_t
*nfsd_lck_grp
;
109 lck_mtx_t
*nfsd_mutex
;
110 struct nfsd_head nfsd_head
, nfsd_queue
;
112 lck_grp_t
*nfsrv_slp_rwlock_group
;
113 lck_grp_t
*nfsrv_slp_mutex_group
;
114 struct nfsrv_sockhead nfsrv_socklist
, nfsrv_deadsocklist
, nfsrv_sockwg
,
115 nfsrv_sockwait
, nfsrv_sockwork
;
116 struct nfsrv_sock
*nfsrv_udpsock
= NULL
;
119 struct nfsrv_expfs_list nfsrv_exports
;
120 struct nfsrv_export_hashhead
*nfsrv_export_hashtbl
= NULL
;
121 int nfsrv_export_hash_size
= NFSRVEXPHASHSZ
;
122 u_long nfsrv_export_hash
;
123 lck_grp_t
*nfsrv_export_rwlock_group
;
124 lck_rw_t nfsrv_export_rwlock
;
127 /* NFS server file modification event generator */
128 struct nfsrv_fmod_hashhead
*nfsrv_fmod_hashtbl
;
129 u_long nfsrv_fmod_hash
;
130 lck_grp_t
*nfsrv_fmod_grp
;
131 lck_mtx_t
*nfsrv_fmod_mutex
;
132 static int nfsrv_fmod_timer_on
= 0;
133 int nfsrv_fsevents_enabled
= 1;
136 /* NFS server timers */
138 thread_call_t nfsrv_fmod_timer_call
;
140 thread_call_t nfsrv_deadsock_timer_call
;
141 thread_call_t nfsrv_wg_timer_call
;
142 int nfsrv_wg_timer_on
;
144 /* globals for the active user list */
145 uint32_t nfsrv_user_stat_enabled
= 1;
146 uint32_t nfsrv_user_stat_node_count
= 0;
147 uint32_t nfsrv_user_stat_max_idle_sec
= NFSRV_USER_STAT_DEF_IDLE_SEC
;
148 uint32_t nfsrv_user_stat_max_nodes
= NFSRV_USER_STAT_DEF_MAX_NODES
;
149 lck_grp_t
*nfsrv_active_user_mutex_group
;
151 int nfsrv_wg_delay
= NFSRV_WGATHERDELAY
* 1000;
152 int nfsrv_wg_delay_v3
= 0;
156 int nfsrv_authorize(vnode_t
,vnode_t
,kauth_action_t
,vfs_context_t
,struct nfs_export_options
*,int);
157 int nfsrv_wg_coalesce(struct nfsrv_descript
*, struct nfsrv_descript
*);
158 void nfsrv_modified(vnode_t
, vfs_context_t
);
160 extern void IOSleep(int);
161 extern int safe_getpath(struct vnode
*dvp
, char *leafname
, char *path
, int _len
, int *truncated_path
);
164 * Initialize the data structures for the server.
167 #define NFSRV_NOT_INITIALIZED 0
168 #define NFSRV_INITIALIZING 1
169 #define NFSRV_INITIALIZED 2
170 static volatile UInt32 nfsrv_initted
= NFSRV_NOT_INITIALIZED
;
173 nfsrv_is_initialized(void)
175 return (nfsrv_initted
== NFSRV_INITIALIZED
);
181 /* make sure we init only once */
182 if (!OSCompareAndSwap(NFSRV_NOT_INITIALIZED
, NFSRV_INITIALIZING
, &nfsrv_initted
)) {
183 /* wait until initialization is complete */
184 while (!nfsrv_is_initialized())
189 if (sizeof (struct nfsrv_sock
) > NFS_SVCALLOC
)
190 printf("struct nfsrv_sock bloated (> %dbytes)\n",NFS_SVCALLOC
);
192 /* init nfsd mutex */
193 nfsd_lck_grp
= lck_grp_alloc_init("nfsd", LCK_GRP_ATTR_NULL
);
194 nfsd_mutex
= lck_mtx_alloc_init(nfsd_lck_grp
, LCK_ATTR_NULL
);
196 /* init slp rwlock */
197 nfsrv_slp_rwlock_group
= lck_grp_alloc_init("nfsrv-slp-rwlock", LCK_GRP_ATTR_NULL
);
198 nfsrv_slp_mutex_group
= lck_grp_alloc_init("nfsrv-slp-mutex", LCK_GRP_ATTR_NULL
);
200 /* init export data structures */
201 LIST_INIT(&nfsrv_exports
);
202 nfsrv_export_rwlock_group
= lck_grp_alloc_init("nfsrv-export-rwlock", LCK_GRP_ATTR_NULL
);
203 lck_rw_init(&nfsrv_export_rwlock
, nfsrv_export_rwlock_group
, LCK_ATTR_NULL
);
205 /* init active user list mutex structures */
206 nfsrv_active_user_mutex_group
= lck_grp_alloc_init("nfs-active-user-mutex", LCK_GRP_ATTR_NULL
);
208 /* init nfs server request cache mutex */
209 nfsrv_reqcache_lck_grp
= lck_grp_alloc_init("nfsrv_reqcache", LCK_GRP_ATTR_NULL
);
210 nfsrv_reqcache_mutex
= lck_mtx_alloc_init(nfsrv_reqcache_lck_grp
, LCK_ATTR_NULL
);
213 /* init NFS server file modified event generation */
214 nfsrv_fmod_hashtbl
= hashinit(NFSRVFMODHASHSZ
, M_TEMP
, &nfsrv_fmod_hash
);
215 nfsrv_fmod_grp
= lck_grp_alloc_init("nfsrv_fmod", LCK_GRP_ATTR_NULL
);
216 nfsrv_fmod_mutex
= lck_mtx_alloc_init(nfsrv_fmod_grp
, LCK_ATTR_NULL
);
219 /* initialize NFS server timer callouts */
221 nfsrv_fmod_timer_call
= thread_call_allocate(nfsrv_fmod_timer
, NULL
);
223 nfsrv_deadsock_timer_call
= thread_call_allocate(nfsrv_deadsock_timer
, NULL
);
224 nfsrv_wg_timer_call
= thread_call_allocate(nfsrv_wg_timer
, NULL
);
226 /* Init server data structures */
227 TAILQ_INIT(&nfsrv_socklist
);
228 TAILQ_INIT(&nfsrv_sockwait
);
229 TAILQ_INIT(&nfsrv_sockwork
);
230 TAILQ_INIT(&nfsrv_deadsocklist
);
231 TAILQ_INIT(&nfsrv_sockwg
);
232 TAILQ_INIT(&nfsd_head
);
233 TAILQ_INIT(&nfsd_queue
);
234 nfsrv_udpsock
= NULL
;
236 /* initialization complete */
237 nfsrv_initted
= NFSRV_INITIALIZED
;
243 * NFS version 2 and 3 server request processing functions
245 * These functions take the following parameters:
247 * struct nfsrv_descript *nd - the NFS request descriptor
248 * struct nfsrv_sock *slp - the NFS socket the request came in on
249 * vfs_context_t ctx - VFS context
250 * mbuf_t *mrepp - pointer to hold the reply mbuf list
252 * These routines generally have 3 phases:
254 * 1 - break down and validate the RPC request in the mbuf chain
255 * provided in nd->nd_nmreq.
256 * 2 - perform the vnode operations for the request
257 * (many are very similar to syscalls in vfs_syscalls.c and
258 * should therefore be kept in sync with those implementations)
259 * 3 - build the RPC reply in an mbuf chain (nmrep) and return the mbuf chain
264 * nfs v3 access service
268 struct nfsrv_descript
*nd
,
269 struct nfsrv_sock
*slp
,
273 struct nfsm_chain
*nmreq
, nmrep
;
276 struct vnode_attr vattr
;
277 struct nfs_filehandle nfh
;
279 kauth_action_t testaction
;
280 struct nfs_export
*nx
;
281 struct nfs_export_options
*nxo
;
286 nmreq
= &nd
->nd_nmreq
;
287 nfsm_chain_null(&nmrep
);
291 nfsm_chain_get_fh_ptr(error
, nmreq
, NFS_VER3
, nfh
.nfh_fhp
, nfh
.nfh_len
);
292 nfsm_chain_get_32(error
, nmreq
, nfsmode
);
294 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
297 /* update export stats */
298 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
300 /* update active user stats */
301 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
303 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
307 * Each NFS mode bit is tested separately.
309 * XXX this code is nominally correct, but returns a pessimistic
310 * rather than optimistic result. It will be necessary to add
311 * an NFS-specific interface to the vnode_authorize code to
312 * obtain good performance in the optimistic mode.
314 if (nfsmode
& NFS_ACCESS_READ
) {
315 if (vnode_isdir(vp
)) {
317 KAUTH_VNODE_LIST_DIRECTORY
|
318 KAUTH_VNODE_READ_EXTATTRIBUTES
;
321 KAUTH_VNODE_READ_DATA
|
322 KAUTH_VNODE_READ_EXTATTRIBUTES
;
324 if (nfsrv_authorize(vp
, NULL
, testaction
, ctx
, nxo
, 0))
325 nfsmode
&= ~NFS_ACCESS_READ
;
327 if ((nfsmode
& NFS_ACCESS_LOOKUP
) &&
329 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
, nxo
, 0)))
330 nfsmode
&= ~NFS_ACCESS_LOOKUP
;
331 if (nfsmode
& NFS_ACCESS_MODIFY
) {
332 if (vnode_isdir(vp
)) {
334 KAUTH_VNODE_ADD_FILE
|
335 KAUTH_VNODE_ADD_SUBDIRECTORY
|
336 KAUTH_VNODE_DELETE_CHILD
;
339 KAUTH_VNODE_WRITE_DATA
;
341 if (nfsrv_authorize(vp
, NULL
, testaction
, ctx
, nxo
, 0))
342 nfsmode
&= ~NFS_ACCESS_MODIFY
;
344 if (nfsmode
& NFS_ACCESS_EXTEND
) {
345 if (vnode_isdir(vp
)) {
347 KAUTH_VNODE_ADD_FILE
|
348 KAUTH_VNODE_ADD_SUBDIRECTORY
;
351 KAUTH_VNODE_WRITE_DATA
|
352 KAUTH_VNODE_APPEND_DATA
;
354 if (nfsrv_authorize(vp
, NULL
, testaction
, ctx
, nxo
, 0))
355 nfsmode
&= ~NFS_ACCESS_EXTEND
;
359 * Note concerning NFS_ACCESS_DELETE:
360 * For hard links, the answer may be wrong if the vnode
361 * has multiple parents with different permissions.
362 * Also, some clients (e.g. MacOSX 10.3) may incorrectly
363 * interpret the missing/cleared DELETE bit.
364 * So we'll just leave the DELETE bit alone. At worst,
365 * we're telling the client it might be able to do
366 * something it really can't.
369 if ((nfsmode
& NFS_ACCESS_EXECUTE
) &&
371 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, ctx
, nxo
, 0)))
372 nfsmode
&= ~NFS_ACCESS_EXECUTE
;
374 /* get postop attributes */
375 nfsm_srv_vattr_init(&vattr
, NFS_VER3
);
376 attrerr
= vnode_getattr(vp
, &vattr
, ctx
);
380 nd
->nd_repstat
= error
;
381 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(NFS_VER3
) + NFSX_UNSIGNED
);
383 *mrepp
= nmrep
.nmc_mhead
;
384 nfsmout_on_status(nd
, error
);
385 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &vattr
);
387 nfsm_chain_add_32(error
, &nmrep
, nfsmode
);
389 nfsm_chain_build_done(error
, &nmrep
);
393 nfsm_chain_cleanup(&nmrep
);
400 * nfs getattr service
404 struct nfsrv_descript
*nd
,
405 struct nfsrv_sock
*slp
,
409 struct nfsm_chain
*nmreq
, nmrep
;
410 struct vnode_attr vattr
;
413 struct nfs_filehandle nfh
;
414 struct nfs_export
*nx
;
415 struct nfs_export_options
*nxo
;
418 nmreq
= &nd
->nd_nmreq
;
419 nfsm_chain_null(&nmrep
);
423 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
425 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
428 /* update export stats */
429 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
431 /* update active user stats */
432 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
434 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
437 nfsm_srv_vattr_init(&vattr
, nd
->nd_vers
);
438 error
= vnode_getattr(vp
, &vattr
, ctx
);
444 nd
->nd_repstat
= error
;
445 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_FATTR(nd
->nd_vers
));
447 *mrepp
= nmrep
.nmc_mhead
;
448 nfsmout_if(nd
->nd_repstat
);
449 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &vattr
);
451 nfsm_chain_build_done(error
, &nmrep
);
455 nfsm_chain_cleanup(&nmrep
);
462 * nfs setattr service
466 struct nfsrv_descript
*nd
,
467 struct nfsrv_sock
*slp
,
471 struct nfsm_chain
*nmreq
, nmrep
;
472 struct vnode_attr preattr
, postattr
;
473 struct vnode_attr vattr
, *vap
= &vattr
;
475 struct nfs_export
*nx
;
476 struct nfs_export_options
*nxo
;
477 int error
, preattrerr
, postattrerr
, gcheck
;
478 struct nfs_filehandle nfh
;
479 struct timespec guard
= { 0, 0 };
480 kauth_action_t action
;
484 preattrerr
= postattrerr
= ENOENT
;
486 nmreq
= &nd
->nd_nmreq
;
487 nfsm_chain_null(&nmrep
);
491 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
495 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
496 if (nd
->nd_vers
== NFS_VER3
) {
497 nfsm_chain_get_32(error
, nmreq
, gcheck
);
499 nfsm_chain_get_time(error
, nmreq
, nd
->nd_vers
, guard
.tv_sec
, guard
.tv_nsec
);
504 * Save the original credential UID in case they are
505 * mapped and we need to map the IDs in the attributes.
507 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
510 * Now that we have all the fields, lets do it.
512 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
515 /* update export stats */
516 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
518 /* update active user stats */
519 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
521 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
524 if (nd
->nd_vers
== NFS_VER3
) {
525 nfsm_srv_pre_vattr_init(&preattr
);
526 error
= preattrerr
= vnode_getattr(vp
, &preattr
, ctx
);
527 if (!error
&& gcheck
&& VATTR_IS_SUPPORTED(&preattr
, va_change_time
) &&
528 (preattr
.va_change_time
.tv_sec
!= guard
.tv_sec
||
529 preattr
.va_change_time
.tv_nsec
!= guard
.tv_nsec
))
530 error
= NFSERR_NOT_SYNC
;
531 if (!preattrerr
&& !VATTR_ALL_SUPPORTED(&preattr
))
537 * If the credentials were mapped, we should
538 * map the same values in the attributes.
540 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nd
->nd_cr
) != saved_uid
)) {
542 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nd
->nd_cr
));
543 if (kauth_cred_ismember_gid(nd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
544 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nd
->nd_cr
));
547 /* Authorize the attribute changes. */
548 error
= vnode_authattr(vp
, vap
, &action
, ctx
);
550 error
= nfsrv_authorize(vp
, NULL
, action
, ctx
, nxo
, 0);
552 /* set the new attributes */
554 error
= vnode_setattr(vp
, vap
, ctx
);
556 if (!error
|| (nd
->nd_vers
== NFS_VER3
)) {
557 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
558 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
568 nd
->nd_repstat
= error
;
569 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCORFATTR(nd
->nd_vers
));
571 *mrepp
= nmrep
.nmc_mhead
;
572 nfsmout_on_status(nd
, error
);
573 if (nd
->nd_vers
== NFS_VER3
)
574 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
575 preattrerr
, &preattr
, postattrerr
, &postattr
);
577 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
579 nfsm_chain_build_done(error
, &nmrep
);
581 nfsm_chain_cleanup(&nmrep
);
592 struct nfsrv_descript
*nd
,
593 struct nfsrv_sock
*slp
,
598 vnode_t vp
, dirp
= NULL
;
599 struct nfs_filehandle dnfh
, nfh
;
600 struct nfs_export
*nx
= NULL
;
601 struct nfs_export_options
*nxo
;
602 int error
, attrerr
, dirattrerr
, isdotdot
;
605 struct vnode_attr va
, dirattr
, *vap
= &va
;
606 struct nfsm_chain
*nmreq
, nmrep
;
609 attrerr
= dirattrerr
= ENOENT
;
610 nmreq
= &nd
->nd_nmreq
;
611 nfsm_chain_null(&nmrep
);
612 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
614 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, dnfh
.nfh_fhp
, dnfh
.nfh_len
);
615 nfsm_chain_get_32(error
, nmreq
, len
);
616 nfsm_name_len_check(error
, nd
, len
);
619 ni
.ni_cnd
.cn_nameiop
= LOOKUP
;
620 ni
.ni_cnd
.cn_flags
= LOCKLEAF
;
621 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
622 isdotdot
= ((len
== 2) && (ni
.ni_cnd
.cn_pnbuf
[0] == '.') && (ni
.ni_cnd
.cn_pnbuf
[1] == '.'));
624 error
= nfsrv_namei(nd
, ctx
, &ni
, &dnfh
, &dirp
, &nx
, &nxo
);
626 /* update export stats */
627 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
629 /* update active user stats */
630 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
635 if (nd
->nd_vers
== NFS_VER3
) {
636 nfsm_srv_vattr_init(&dirattr
, NFS_VER3
);
637 dirattrerr
= vnode_getattr(dirp
, &dirattr
, ctx
);
646 error
= nfsrv_vptofh(nx
, nd
->nd_vers
, (isdotdot
? &dnfh
: NULL
), vp
, ctx
, &nfh
);
648 nfsm_srv_vattr_init(vap
, nd
->nd_vers
);
649 attrerr
= vnode_getattr(vp
, vap
, ctx
);
655 nd
->nd_repstat
= error
;
656 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(nd
->nd_vers
, &nfh
) +
657 NFSX_POSTOPORFATTR(nd
->nd_vers
) + NFSX_POSTOPATTR(nd
->nd_vers
));
659 *mrepp
= nmrep
.nmc_mhead
;
660 if (nd
->nd_repstat
) {
661 if (nd
->nd_vers
== NFS_VER3
)
662 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, dirattrerr
, &dirattr
);
665 nfsm_chain_add_fh(error
, &nmrep
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
666 if (nd
->nd_vers
== NFS_VER3
) {
667 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, vap
);
668 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, dirattrerr
, &dirattr
);
670 error
= nfsm_chain_add_fattr(nd
, &nmrep
, vap
);
673 nfsm_chain_build_done(error
, &nmrep
);
675 nfsm_chain_cleanup(&nmrep
);
682 * nfs readlink service
686 struct nfsrv_descript
*nd
,
687 struct nfsrv_sock
*slp
,
691 int error
, mpcnt
, tlen
, len
, attrerr
;
693 struct vnode_attr vattr
;
694 struct nfs_filehandle nfh
;
695 struct nfs_export
*nx
;
696 struct nfs_export_options
*nxo
;
697 struct nfsm_chain
*nmreq
, nmrep
;
700 char uio_buf
[ UIO_SIZEOF(4) ];
701 char *uio_bufp
= &uio_buf
[0];
702 int uio_buflen
= UIO_SIZEOF(4);
706 nmreq
= &nd
->nd_nmreq
;
707 nfsm_chain_null(&nmrep
);
710 len
= NFS_MAXPATHLEN
;
712 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
715 /* get mbuf list to hold symlink path */
716 error
= nfsm_mbuf_get_list(len
, &mpath
, &mpcnt
);
719 uio_buflen
= UIO_SIZEOF(mpcnt
);
720 MALLOC(uio_bufp
, char*, uio_buflen
, M_TEMP
, M_WAITOK
);
725 auio
= uio_createwithbuffer(mpcnt
, 0, UIO_SYSSPACE
, UIO_READ
, uio_bufp
, uio_buflen
);
730 for (mp
= mpath
; mp
; mp
= mbuf_next(mp
))
731 uio_addiov(auio
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), mbuf_len(mp
));
733 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
736 /* update export stats */
737 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
739 /* update active user stats */
740 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
742 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
745 if (vnode_vtype(vp
) != VLNK
) {
746 if (nd
->nd_vers
== NFS_VER3
)
753 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, ctx
, nxo
, 0);
755 error
= VNOP_READLINK(vp
, auio
, ctx
);
757 if (nd
->nd_vers
== NFS_VER3
) {
758 nfsm_srv_vattr_init(&vattr
, NFS_VER3
);
759 attrerr
= vnode_getattr(vp
, &vattr
, ctx
);
771 nd
->nd_repstat
= error
;
772 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_UNSIGNED
);
774 *mrepp
= nmrep
.nmc_mhead
;
775 nfsmout_on_status(nd
, error
);
776 if (nd
->nd_vers
== NFS_VER3
)
777 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &vattr
);
778 if (error
|| nd
->nd_repstat
) {
779 nfsm_chain_build_done(error
, &nmrep
);
782 if (auio
&& (uio_resid(auio
) > 0)) {
783 len
-= uio_resid(auio
);
784 tlen
= nfsm_rndup(len
);
785 nfsm_adj(mpath
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
787 nfsm_chain_add_32(error
, &nmrep
, len
);
788 nfsm_chain_build_done(error
, &nmrep
);
790 error
= mbuf_setnext(nmrep
.nmc_mcur
, mpath
);
798 if (uio_bufp
!= &uio_buf
[0])
799 FREE(uio_bufp
, M_TEMP
);
801 nfsm_chain_cleanup(&nmrep
);
812 struct nfsrv_descript
*nd
,
813 struct nfsrv_sock
*slp
,
817 int error
, attrerr
, mreadcnt
;
818 uint32_t reqlen
, maxlen
, count
, len
, tlen
, left
;
821 struct nfs_filehandle nfh
;
822 struct nfs_export
*nx
;
823 struct nfs_export_options
*nxo
;
825 char *uio_bufp
= NULL
;
826 struct vnode_attr vattr
, *vap
= &vattr
;
829 char uio_buf
[ UIO_SIZEOF(0) ];
830 struct nfsm_chain
*nmreq
, nmrep
;
834 nmreq
= &nd
->nd_nmreq
;
835 nfsm_chain_null(&nmrep
);
839 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
841 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
843 if (nd
->nd_vers
== NFS_VER3
)
844 nfsm_chain_get_64(error
, nmreq
, off
);
846 nfsm_chain_get_32(error
, nmreq
, off
);
847 nfsm_chain_get_32(error
, nmreq
, reqlen
);
848 maxlen
= NFSRV_NDMAXDATA(nd
);
852 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
855 /* update export stats */
856 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
858 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
861 if (vnode_vtype(vp
) != VREG
) {
862 if (nd
->nd_vers
== NFS_VER3
)
865 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
869 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, ctx
, nxo
, 1)))
870 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, ctx
, nxo
, 1);
872 nfsm_srv_vattr_init(vap
, nd
->nd_vers
);
873 attrerr
= vnode_getattr(vp
, vap
, ctx
);
878 if ((u_quad_t
)off
>= vap
->va_data_size
)
880 else if (((u_quad_t
)off
+ reqlen
) > vap
->va_data_size
)
881 count
= nfsm_rndup(vap
->va_data_size
- off
);
887 /* get mbuf list to hold read data */
888 error
= nfsm_mbuf_get_list(count
, &mread
, &mreadcnt
);
890 MALLOC(uio_bufp
, char *, UIO_SIZEOF(mreadcnt
), M_TEMP
, M_WAITOK
);
892 auio
= uio_createwithbuffer(mreadcnt
, off
, UIO_SYSSPACE
,
893 UIO_READ
, uio_bufp
, UIO_SIZEOF(mreadcnt
));
894 if (!uio_bufp
|| !auio
) {
898 for (m
= mread
; m
; m
= mbuf_next(m
))
899 uio_addiov(auio
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(m
)), mbuf_len(m
));
900 error
= VNOP_READ(vp
, auio
, IO_NODELOCKED
, ctx
);
902 auio
= uio_createwithbuffer(0, 0, UIO_SYSSPACE
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
910 if (!error
|| (nd
->nd_vers
== NFS_VER3
)) {
911 nfsm_srv_vattr_init(vap
, nd
->nd_vers
);
912 attrerr
= vnode_getattr(vp
, vap
, ctx
);
913 if (!error
&& (nd
->nd_vers
== NFS_VER2
))
914 error
= attrerr
; /* NFSv2 must have attributes to return */
921 /* trim off any data not actually read */
922 len
-= uio_resid(auio
);
923 tlen
= nfsm_rndup(len
);
924 if (count
!= tlen
|| tlen
!= len
)
925 nfsm_adj(mread
, count
- tlen
, tlen
- len
);
929 nd
->nd_repstat
= error
;
930 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPORFATTR(nd
->nd_vers
) + 3 * NFSX_UNSIGNED
);
932 *mrepp
= nmrep
.nmc_mhead
;
933 nfsmout_on_status(nd
, error
);
934 if (nd
->nd_vers
== NFS_VER3
)
935 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, vap
);
936 if (error
|| nd
->nd_repstat
) {
937 nfsm_chain_build_done(error
, &nmrep
);
940 if (nd
->nd_vers
== NFS_VER3
) {
941 nfsm_chain_add_32(error
, &nmrep
, len
);
942 nfsm_chain_add_32(error
, &nmrep
, (len
< reqlen
) ? TRUE
: FALSE
);
944 error
= nfsm_chain_add_fattr(nd
, &nmrep
, vap
);
946 nfsm_chain_add_32(error
, &nmrep
, len
);
947 nfsm_chain_build_done(error
, &nmrep
);
949 error
= mbuf_setnext(nmrep
.nmc_mcur
, mread
);
953 /* update export stats */
954 NFSStatAdd64(&nx
->nx_stats
.bytes_read
, len
);
956 /* update active user stats */
957 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, len
, 0);
963 if (uio_bufp
!= NULL
)
964 FREE(uio_bufp
, M_TEMP
);
966 nfsm_chain_cleanup(&nmrep
);
974 * NFS File modification reporting
976 * When the contents of a file are changed, a "content modified"
977 * fsevent needs to be issued. Normally this would be done at
978 * file close time. This is difficult for NFS because the protocol
979 * has no "close" operation. The client sends a stream of write
980 * requests that just stop. So we keep a hash table full of
981 * vnodes that have been written to recently, and issue a
982 * "content modified" fsevent only if there are no writes to
983 * a vnode for nfsrv_fmod_pendtime milliseconds.
985 int nfsrv_fmod_pending
; /* count of vnodes being written to */
986 int nfsrv_fmod_pendtime
= 1000; /* msec to wait */
987 int nfsrv_fmod_min_interval
= 100; /* msec min interval between callbacks */
990 * This function is called via the kernel's callout
991 * mechanism. Calls are made only when there are
992 * vnodes pending a fsevent creation, and no more
993 * frequently than every nfsrv_fmod_min_interval ms.
996 nfsrv_fmod_timer(__unused
void *param0
, __unused
void *param1
)
998 struct nfsrv_fmod_hashhead
*headp
, firehead
;
999 struct nfsrv_fmod
*fp
, *nfp
, *pfp
;
1000 uint64_t timenow
, next_deadline
;
1001 int interval
= 0, i
, fmod_fire
;
1003 LIST_INIT(&firehead
);
1004 lck_mtx_lock(nfsrv_fmod_mutex
);
1006 clock_get_uptime(&timenow
);
1007 clock_interval_to_deadline(nfsrv_fmod_pendtime
, 1000 * 1000,
1011 * Scan all the hash chains
1014 for (i
= 0; i
< NFSRVFMODHASHSZ
; i
++) {
1016 * For each hash chain, look for an entry
1017 * that has exceeded the deadline.
1019 headp
= &nfsrv_fmod_hashtbl
[i
];
1020 LIST_FOREACH(fp
, headp
, fm_link
) {
1021 if (timenow
>= fp
->fm_deadline
)
1023 if (fp
->fm_deadline
< next_deadline
)
1024 next_deadline
= fp
->fm_deadline
;
1028 * If we have an entry that's exceeded the
1029 * deadline, then the same is true for all
1030 * following entries in the chain, since they're
1031 * sorted in time order.
1035 /* move each entry to the fire list */
1036 nfp
= LIST_NEXT(fp
, fm_link
);
1037 LIST_REMOVE(fp
, fm_link
);
1040 LIST_INSERT_AFTER(pfp
, fp
, fm_link
);
1042 LIST_INSERT_HEAD(&firehead
, fp
, fm_link
);
1049 lck_mtx_unlock(nfsrv_fmod_mutex
);
1051 * Fire off the content modified fsevent for each
1052 * entry and free it.
1054 LIST_FOREACH_SAFE(fp
, &firehead
, fm_link
, nfp
) {
1055 if (nfsrv_fsevents_enabled
)
1056 add_fsevent(FSE_CONTENT_MODIFIED
, &fp
->fm_context
,
1057 FSE_ARG_VNODE
, fp
->fm_vp
,
1059 vnode_put(fp
->fm_vp
);
1060 kauth_cred_unref(&fp
->fm_context
.vc_ucred
);
1061 LIST_REMOVE(fp
, fm_link
);
1064 lck_mtx_lock(nfsrv_fmod_mutex
);
1065 nfsrv_fmod_pending
-= fmod_fire
;
1070 * If there are still pending entries, set up another
1071 * callout to handle them later. Set the timeout deadline
1072 * so that the callout happens when the oldest pending
1073 * entry is ready to send its fsevent.
1075 if (nfsrv_fmod_pending
> 0) {
1076 interval
= (next_deadline
- timenow
) / (1000 * 1000);
1077 if (interval
< nfsrv_fmod_min_interval
)
1078 interval
= nfsrv_fmod_min_interval
;
1081 nfsrv_fmod_timer_on
= interval
> 0;
1082 if (nfsrv_fmod_timer_on
)
1083 nfs_interval_timer_start(nfsrv_fmod_timer_call
, interval
);
1085 lck_mtx_unlock(nfsrv_fmod_mutex
);
1089 * When a vnode has been written to, enter it in the hash
1090 * table of vnodes pending creation of an fsevent. If the
1091 * callout timer isn't already running, schedule a callback
1092 * for nfsrv_fmod_pendtime msec from now.
1095 nfsrv_modified(vnode_t vp
, vfs_context_t ctx
)
1098 struct nfsrv_fmod
*fp
;
1099 struct nfsrv_fmod_hashhead
*head
;
1101 lck_mtx_lock(nfsrv_fmod_mutex
);
1104 * Compute the time in the future when the
1105 * content modified fsevent is to be issued.
1107 clock_interval_to_deadline(nfsrv_fmod_pendtime
, 1000 * 1000, &deadline
);
1110 * Check if there's already a file content change fsevent
1111 * pending for this vnode. If there is, update its
1112 * timestamp and make sure it's at the front of the hash chain.
1114 head
= &nfsrv_fmod_hashtbl
[NFSRVFMODHASH(vp
)];
1115 LIST_FOREACH(fp
, head
, fm_link
) {
1116 if (vp
== fp
->fm_vp
) {
1117 fp
->fm_deadline
= deadline
;
1118 if (fp
!= LIST_FIRST(head
)) {
1119 LIST_REMOVE(fp
, fm_link
);
1120 LIST_INSERT_HEAD(head
, fp
, fm_link
);
1122 lck_mtx_unlock(nfsrv_fmod_mutex
);
1128 * First content change fsevent for this vnode.
1129 * Allocate a new file mod entry and add it
1130 * on the front of the hash chain.
1132 if (vnode_get(vp
) != 0)
1134 MALLOC(fp
, struct nfsrv_fmod
*, sizeof(*fp
), M_TEMP
, M_WAITOK
);
1140 kauth_cred_ref(vfs_context_ucred(ctx
));
1141 fp
->fm_context
= *ctx
;
1142 fp
->fm_deadline
= deadline
;
1143 LIST_INSERT_HEAD(head
, fp
, fm_link
);
1146 * If added to an empty hash table, then set the
1147 * callout timer to go off after nfsrv_fmod_pendtime.
1149 nfsrv_fmod_pending
++;
1150 if (!nfsrv_fmod_timer_on
) {
1151 nfsrv_fmod_timer_on
= 1;
1152 nfs_interval_timer_start(nfsrv_fmod_timer_call
,
1153 nfsrv_fmod_pendtime
);
1156 lck_mtx_unlock(nfsrv_fmod_mutex
);
1159 #endif /* CONFIG_FSE */
1166 struct nfsrv_descript
*nd
,
1167 struct nfsrv_sock
*slp
,
1171 struct vnode_attr preattr
, postattr
;
1172 int error
, preattrerr
, postattrerr
;
1173 int ioflags
, len
, retlen
;
1175 int stable
= NFS_WRITE_FILESYNC
;
1178 struct nfs_filehandle nfh
;
1179 struct nfs_export
*nx
;
1180 struct nfs_export_options
*nxo
;
1182 char *uio_bufp
= NULL
;
1185 struct nfsm_chain
*nmreq
, nmrep
;
1187 if (nd
->nd_nmreq
.nmc_mhead
== NULL
) {
1193 preattrerr
= postattrerr
= ENOENT
;
1194 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
1195 nmreq
= &nd
->nd_nmreq
;
1196 nfsm_chain_null(&nmrep
);
1200 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
1202 if (nd
->nd_vers
== NFS_VER3
) {
1203 nfsm_chain_get_64(error
, nmreq
, off
);
1204 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1205 nfsm_chain_get_32(error
, nmreq
, stable
);
1207 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1208 nfsm_chain_get_32(error
, nmreq
, off
);
1209 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1211 stable
= NFS_WRITE_UNSTABLE
;
1213 nfsm_chain_get_32(error
, nmreq
, len
);
1218 * For NFS Version 2, it is not obvious what a write of zero length
1219 * should do, but I might as well be consistent with Version 3,
1220 * which is to return ok so long as there are no permission problems.
1224 error
= nfsm_chain_trim_data(nmreq
, len
, &mlen
);
1229 if ((len
> NFSRV_MAXDATA
) || (len
< 0) || (mlen
< len
)) {
1233 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
1236 /* update export stats */
1237 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
1239 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
1242 if (nd
->nd_vers
== NFS_VER3
) {
1243 nfsm_srv_pre_vattr_init(&preattr
);
1244 preattrerr
= vnode_getattr(vp
, &preattr
, ctx
);
1246 if (vnode_vtype(vp
) != VREG
) {
1247 if (nd
->nd_vers
== NFS_VER3
)
1250 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1253 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, ctx
, nxo
, 1);
1257 for (mcount
=0, m
=nmreq
->nmc_mcur
; m
; m
= mbuf_next(m
))
1258 if (mbuf_len(m
) > 0)
1260 MALLOC(uio_bufp
, char *, UIO_SIZEOF(mcount
), M_TEMP
, M_WAITOK
);
1262 auio
= uio_createwithbuffer(mcount
, off
, UIO_SYSSPACE
, UIO_WRITE
, uio_bufp
, UIO_SIZEOF(mcount
));
1263 if (!uio_bufp
|| !auio
)
1266 for (m
= nmreq
->nmc_mcur
; m
; m
= mbuf_next(m
))
1267 if ((mlen
= mbuf_len(m
)) > 0)
1268 uio_addiov(auio
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(m
)), mlen
);
1270 * XXX The IO_METASYNC flag indicates that all metadata (and not just
1271 * enough to ensure data integrity) mus be written to stable storage
1272 * synchronously. (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1274 if (stable
== NFS_WRITE_UNSTABLE
)
1275 ioflags
= IO_NODELOCKED
;
1276 else if (stable
== NFS_WRITE_DATASYNC
)
1277 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1279 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1281 error
= VNOP_WRITE(vp
, auio
, ioflags
, ctx
);
1282 OSAddAtomic(1, &nfsstats
.srvvop_writes
);
1284 /* update export stats */
1285 NFSStatAdd64(&nx
->nx_stats
.bytes_written
, len
);
1287 /* update active user stats */
1288 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, len
);
1291 if (nfsrv_fsevents_enabled
&& !error
&& need_fsevent(FSE_CONTENT_MODIFIED
, vp
))
1292 nfsrv_modified(vp
, ctx
);
1295 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
1296 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
1297 if (!error
&& (nd
->nd_vers
== NFS_VER2
))
1298 error
= postattrerr
; /* NFSv2 must have attributes to return */
1303 /* assemble reply */
1304 nd
->nd_repstat
= error
;
1305 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_PREOPATTR(nd
->nd_vers
) +
1306 NFSX_POSTOPORFATTR(nd
->nd_vers
) + 2 * NFSX_UNSIGNED
+
1307 NFSX_WRITEVERF(nd
->nd_vers
));
1309 *mrepp
= nmrep
.nmc_mhead
;
1310 nfsmout_on_status(nd
, error
);
1311 if (nd
->nd_vers
== NFS_VER3
) {
1312 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
1313 preattrerr
, &preattr
, postattrerr
, &postattr
);
1314 nfsmout_if(error
|| nd
->nd_repstat
);
1315 nfsm_chain_add_32(error
, &nmrep
, retlen
);
1316 /* If nfsrv_async is set, then pretend the write was FILESYNC. */
1317 if ((stable
== NFS_WRITE_UNSTABLE
) && !nfsrv_async
)
1318 nfsm_chain_add_32(error
, &nmrep
, stable
);
1320 nfsm_chain_add_32(error
, &nmrep
, NFS_WRITE_FILESYNC
);
1321 /* write verifier */
1322 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_sec
);
1323 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_usec
);
1325 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
1328 nfsm_chain_build_done(error
, &nmrep
);
1331 if (uio_bufp
!= NULL
)
1332 FREE(uio_bufp
, M_TEMP
);
1334 nfsm_chain_cleanup(&nmrep
);
1341 * NFS write service with write gathering support. Called when
1342 * nfsrv_wg_delay > 0.
1343 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1344 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1348 #define NWDELAYHASH(sock, f) \
1349 (&(sock)->ns_wdelayhashtbl[(*((u_int32_t *)(f))) % NFS_WDELAYHASHSIZ])
1350 /* These macros compare nfsrv_descript structures. */
1351 #define NFSW_CONTIG(o, n) \
1352 (((o)->nd_eoff >= (n)->nd_off) && nfsrv_fhmatch(&(o)->nd_fh, &(n)->nd_fh))
1354 * XXX The following is an incorrect comparison; it fails to take into account
1355 * XXX scoping of MAC labels, but we currently lack KPI for credential
1358 #define NFSW_SAMECRED(o, n) \
1359 (!bcmp((caddr_t)(o)->nd_cr, (caddr_t)(n)->nd_cr, \
1360 sizeof (struct ucred)))
1364 struct nfsrv_descript
**ndp
,
1365 struct nfsrv_sock
*slp
,
1369 struct nfsrv_descript
*nd
, *wp
, *owp
, *swp
;
1370 struct nfs_export
*nx
;
1371 struct nfs_export_options
*nxo
;
1372 struct nfsrv_wg_delayhash
*wpp
;
1374 struct vnode_attr preattr
, postattr
;
1375 int error
, mlen
, i
, ioflags
, tlen
;
1376 int preattrerr
, postattrerr
;
1380 char *uio_bufp
= NULL
;
1383 struct nfsm_chain
*nmreq
, nmrep
;
1386 preattrerr
= postattrerr
= ENOENT
;
1387 nfsm_chain_null(&nmrep
);
1394 nmreq
= &nd
->nd_nmreq
;
1395 LIST_INIT(&nd
->nd_coalesce
);
1397 nd
->nd_stable
= NFS_WRITE_FILESYNC
;
1399 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1400 nd
->nd_time
= cur_usec
+
1401 ((nd
->nd_vers
== NFS_VER3
) ? nfsrv_wg_delay_v3
: nfsrv_wg_delay
);
1403 /* Now, get the write header... */
1404 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nd
->nd_fh
.nfh_fhp
, nd
->nd_fh
.nfh_len
);
1405 /* XXX shouldn't we be checking for invalid FHs before doing any more work? */
1407 if (nd
->nd_vers
== NFS_VER3
) {
1408 nfsm_chain_get_64(error
, nmreq
, nd
->nd_off
);
1409 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1410 nfsm_chain_get_32(error
, nmreq
, nd
->nd_stable
);
1412 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1413 nfsm_chain_get_32(error
, nmreq
, nd
->nd_off
);
1414 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1416 nd
->nd_stable
= NFS_WRITE_UNSTABLE
;
1418 nfsm_chain_get_32(error
, nmreq
, nd
->nd_len
);
1420 nd
->nd_eoff
= nd
->nd_off
+ nd
->nd_len
;
1422 if (nd
->nd_len
> 0) {
1423 error
= nfsm_chain_trim_data(nmreq
, nd
->nd_len
, &mlen
);
1429 if ((nd
->nd_len
> NFSRV_MAXDATA
) || (nd
->nd_len
< 0) || (mlen
< nd
->nd_len
)) {
1432 nd
->nd_repstat
= error
;
1433 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCDATA(nd
->nd_vers
));
1435 nd
->nd_mrep
= nmrep
.nmc_mhead
;
1436 if (nd
->nd_vers
== NFS_VER3
)
1437 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
1438 preattrerr
, &preattr
, postattrerr
, &postattr
);
1440 nfsm_chain_build_done(error
, &nmrep
);
1445 * Add this entry to the hash and time queues.
1447 lck_mtx_lock(&slp
->ns_wgmutex
);
1449 wp
= slp
->ns_tq
.lh_first
;
1450 while (wp
&& wp
->nd_time
< nd
->nd_time
) {
1452 wp
= wp
->nd_tq
.le_next
;
1455 LIST_INSERT_AFTER(owp
, nd
, nd_tq
);
1457 LIST_INSERT_HEAD(&slp
->ns_tq
, nd
, nd_tq
);
1460 wpp
= NWDELAYHASH(slp
, nd
->nd_fh
.nfh_fid
);
1463 while (wp
&& !nfsrv_fhmatch(&nd
->nd_fh
, &wp
->nd_fh
)) {
1465 wp
= wp
->nd_hash
.le_next
;
1467 while (wp
&& (wp
->nd_off
< nd
->nd_off
) &&
1468 nfsrv_fhmatch(&nd
->nd_fh
, &wp
->nd_fh
)) {
1470 wp
= wp
->nd_hash
.le_next
;
1473 LIST_INSERT_AFTER(owp
, nd
, nd_hash
);
1475 * Search the hash list for overlapping entries and
1478 for(; nd
&& NFSW_CONTIG(owp
, nd
); nd
= wp
) {
1479 wp
= nd
->nd_hash
.le_next
;
1480 if (NFSW_SAMECRED(owp
, nd
))
1481 nfsrv_wg_coalesce(owp
, nd
);
1484 LIST_INSERT_HEAD(wpp
, nd
, nd_hash
);
1488 lck_mtx_lock(&slp
->ns_wgmutex
);
1492 * Now, do VNOP_WRITE()s for any one(s) that need to be done now
1493 * and generate the associated reply mbuf list(s).
1497 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1498 for (nd
= slp
->ns_tq
.lh_first
; nd
; nd
= owp
) {
1499 owp
= nd
->nd_tq
.le_next
;
1500 if (nd
->nd_time
> cur_usec
)
1504 LIST_REMOVE(nd
, nd_tq
);
1505 LIST_REMOVE(nd
, nd_hash
);
1506 nmreq
= &nd
->nd_nmreq
;
1507 preattrerr
= postattrerr
= ENOENT
;
1509 /* save the incoming uid before mapping, */
1510 /* for updating active user stats later */
1511 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
1513 error
= nfsrv_fhtovp(&nd
->nd_fh
, nd
, &vp
, &nx
, &nxo
);
1515 /* update per-export stats */
1516 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
1518 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
1523 if (nd
->nd_vers
== NFS_VER3
) {
1524 nfsm_srv_pre_vattr_init(&preattr
);
1525 preattrerr
= vnode_getattr(vp
, &preattr
, ctx
);
1527 if (vnode_vtype(vp
) != VREG
) {
1528 if (nd
->nd_vers
== NFS_VER3
)
1531 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1536 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, ctx
, nxo
, 1);
1538 if (nd
->nd_stable
== NFS_WRITE_UNSTABLE
)
1539 ioflags
= IO_NODELOCKED
;
1540 else if (nd
->nd_stable
== NFS_WRITE_DATASYNC
)
1541 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1543 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1545 if (!error
&& ((nd
->nd_eoff
- nd
->nd_off
) > 0)) {
1546 for (i
=0, m
=nmreq
->nmc_mhead
; m
; m
= mbuf_next(m
))
1547 if (mbuf_len(m
) > 0)
1550 MALLOC(uio_bufp
, char *, UIO_SIZEOF(i
), M_TEMP
, M_WAITOK
);
1552 auio
= uio_createwithbuffer(i
, nd
->nd_off
, UIO_SYSSPACE
,
1553 UIO_WRITE
, uio_bufp
, UIO_SIZEOF(i
));
1554 if (!uio_bufp
|| !auio
)
1557 for (m
= nmreq
->nmc_mhead
; m
; m
= mbuf_next(m
))
1558 if ((tlen
= mbuf_len(m
)) > 0)
1559 uio_addiov(auio
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(m
)), tlen
);
1560 error
= VNOP_WRITE(vp
, auio
, ioflags
, ctx
);
1561 OSAddAtomic(1, &nfsstats
.srvvop_writes
);
1563 /* update export stats */
1564 NFSStatAdd64(&nx
->nx_stats
.bytes_written
, nd
->nd_len
);
1565 /* update active user stats */
1566 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, nd
->nd_len
);
1569 if (nfsrv_fsevents_enabled
&& !error
&& need_fsevent(FSE_CONTENT_MODIFIED
, vp
))
1570 nfsrv_modified(vp
, ctx
);
1574 FREE(uio_bufp
, M_TEMP
);
1579 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
1580 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
1585 * Loop around generating replies for all write rpcs that have
1586 * now been completed.
1591 nd
->nd_repstat
= error
;
1592 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCDATA(nd
->nd_vers
));
1593 if (!error
&& (nd
->nd_vers
== NFS_VER3
)) {
1594 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
1595 preattrerr
, &preattr
, postattrerr
, &postattr
);
1598 nd
->nd_repstat
= error
;
1599 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_PREOPATTR(nd
->nd_vers
) +
1600 NFSX_POSTOPORFATTR(nd
->nd_vers
) + 2 * NFSX_UNSIGNED
+
1601 NFSX_WRITEVERF(nd
->nd_vers
));
1602 if (!error
&& (nd
->nd_vers
== NFS_VER3
)) {
1603 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
1604 preattrerr
, &preattr
, postattrerr
, &postattr
);
1605 nfsm_chain_add_32(error
, &nmrep
, nd
->nd_len
);
1606 nfsm_chain_add_32(error
, &nmrep
, nd
->nd_stable
);
1607 /* write verifier */
1608 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_sec
);
1609 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_usec
);
1610 } else if (!error
) {
1611 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
1614 nfsm_chain_build_done(error
, &nmrep
);
1616 nd
->nd_mrep
= nmrep
.nmc_mhead
;
1619 * Done. Put it at the head of the timer queue so that
1620 * the final phase can return the reply.
1624 LIST_INSERT_HEAD(&slp
->ns_tq
, nd
, nd_tq
);
1626 nd
= swp
->nd_coalesce
.lh_first
;
1628 LIST_REMOVE(nd
, nd_tq
);
1632 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1637 * Search for a reply to return.
1639 for (nd
= slp
->ns_tq
.lh_first
; nd
; nd
= nd
->nd_tq
.le_next
)
1641 LIST_REMOVE(nd
, nd_tq
);
1642 *mrepp
= nd
->nd_mrep
;
1646 slp
->ns_wgtime
= slp
->ns_tq
.lh_first
? slp
->ns_tq
.lh_first
->nd_time
: 0;
1647 lck_mtx_unlock(&slp
->ns_wgmutex
);
1650 * If we've just created a write pending gather,
1651 * start the timer to check on it soon to make sure
1652 * the write will be completed.
1654 * Add/Remove the socket in the nfsrv_sockwg queue as needed.
1656 lck_mtx_lock(nfsd_mutex
);
1657 if (slp
->ns_wgtime
) {
1658 if (slp
->ns_wgq
.tqe_next
== SLPNOLIST
) {
1659 TAILQ_INSERT_HEAD(&nfsrv_sockwg
, slp
, ns_wgq
);
1661 if (!nfsrv_wg_timer_on
) {
1662 nfsrv_wg_timer_on
= 1;
1663 nfs_interval_timer_start(nfsrv_wg_timer_call
,
1664 NFSRV_WGATHERDELAY
);
1666 } else if (slp
->ns_wgq
.tqe_next
!= SLPNOLIST
) {
1667 TAILQ_REMOVE(&nfsrv_sockwg
, slp
, ns_wgq
);
1668 slp
->ns_wgq
.tqe_next
= SLPNOLIST
;
1670 lck_mtx_unlock(nfsd_mutex
);
1676 * Coalesce the write request nd into owp. To do this we must:
1677 * - remove nd from the queues
1678 * - merge nd->nd_nmreq into owp->nd_nmreq
1679 * - update the nd_eoff and nd_stable for owp
1680 * - put nd on owp's nd_coalesce list
1683 nfsrv_wg_coalesce(struct nfsrv_descript
*owp
, struct nfsrv_descript
*nd
)
1687 struct nfsrv_descript
*p
;
1689 LIST_REMOVE(nd
, nd_hash
);
1690 LIST_REMOVE(nd
, nd_tq
);
1691 if (owp
->nd_eoff
< nd
->nd_eoff
) {
1692 overlap
= owp
->nd_eoff
- nd
->nd_off
;
1696 mbuf_adj(nd
->nd_nmreq
.nmc_mhead
, overlap
);
1697 mp
= owp
->nd_nmreq
.nmc_mhead
;
1698 while ((mpnext
= mbuf_next(mp
)))
1700 error
= mbuf_setnext(mp
, nd
->nd_nmreq
.nmc_mhead
);
1703 owp
->nd_eoff
= nd
->nd_eoff
;
1705 mbuf_freem(nd
->nd_nmreq
.nmc_mhead
);
1707 nd
->nd_nmreq
.nmc_mhead
= NULL
;
1708 nd
->nd_nmreq
.nmc_mcur
= NULL
;
1709 if (nd
->nd_stable
== NFS_WRITE_FILESYNC
)
1710 owp
->nd_stable
= NFS_WRITE_FILESYNC
;
1711 else if ((nd
->nd_stable
== NFS_WRITE_DATASYNC
) &&
1712 (owp
->nd_stable
== NFS_WRITE_UNSTABLE
))
1713 owp
->nd_stable
= NFS_WRITE_DATASYNC
;
1714 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nd
, nd_tq
);
1717 * If nd had anything else coalesced into it, transfer them
1718 * to owp, otherwise their replies will never get sent.
1720 while ((p
= nd
->nd_coalesce
.lh_first
)) {
1721 LIST_REMOVE(p
, nd_tq
);
1722 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1728 * Scan the write gathering queues for writes that need to be
1732 nfsrv_wg_timer(__unused
void *param0
, __unused
void *param1
)
1735 uint64_t cur_usec
, next_usec
;
1737 struct nfsrv_sock
*slp
;
1738 int writes_pending
= 0;
1741 cur_usec
= (uint64_t)now
.tv_sec
* 1000000 + (uint64_t)now
.tv_usec
;
1742 next_usec
= cur_usec
+ (NFSRV_WGATHERDELAY
* 1000);
1744 lck_mtx_lock(nfsd_mutex
);
1745 TAILQ_FOREACH(slp
, &nfsrv_sockwg
, ns_wgq
) {
1746 if (slp
->ns_wgtime
) {
1748 if (slp
->ns_wgtime
<= cur_usec
) {
1749 lck_rw_lock_exclusive(&slp
->ns_rwlock
);
1750 slp
->ns_flag
|= SLP_DOWRITES
;
1751 lck_rw_done(&slp
->ns_rwlock
);
1752 nfsrv_wakenfsd(slp
);
1755 if (slp
->ns_wgtime
< next_usec
)
1756 next_usec
= slp
->ns_wgtime
;
1760 if (writes_pending
== 0) {
1761 nfsrv_wg_timer_on
= 0;
1762 lck_mtx_unlock(nfsd_mutex
);
1765 lck_mtx_unlock(nfsd_mutex
);
1768 * Return the number of msec to wait again
1770 interval
= (next_usec
- cur_usec
) / 1000;
1773 nfs_interval_timer_start(nfsrv_wg_timer_call
, interval
);
1777 * Sort the group list in increasing numerical order.
1778 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1779 * that used to be here.)
1782 nfsrv_group_sort(gid_t
*list
, int num
)
1787 /* Insertion sort. */
1788 for (i
= 1; i
< num
; i
++) {
1790 /* find correct slot for value v, moving others up */
1791 for (j
= i
; --j
>= 0 && v
< list
[j
];)
1792 list
[j
+ 1] = list
[j
];
1798 * nfs create service
1799 * now does a truncate to 0 length via. setattr if it already exists
1803 struct nfsrv_descript
*nd
,
1804 struct nfsrv_sock
*slp
,
1808 struct vnode_attr dpreattr
, dpostattr
, postattr
;
1809 struct vnode_attr va
, *vap
= &va
;
1810 struct nameidata ni
;
1811 int error
, rdev
, dpreattrerr
, dpostattrerr
, postattrerr
;
1812 int how
, exclusive_flag
;
1813 uint32_t len
= 0, cnflags
;
1814 vnode_t vp
, dvp
, dirp
;
1815 struct nfs_filehandle nfh
;
1816 struct nfs_export
*nx
= NULL
;
1817 struct nfs_export_options
*nxo
;
1819 u_char cverf
[NFSX_V3CREATEVERF
];
1821 struct nfsm_chain
*nmreq
, nmrep
;
1824 dpreattrerr
= dpostattrerr
= postattrerr
= ENOENT
;
1825 nmreq
= &nd
->nd_nmreq
;
1826 nfsm_chain_null(&nmrep
);
1827 vp
= dvp
= dirp
= NULL
;
1829 ni
.ni_cnd
.cn_nameiop
= 0;
1833 * Save the original credential UID in case they are
1834 * mapped and we need to map the IDs in the attributes.
1836 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
1838 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
1839 nfsm_chain_get_32(error
, nmreq
, len
);
1840 nfsm_name_len_check(error
, nd
, len
);
1843 ni
.ni_cnd
.cn_nameiop
= CREATE
;
1844 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1845 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
1847 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
1849 /* update export stats */
1850 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
1852 /* update active user stats */
1853 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
1857 if (nd
->nd_vers
== NFS_VER3
) {
1858 nfsm_srv_pre_vattr_init(&dpreattr
);
1859 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
1867 ni
.ni_cnd
.cn_nameiop
= 0;
1875 if (nd
->nd_vers
== NFS_VER3
) {
1876 nfsm_chain_get_32(error
, nmreq
, how
);
1879 case NFS_CREATE_GUARDED
:
1884 case NFS_CREATE_UNCHECKED
:
1885 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
1887 case NFS_CREATE_EXCLUSIVE
:
1888 nfsm_chain_get_opaque(error
, nmreq
, NFSX_V3CREATEVERF
, cverf
);
1891 VATTR_SET(vap
, va_mode
, 0);
1894 VATTR_SET(vap
, va_type
, VREG
);
1898 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
1900 v_type
= vap
->va_type
;
1903 VATTR_SET(vap
, va_type
, v_type
);
1909 rdev
= vap
->va_data_size
;
1910 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
1919 * If it doesn't exist, create it
1920 * otherwise just truncate to 0 length
1921 * should I set the mode too ??
1924 kauth_acl_t xacl
= NULL
;
1927 * If the credentials were mapped, we should
1928 * map the same values in the attributes.
1930 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nd
->nd_cr
) != saved_uid
)) {
1932 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nd
->nd_cr
));
1933 if (kauth_cred_ismember_gid(nd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
1934 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nd
->nd_cr
));
1937 /* authorize before creating */
1938 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
, nxo
, 0);
1940 /* construct ACL and handle inheritance */
1942 error
= kauth_acl_inherit(dvp
,
1948 if (!error
&& xacl
!= NULL
)
1949 VATTR_SET(vap
, va_acl
, xacl
);
1951 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
1952 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
1954 /* validate new-file security information */
1956 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
1957 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
1959 * Most NFS servers just ignore the UID/GID attributes, so we
1960 * try ignoring them if that'll help the request succeed.
1962 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
1963 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
1964 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
1968 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1971 error
= VNOP_CREATE(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
);
1973 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
1975 * If some of the requested attributes weren't handled by the VNOP,
1976 * use our fallback code.
1978 error
= vnode_setattr_fallback(vp
, vap
, ctx
);
1981 kauth_acl_free(xacl
);
1984 if (exclusive_flag
) {
1987 bcopy(cverf
, (caddr_t
)&vap
->va_access_time
,
1989 VATTR_SET_ACTIVE(vap
, va_access_time
);
1990 // skip authorization, as this is an
1991 // NFS internal implementation detail.
1992 error
= vnode_setattr(vp
, vap
, ctx
);
1996 if (nfsrv_fsevents_enabled
&& need_fsevent(FSE_CREATE_FILE
, vp
)) {
1997 add_fsevent(FSE_CREATE_FILE
, ctx
,
2004 } else if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
||
2005 vap
->va_type
== VFIFO
) {
2006 if (vap
->va_type
== VCHR
&& rdev
== (int)0xffffffff)
2007 VATTR_SET(vap
, va_type
, VFIFO
);
2008 if (vap
->va_type
!= VFIFO
) {
2009 error
= suser(nd
->nd_cr
, NULL
);
2012 VATTR_SET(vap
, va_rdev
, (dev_t
)rdev
);
2014 error
= VNOP_MKNOD(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
);
2017 kauth_acl_free(xacl
);
2026 ni
.ni_cnd
.cn_nameiop
= LOOKUP
;
2027 ni
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
2028 ni
.ni_cnd
.cn_context
= ctx
;
2029 ni
.ni_startdir
= dvp
;
2031 cnflags
= ni
.ni_cnd
.cn_flags
; /* store in case we have to restore */
2032 while ((error
= lookup(&ni
)) == ERECYCLE
) {
2033 ni
.ni_cnd
.cn_flags
= cnflags
;
2034 ni
.ni_cnd
.cn_nameptr
= ni
.ni_cnd
.cn_pnbuf
;
2035 ni
.ni_usedvp
= ni
.ni_dvp
= ni
.ni_startdir
= dvp
;
2038 if (ni
.ni_cnd
.cn_flags
& ISSYMLINK
)
2047 * nameidone has to happen before we vnode_put(dvp)
2048 * since it may need to release the fs_nodelock on the dvp
2051 ni
.ni_cnd
.cn_nameiop
= 0;
2056 * nameidone has to happen before we vnode_put(dvp)
2057 * since it may need to release the fs_nodelock on the dvp
2060 ni
.ni_cnd
.cn_nameiop
= 0;
2064 if (!error
&& VATTR_IS_ACTIVE(vap
, va_data_size
)) {
2065 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
,
2068 tempsize
= vap
->va_data_size
;
2070 VATTR_SET(vap
, va_data_size
, tempsize
);
2071 error
= vnode_setattr(vp
, vap
, ctx
);
2076 error
= nfsrv_vptofh(nx
, nd
->nd_vers
, NULL
, vp
, ctx
, &nfh
);
2078 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
2079 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
2080 if (nd
->nd_vers
== NFS_VER2
)
2081 error
= postattrerr
;
2087 if (nd
->nd_vers
== NFS_VER3
) {
2088 if (exclusive_flag
&& !error
&&
2089 bcmp(cverf
, &postattr
.va_access_time
, NFSX_V3CREATEVERF
))
2091 nfsm_srv_vattr_init(&dpostattr
, NFS_VER3
);
2092 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
2098 /* assemble reply */
2099 nd
->nd_repstat
= error
;
2100 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(nd
->nd_vers
, &nfh
) +
2101 NFSX_FATTR(nd
->nd_vers
) + NFSX_WCCDATA(nd
->nd_vers
));
2103 *mrepp
= nmrep
.nmc_mhead
;
2104 nfsmout_on_status(nd
, error
);
2105 if (nd
->nd_vers
== NFS_VER3
) {
2106 if (!nd
->nd_repstat
) {
2107 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2108 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, postattrerr
, &postattr
);
2110 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
2111 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
2113 nfsm_chain_add_fh(error
, &nmrep
, NFS_VER2
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2115 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
2118 nfsm_chain_build_done(error
, &nmrep
);
2119 if (ni
.ni_cnd
.cn_nameiop
) {
2121 * nameidone has to happen before we vnode_put(dvp)
2122 * since it may need to release the fs_nodelock on the dvp
2133 nfsm_chain_cleanup(&nmrep
);
2140 * nfs v3 mknod service
2144 struct nfsrv_descript
*nd
,
2145 struct nfsrv_sock
*slp
,
2149 struct vnode_attr dpreattr
, dpostattr
, postattr
;
2150 struct vnode_attr va
, *vap
= &va
;
2151 struct nameidata ni
;
2152 int error
, dpreattrerr
, dpostattrerr
, postattrerr
;
2153 uint32_t len
= 0, cnflags
;
2154 u_int32_t major
= 0, minor
= 0;
2156 vnode_t vp
, dvp
, dirp
;
2157 struct nfs_filehandle nfh
;
2158 struct nfs_export
*nx
= NULL
;
2159 struct nfs_export_options
*nxo
;
2161 kauth_acl_t xacl
= NULL
;
2162 struct nfsm_chain
*nmreq
, nmrep
;
2165 dpreattrerr
= dpostattrerr
= postattrerr
= ENOENT
;
2166 nmreq
= &nd
->nd_nmreq
;
2167 nfsm_chain_null(&nmrep
);
2168 vp
= dvp
= dirp
= NULL
;
2169 ni
.ni_cnd
.cn_nameiop
= 0;
2172 * Save the original credential UID in case they are
2173 * mapped and we need to map the IDs in the attributes.
2175 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
2177 nfsm_chain_get_fh_ptr(error
, nmreq
, NFS_VER3
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2178 nfsm_chain_get_32(error
, nmreq
, len
);
2179 nfsm_name_len_check(error
, nd
, len
);
2182 ni
.ni_cnd
.cn_nameiop
= CREATE
;
2183 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2184 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
2186 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
2188 /* update export stats */
2189 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
2191 /* update active user stats */
2192 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
2196 nfsm_srv_pre_vattr_init(&dpreattr
);
2197 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
2200 ni
.ni_cnd
.cn_nameiop
= 0;
2207 nfsm_chain_get_32(error
, nmreq
, vtyp
);
2209 vtyp
= nfstov_type(vtyp
, NFS_VER3
);
2210 if (!error
&& (vtyp
!= VCHR
) && (vtyp
!= VBLK
) && (vtyp
!= VSOCK
) && (vtyp
!= VFIFO
)) {
2211 error
= NFSERR_BADTYPE
;
2216 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
2217 if ((vtyp
== VCHR
) || (vtyp
== VBLK
)) {
2218 nfsm_chain_get_32(error
, nmreq
, major
);
2219 nfsm_chain_get_32(error
, nmreq
, minor
);
2221 VATTR_SET(vap
, va_rdev
, makedev(major
, minor
));
2226 * If it doesn't exist, create it.
2232 VATTR_SET(vap
, va_type
, vtyp
);
2235 * If the credentials were mapped, we should
2236 * map the same values in the attributes.
2238 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nd
->nd_cr
) != saved_uid
)) {
2240 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nd
->nd_cr
));
2241 if (kauth_cred_ismember_gid(nd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
2242 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nd
->nd_cr
));
2245 /* authorize before creating */
2246 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
, nxo
, 0);
2248 /* construct ACL and handle inheritance */
2250 error
= kauth_acl_inherit(dvp
,
2256 if (!error
&& xacl
!= NULL
)
2257 VATTR_SET(vap
, va_acl
, xacl
);
2259 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
2260 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
2262 /* validate new-file security information */
2264 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
2265 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
2267 * Most NFS servers just ignore the UID/GID attributes, so we
2268 * try ignoring them if that'll help the request succeed.
2270 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
2271 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
2272 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
2278 if (vtyp
== VSOCK
) {
2279 error
= VNOP_CREATE(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
);
2281 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
2283 * If some of the requested attributes weren't handled by the VNOP,
2284 * use our fallback code.
2286 error
= vnode_setattr_fallback(vp
, vap
, ctx
);
2288 if (vtyp
!= VFIFO
&& (error
= suser(nd
->nd_cr
, (u_short
*)0)))
2290 if ((error
= VNOP_MKNOD(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
)))
2297 ni
.ni_cnd
.cn_nameiop
= LOOKUP
;
2298 ni
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
2299 ni
.ni_cnd
.cn_context
= vfs_context_current();
2300 ni
.ni_startdir
= dvp
;
2302 cnflags
= ni
.ni_cnd
.cn_flags
; /* store in case we have to restore */
2303 while ((error
= lookup(&ni
)) == ERECYCLE
) {
2304 ni
.ni_cnd
.cn_flags
= cnflags
;
2305 ni
.ni_cnd
.cn_nameptr
= ni
.ni_cnd
.cn_pnbuf
;
2306 ni
.ni_usedvp
= ni
.ni_dvp
= ni
.ni_startdir
= dvp
;
2310 if (ni
.ni_cnd
.cn_flags
& ISSYMLINK
)
2316 kauth_acl_free(xacl
);
2319 * nameidone has to happen before we vnode_put(dvp)
2320 * since it may need to release the fs_nodelock on the dvp
2323 ni
.ni_cnd
.cn_nameiop
= 0;
2329 error
= nfsrv_vptofh(nx
, NFS_VER3
, NULL
, vp
, ctx
, &nfh
);
2331 nfsm_srv_vattr_init(&postattr
, NFS_VER3
);
2332 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
2340 nfsm_srv_vattr_init(&dpostattr
, NFS_VER3
);
2341 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
2346 /* assemble reply */
2347 nd
->nd_repstat
= error
;
2348 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(NFS_VER3
, &nfh
) +
2349 NFSX_POSTOPATTR(NFS_VER3
) + NFSX_WCCDATA(NFS_VER3
));
2351 *mrepp
= nmrep
.nmc_mhead
;
2352 nfsmout_on_status(nd
, error
);
2353 if (!nd
->nd_repstat
) {
2354 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2355 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, postattrerr
, &postattr
);
2357 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
2358 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
2360 nfsm_chain_build_done(error
, &nmrep
);
2361 if (ni
.ni_cnd
.cn_nameiop
) {
2363 * nameidone has to happen before we vnode_put(dvp)
2364 * since it may need to release the fs_nodelock on the dvp
2379 nfsm_chain_cleanup(&nmrep
);
2386 * nfs remove service
2390 struct nfsrv_descript
*nd
,
2391 struct nfsrv_sock
*slp
,
2395 struct nameidata ni
;
2396 int error
, dpreattrerr
, dpostattrerr
;
2399 vnode_t vp
, dvp
, dirp
= NULL
;
2400 struct vnode_attr dpreattr
, dpostattr
;
2401 struct nfs_filehandle nfh
;
2402 struct nfs_export
*nx
= NULL
;
2403 struct nfs_export_options
*nxo
;
2404 struct nfsm_chain
*nmreq
, nmrep
;
2407 dpreattrerr
= dpostattrerr
= ENOENT
;
2408 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
2409 dvp
= vp
= dirp
= NULL
;
2410 nmreq
= &nd
->nd_nmreq
;
2411 nfsm_chain_null(&nmrep
);
2413 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2414 nfsm_chain_get_32(error
, nmreq
, len
);
2415 nfsm_name_len_check(error
, nd
, len
);
2418 ni
.ni_cnd
.cn_nameiop
= DELETE
;
2419 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2420 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
2422 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
2424 /* update export stats */
2425 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
2427 /* update active user stats */
2428 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
2432 if (nd
->nd_vers
== NFS_VER3
) {
2433 nfsm_srv_pre_vattr_init(&dpreattr
);
2434 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
2445 if (vnode_vtype(vp
) == VDIR
)
2446 error
= EPERM
; /* POSIX */
2447 else if (vnode_isvroot(vp
))
2449 * The root of a mounted filesystem cannot be deleted.
2453 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, ctx
, nxo
, 0);
2461 if (nfsrv_fsevents_enabled
&& need_fsevent(FSE_DELETE
, dvp
)) {
2463 if ((path
= get_pathbuff()) && !vn_getpath(vp
, path
, &plen
)) {
2464 get_fse_info(vp
, &finfo
, ctx
);
2466 release_pathbuff(path
);
2471 error
= VNOP_REMOVE(dvp
, vp
, &ni
.ni_cnd
, 0, ctx
);
2476 add_fsevent(FSE_DELETE
, ctx
,
2477 FSE_ARG_STRING
, plen
, path
,
2478 FSE_ARG_FINFO
, &finfo
,
2480 release_pathbuff(path
);
2486 * nameidone has to happen before we vnode_put(dvp)
2487 * since it may need to release the fs_nodelock on the dvp
2497 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
2498 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
2502 /* assemble reply */
2503 nd
->nd_repstat
= error
;
2504 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCDATA(nd
->nd_vers
));
2506 *mrepp
= nmrep
.nmc_mhead
;
2507 nfsmout_on_status(nd
, error
);
2508 if (nd
->nd_vers
== NFS_VER3
)
2509 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
2510 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
2512 nfsm_chain_build_done(error
, &nmrep
);
2514 nfsm_chain_cleanup(&nmrep
);
2521 * nfs rename service
2525 struct nfsrv_descript
*nd
,
2526 struct nfsrv_sock
*slp
,
2530 kauth_cred_t saved_cred
= NULL
;
2533 uint32_t fromlen
, tolen
;
2534 int fdpreattrerr
, fdpostattrerr
;
2535 int tdpreattrerr
, tdpostattrerr
;
2536 char *frompath
= NULL
, *topath
= NULL
;
2537 struct nameidata fromni
, toni
;
2538 vnode_t fvp
, tvp
, tdvp
, fdvp
, fdirp
, tdirp
;
2539 struct vnode_attr fdpreattr
, fdpostattr
;
2540 struct vnode_attr tdpreattr
, tdpostattr
;
2541 struct nfs_filehandle fnfh
, tnfh
;
2542 struct nfs_export
*fnx
, *tnx
;
2543 struct nfs_export_options
*fnxo
, *tnxo
;
2544 enum vtype fvtype
, tvtype
;
2545 int holding_mntlock
;
2547 struct nfsm_chain
*nmreq
, nmrep
;
2548 char *from_name
, *to_name
;
2550 int from_len
=0, to_len
=0;
2551 fse_info from_finfo
, to_finfo
;
2553 u_char didstats
= 0;
2557 fdpreattrerr
= fdpostattrerr
= ENOENT
;
2558 tdpreattrerr
= tdpostattrerr
= ENOENT
;
2559 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
2560 fromlen
= tolen
= 0;
2561 frompath
= topath
= NULL
;
2562 fdirp
= tdirp
= NULL
;
2563 nmreq
= &nd
->nd_nmreq
;
2564 nfsm_chain_null(&nmrep
);
2567 * these need to be set before calling any code
2568 * that they may take us out through the error path.
2570 holding_mntlock
= 0;
2575 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, fnfh
.nfh_fhp
, fnfh
.nfh_len
);
2576 nfsm_chain_get_32(error
, nmreq
, fromlen
);
2577 nfsm_name_len_check(error
, nd
, fromlen
);
2579 error
= nfsm_chain_get_path_namei(nmreq
, fromlen
, &fromni
);
2581 frompath
= fromni
.ni_cnd
.cn_pnbuf
;
2583 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, tnfh
.nfh_fhp
, tnfh
.nfh_len
);
2584 nfsm_chain_get_32(error
, nmreq
, tolen
);
2585 nfsm_name_len_check(error
, nd
, tolen
);
2587 error
= nfsm_chain_get_path_namei(nmreq
, tolen
, &toni
);
2589 topath
= toni
.ni_cnd
.cn_pnbuf
;
2592 * Remember our original uid so that we can reset cr_uid before
2593 * the second nfsrv_namei() call, in case it is remapped.
2595 saved_cred
= nd
->nd_cr
;
2596 kauth_cred_ref(saved_cred
);
2598 fromni
.ni_cnd
.cn_nameiop
= DELETE
;
2599 fromni
.ni_cnd
.cn_flags
= WANTPARENT
;
2601 fromni
.ni_cnd
.cn_pnbuf
= frompath
;
2603 fromni
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2604 fromni
.ni_cnd
.cn_flags
|= HASBUF
;
2606 error
= nfsrv_namei(nd
, ctx
, &fromni
, &fnfh
, &fdirp
, &fnx
, &fnxo
);
2609 fdvp
= fromni
.ni_dvp
;
2613 if (nd
->nd_vers
== NFS_VER3
) {
2614 nfsm_srv_pre_vattr_init(&fdpreattr
);
2615 fdpreattrerr
= vnode_getattr(fdirp
, &fdpreattr
, ctx
);
2621 fvtype
= vnode_vtype(fvp
);
2623 /* reset credential if it was remapped */
2624 if (nd
->nd_cr
!= saved_cred
) {
2625 kauth_cred_ref(saved_cred
);
2626 kauth_cred_unref(&nd
->nd_cr
);
2627 ctx
->vc_ucred
= nd
->nd_cr
= saved_cred
;
2630 toni
.ni_cnd
.cn_nameiop
= RENAME
;
2631 toni
.ni_cnd
.cn_flags
= WANTPARENT
;
2633 toni
.ni_cnd
.cn_pnbuf
= topath
;
2635 toni
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2636 toni
.ni_cnd
.cn_flags
|= HASBUF
;
2639 toni
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2642 error
= nfsrv_namei(nd
, ctx
, &toni
, &tnfh
, &tdirp
, &tnx
, &tnxo
);
2645 * Translate error code for rename("dir1", "dir2/.").
2647 if (error
== EISDIR
&& fvtype
== VDIR
) {
2648 if (nd
->nd_vers
== NFS_VER3
)
2659 /* update export stats once only */
2661 /* update export stats */
2662 NFSStatAdd64(&tnx
->nx_stats
.ops
, 1);
2664 /* update active user stats */
2665 nfsrv_update_user_stat(tnx
, nd
, saved_uid
, 1, 0, 0);
2671 if (nd
->nd_vers
== NFS_VER3
) {
2672 nfsm_srv_pre_vattr_init(&tdpreattr
);
2673 tdpreattrerr
= vnode_getattr(tdirp
, &tdpreattr
, ctx
);
2681 tvtype
= vnode_vtype(tvp
);
2683 if (fvtype
== VDIR
&& tvtype
!= VDIR
) {
2684 if (nd
->nd_vers
== NFS_VER3
)
2689 } else if (fvtype
!= VDIR
&& tvtype
== VDIR
) {
2690 if (nd
->nd_vers
== NFS_VER3
)
2696 if (tvtype
== VDIR
&& vnode_mountedhere(tvp
)) {
2697 if (nd
->nd_vers
== NFS_VER3
)
2705 if (nd
->nd_vers
== NFS_VER3
)
2715 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
2716 * the node is moving between directories and we need rights to remove from the
2717 * old and add to the new.
2719 * If tvp already exists and is not a directory, we need to be allowed to delete it.
2721 * Note that we do not inherit when renaming. XXX this needs to be revisited to
2722 * implement the deferred-inherit bit.
2728 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
2731 } else if (tdvp
!= fdvp
) {
2735 /* moving out of fdvp, must have delete rights */
2736 if ((error
= nfsrv_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, ctx
, fnxo
, 0)) != 0)
2738 /* moving into tdvp or tvp, must have rights to add */
2739 if ((error
= nfsrv_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
2741 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2742 ctx
, tnxo
, 0)) != 0)
2745 /* node staying in same directory, must be allowed to add new name */
2746 if ((error
= nfsrv_authorize(fdvp
, NULL
,
2747 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2748 ctx
, fnxo
, 0)) != 0)
2751 /* overwriting tvp */
2752 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
2753 ((error
= nfsrv_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, ctx
, tnxo
, 0)) != 0))
2756 /* XXX more checks? */
2759 /* authorization denied */
2764 if ((vnode_mount(fvp
) != vnode_mount(tdvp
)) ||
2765 (tvp
&& (vnode_mount(fvp
) != vnode_mount(tvp
)))) {
2766 if (nd
->nd_vers
== NFS_VER3
)
2773 * The following edge case is caught here:
2774 * (to cannot be a descendent of from)
2787 if (tdvp
->v_parent
== fvp
) {
2788 if (nd
->nd_vers
== NFS_VER3
)
2794 if (fvtype
== VDIR
&& vnode_mountedhere(fvp
)) {
2795 if (nd
->nd_vers
== NFS_VER3
)
2802 * If source is the same as the destination (that is the
2803 * same vnode) then there is nothing to do...
2804 * EXCEPT if the underlying file system supports case
2805 * insensitivity and is case preserving. In this case
2806 * the file system needs to handle the special case of
2807 * getting the same vnode as target (fvp) and source (tvp).
2809 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2810 * and _PC_CASE_PRESERVING can have this exception, and they need to
2811 * handle the special case of getting the same vnode as target and
2812 * source. NOTE: Then the target is unlocked going into vnop_rename,
2813 * so not to cause locking problems. There is a single reference on tvp.
2815 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2816 * that correct behaviour then is just to remove the source (link)
2818 if ((fvp
== tvp
) && (fdvp
== tdvp
)) {
2819 if (fromni
.ni_cnd
.cn_namelen
== toni
.ni_cnd
.cn_namelen
&&
2820 !bcmp(fromni
.ni_cnd
.cn_nameptr
, toni
.ni_cnd
.cn_nameptr
,
2821 fromni
.ni_cnd
.cn_namelen
)) {
2826 if (holding_mntlock
&& vnode_mount(fvp
) != locked_mp
) {
2828 * we're holding a reference and lock
2829 * on locked_mp, but it no longer matches
2830 * what we want to do... so drop our hold
2832 mount_unlock_renames(locked_mp
);
2833 mount_drop(locked_mp
, 0);
2834 holding_mntlock
= 0;
2836 if (tdvp
!= fdvp
&& fvtype
== VDIR
) {
2838 * serialize renames that re-shape
2839 * the tree... if holding_mntlock is
2840 * set, then we're ready to go...
2842 * first need to drop the iocounts
2843 * we picked up, second take the
2844 * lock to serialize the access,
2845 * then finally start the lookup
2846 * process over with the lock held
2848 if (!holding_mntlock
) {
2850 * need to grab a reference on
2851 * the mount point before we
2852 * drop all the iocounts... once
2853 * the iocounts are gone, the mount
2856 locked_mp
= vnode_mount(fvp
);
2857 mount_ref(locked_mp
, 0);
2859 /* make a copy of to path to pass to nfsrv_namei() again */
2860 MALLOC_ZONE(topath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2862 bcopy(toni
.ni_cnd
.cn_pnbuf
, topath
, tolen
+ 1);
2865 * nameidone has to happen before we vnode_put(tdvp)
2866 * since it may need to release the fs_nodelock on the tdvp
2874 /* make a copy of from path to pass to nfsrv_namei() again */
2875 MALLOC_ZONE(frompath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2877 bcopy(fromni
.ni_cnd
.cn_pnbuf
, frompath
, fromlen
+ 1);
2880 * nameidone has to happen before we vnode_put(fdvp)
2881 * since it may need to release the fs_nodelock on the fdvp
2896 mount_lock_renames(locked_mp
);
2897 holding_mntlock
= 1;
2902 fdpreattrerr
= tdpreattrerr
= ENOENT
;
2904 if (!topath
|| !frompath
) {
2905 /* we couldn't allocate a path, so bail */
2910 /* reset credential if it was remapped */
2911 if (nd
->nd_cr
!= saved_cred
) {
2912 kauth_cred_ref(saved_cred
);
2913 kauth_cred_unref(&nd
->nd_cr
);
2914 ctx
->vc_ucred
= nd
->nd_cr
= saved_cred
;
2921 * when we dropped the iocounts to take
2922 * the lock, we allowed the identity of
2923 * the various vnodes to change... if they did,
2924 * we may no longer be dealing with a rename
2925 * that reshapes the tree... once we're holding
2926 * the iocounts, the vnodes can't change type
2927 * so we're free to drop the lock at this point
2930 if (holding_mntlock
) {
2931 mount_unlock_renames(locked_mp
);
2932 mount_drop(locked_mp
, 0);
2933 holding_mntlock
= 0;
2937 // save these off so we can later verify that fvp is the same
2939 oname
= fvp
->v_name
;
2940 oparent
= fvp
->v_parent
;
2943 * If generating an fsevent, then
2944 * stash any pre-rename info we may need.
2947 if (nfsrv_fsevents_enabled
&& need_fsevent(FSE_RENAME
, fvp
)) {
2948 int from_truncated
= 0, to_truncated
= 0;
2950 get_fse_info(fvp
, &from_finfo
, ctx
);
2952 get_fse_info(tvp
, &to_finfo
, ctx
);
2954 from_name
= get_pathbuff();
2956 from_len
= safe_getpath(fdvp
, fromni
.ni_cnd
.cn_nameptr
, from_name
, MAXPATHLEN
, &from_truncated
);
2959 to_name
= from_name
? get_pathbuff() : NULL
;
2961 to_len
= safe_getpath(tdvp
, toni
.ni_cnd
.cn_nameptr
, to_name
, MAXPATHLEN
, &to_truncated
);
2964 if (from_truncated
|| to_truncated
) {
2965 from_finfo
.mode
|= FSE_TRUNCATED_PATH
;
2972 #else /* CONFIG_FSE */
2975 #endif /* CONFIG_FSE */
2977 error
= VNOP_RENAME(fromni
.ni_dvp
, fromni
.ni_vp
, &fromni
.ni_cnd
,
2978 toni
.ni_dvp
, toni
.ni_vp
, &toni
.ni_cnd
, ctx
);
2980 * fix up name & parent pointers. note that we first
2981 * check that fvp has the same name/parent pointers it
2982 * had before the rename call... this is a 'weak' check
2985 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
2987 update_flags
= VNODE_UPDATE_NAME
;
2989 update_flags
|= VNODE_UPDATE_PARENT
;
2990 vnode_update_identity(fvp
, tdvp
, toni
.ni_cnd
.cn_nameptr
,
2991 toni
.ni_cnd
.cn_namelen
, toni
.ni_cnd
.cn_hash
, update_flags
);
2995 * If the rename is OK and we've got the paths
2996 * then add an fsevent.
2999 if (nfsrv_fsevents_enabled
&& !error
&& from_name
&& to_name
) {
3001 add_fsevent(FSE_RENAME
, ctx
,
3002 FSE_ARG_STRING
, from_len
, from_name
,
3003 FSE_ARG_FINFO
, &from_finfo
,
3004 FSE_ARG_STRING
, to_len
, to_name
,
3005 FSE_ARG_FINFO
, &to_finfo
,
3008 add_fsevent(FSE_RENAME
, ctx
,
3009 FSE_ARG_STRING
, from_len
, from_name
,
3010 FSE_ARG_FINFO
, &from_finfo
,
3011 FSE_ARG_STRING
, to_len
, to_name
,
3016 release_pathbuff(from_name
);
3018 release_pathbuff(to_name
);
3019 #endif /* CONFIG_FSE */
3020 from_name
= to_name
= NULL
;
3023 if (holding_mntlock
) {
3024 mount_unlock_renames(locked_mp
);
3025 mount_drop(locked_mp
, 0);
3026 holding_mntlock
= 0;
3030 * nameidone has to happen before we vnode_put(tdvp)
3031 * since it may need to release the fs_nodelock on the tdvp
3042 * nameidone has to happen before we vnode_put(fdvp)
3043 * since it may need to release the fs_nodelock on the fdvp
3054 nfsm_srv_vattr_init(&fdpostattr
, nd
->nd_vers
);
3055 fdpostattrerr
= vnode_getattr(fdirp
, &fdpostattr
, ctx
);
3060 nfsm_srv_vattr_init(&tdpostattr
, nd
->nd_vers
);
3061 tdpostattrerr
= vnode_getattr(tdirp
, &tdpostattr
, ctx
);
3067 /* assemble reply */
3068 nd
->nd_repstat
= error
;
3069 error
= nfsrv_rephead(nd
, slp
, &nmrep
, 2 * NFSX_WCCDATA(nd
->nd_vers
));
3071 *mrepp
= nmrep
.nmc_mhead
;
3072 nfsmout_on_status(nd
, error
);
3073 if (nd
->nd_vers
== NFS_VER3
) {
3074 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3075 fdpreattrerr
, &fdpreattr
, fdpostattrerr
, &fdpostattr
);
3076 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3077 tdpreattrerr
, &tdpreattr
, tdpostattrerr
, &tdpostattr
);
3080 nfsm_chain_build_done(error
, &nmrep
);
3081 if (holding_mntlock
) {
3082 mount_unlock_renames(locked_mp
);
3083 mount_drop(locked_mp
, 0);
3087 * nameidone has to happen before we vnode_put(tdvp)
3088 * since it may need to release the fs_nodelock on the tdvp
3098 * nameidone has to happen before we vnode_put(fdvp)
3099 * since it may need to release the fs_nodelock on the fdvp
3112 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
3114 FREE_ZONE(topath
, MAXPATHLEN
, M_NAMEI
);
3116 kauth_cred_unref(&saved_cred
);
3118 nfsm_chain_cleanup(&nmrep
);
3129 struct nfsrv_descript
*nd
,
3130 struct nfsrv_sock
*slp
,
3134 struct nameidata ni
;
3135 int error
, dpreattrerr
, dpostattrerr
, attrerr
;
3137 vnode_t vp
, xp
, dvp
, dirp
;
3138 struct vnode_attr dpreattr
, dpostattr
, attr
;
3139 struct nfs_filehandle nfh
, dnfh
;
3140 struct nfs_export
*nx
;
3141 struct nfs_export_options
*nxo
;
3142 struct nfsm_chain
*nmreq
, nmrep
;
3145 dpreattrerr
= dpostattrerr
= attrerr
= ENOENT
;
3146 vp
= xp
= dvp
= dirp
= NULL
;
3147 nmreq
= &nd
->nd_nmreq
;
3148 nfsm_chain_null(&nmrep
);
3150 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3151 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, dnfh
.nfh_fhp
, dnfh
.nfh_len
);
3152 nfsm_chain_get_32(error
, nmreq
, len
);
3153 nfsm_name_len_check(error
, nd
, len
);
3155 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
3158 /* update export stats */
3159 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3161 /* update active user stats */
3162 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
3164 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
3167 /* we're not allowed to link to directories... */
3168 if (vnode_vtype(vp
) == VDIR
) {
3169 error
= EPERM
; /* POSIX */
3173 /* ...or to anything that kauth doesn't want us to (eg. immutable items) */
3174 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, ctx
, nxo
, 0)) != 0)
3177 ni
.ni_cnd
.cn_nameiop
= CREATE
;
3178 ni
.ni_cnd
.cn_flags
= LOCKPARENT
;
3179 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
3181 error
= nfsrv_namei(nd
, ctx
, &ni
, &dnfh
, &dirp
, &nx
, &nxo
);
3183 if (nd
->nd_vers
== NFS_VER3
) {
3184 nfsm_srv_pre_vattr_init(&dpreattr
);
3185 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
3198 else if (vnode_mount(vp
) != vnode_mount(dvp
))
3201 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
, nxo
, 0);
3204 error
= VNOP_LINK(vp
, dvp
, &ni
.ni_cnd
, ctx
);
3207 if (nfsrv_fsevents_enabled
&& !error
&& need_fsevent(FSE_CREATE_FILE
, dvp
)) {
3208 char *target_path
= NULL
;
3209 int plen
, truncated
=0;
3212 /* build the path to the new link file */
3213 target_path
= get_pathbuff();
3215 plen
= safe_getpath(dvp
, ni
.ni_cnd
.cn_nameptr
, target_path
, MAXPATHLEN
, &truncated
);
3217 if (get_fse_info(vp
, &finfo
, ctx
) == 0) {
3219 finfo
.mode
|= FSE_TRUNCATED_PATH
;
3221 add_fsevent(FSE_CREATE_FILE
, ctx
,
3222 FSE_ARG_STRING
, plen
, target_path
,
3223 FSE_ARG_FINFO
, &finfo
,
3227 release_pathbuff(target_path
);
3233 * nameidone has to happen before we vnode_put(dvp)
3234 * since it may need to release the fs_nodelock on the dvp
3242 if (nd
->nd_vers
== NFS_VER3
) {
3243 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
3244 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
3247 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
3248 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
3256 /* assemble reply */
3257 nd
->nd_repstat
= error
;
3258 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_WCCDATA(nd
->nd_vers
));
3260 *mrepp
= nmrep
.nmc_mhead
;
3261 nfsmout_on_status(nd
, error
);
3262 if (nd
->nd_vers
== NFS_VER3
) {
3263 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
3264 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3265 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
3268 nfsm_chain_build_done(error
, &nmrep
);
3272 nfsm_chain_cleanup(&nmrep
);
3279 * nfs symbolic link service
3283 struct nfsrv_descript
*nd
,
3284 struct nfsrv_sock
*slp
,
3288 struct vnode_attr dpreattr
, dpostattr
, postattr
;
3289 struct vnode_attr va
, *vap
= &va
;
3290 struct nameidata ni
;
3291 int error
, dpreattrerr
, dpostattrerr
, postattrerr
;
3292 uint32_t len
= 0, linkdatalen
, cnflags
;
3295 vnode_t vp
, dvp
, dirp
;
3296 struct nfs_filehandle nfh
;
3297 struct nfs_export
*nx
= NULL
;
3298 struct nfs_export_options
*nxo
;
3300 char uio_buf
[ UIO_SIZEOF(1) ];
3301 struct nfsm_chain
*nmreq
, nmrep
;
3304 dpreattrerr
= dpostattrerr
= postattrerr
= ENOENT
;
3305 nmreq
= &nd
->nd_nmreq
;
3306 nfsm_chain_null(&nmrep
);
3311 * Save the original credential UID in case they are
3312 * mapped and we need to map the IDs in the attributes.
3314 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
3316 ni
.ni_cnd
.cn_nameiop
= 0;
3319 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3320 nfsm_chain_get_32(error
, nmreq
, len
);
3321 nfsm_name_len_check(error
, nd
, len
);
3324 ni
.ni_cnd
.cn_nameiop
= CREATE
;
3325 ni
.ni_cnd
.cn_flags
= LOCKPARENT
;
3326 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
3328 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
3330 /* update export stats */
3331 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3333 /* update active user stats */
3334 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
3338 if (nd
->nd_vers
== NFS_VER3
) {
3339 nfsm_srv_pre_vattr_init(&dpreattr
);
3340 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
3347 ni
.ni_cnd
.cn_nameiop
= 0;
3354 if (nd
->nd_vers
== NFS_VER3
)
3355 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
3356 nfsm_chain_get_32(error
, nmreq
, linkdatalen
);
3357 if (!error
&& (((nd
->nd_vers
== NFS_VER2
) && (linkdatalen
> NFS_MAXPATHLEN
)) ||
3358 ((nd
->nd_vers
== NFS_VER3
) && (linkdatalen
> MAXPATHLEN
))))
3359 error
= NFSERR_NAMETOL
;
3361 MALLOC(linkdata
, caddr_t
, linkdatalen
+ 1, M_TEMP
, M_WAITOK
);
3363 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3364 &uio_buf
[0], sizeof(uio_buf
));
3365 if (!linkdata
|| !auio
) {
3369 uio_addiov(auio
, CAST_USER_ADDR_T(linkdata
), linkdatalen
);
3370 error
= nfsm_chain_get_uio(nmreq
, linkdatalen
, auio
);
3371 if (!error
&& (nd
->nd_vers
== NFS_VER2
))
3372 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
3374 *(linkdata
+ linkdatalen
) = '\0';
3381 * If the credentials were mapped, we should
3382 * map the same values in the attributes.
3384 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nd
->nd_cr
) != saved_uid
)) {
3386 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nd
->nd_cr
));
3387 if (kauth_cred_ismember_gid(nd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
3388 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nd
->nd_cr
));
3390 VATTR_SET(vap
, va_type
, VLNK
);
3391 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3392 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3394 /* authorize before creating */
3395 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
, nxo
, 0);
3397 /* validate given attributes */
3399 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
3400 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
3402 * Most NFS servers just ignore the UID/GID attributes, so we
3403 * try ignoring them if that'll help the request succeed.
3405 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3406 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3407 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
3411 error
= VNOP_SYMLINK(dvp
, &vp
, &ni
.ni_cnd
, vap
, linkdata
, ctx
);
3413 if (!error
&& (nd
->nd_vers
== NFS_VER3
)) {
3415 ni
.ni_cnd
.cn_nameiop
= LOOKUP
;
3416 ni
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| FOLLOW
);
3417 ni
.ni_cnd
.cn_flags
|= (NOFOLLOW
| LOCKLEAF
);
3418 ni
.ni_cnd
.cn_context
= ctx
;
3419 ni
.ni_startdir
= dvp
;
3421 cnflags
= ni
.ni_cnd
.cn_flags
; /* store in case we have to restore */
3422 while ((error
= lookup(&ni
)) == ERECYCLE
) {
3423 ni
.ni_cnd
.cn_flags
= cnflags
;
3424 ni
.ni_cnd
.cn_nameptr
= ni
.ni_cnd
.cn_pnbuf
;
3425 ni
.ni_usedvp
= ni
.ni_dvp
= ni
.ni_startdir
= dvp
;
3431 error
= nfsrv_vptofh(nx
, NFS_VER3
, NULL
, vp
, ctx
, &nfh
);
3433 nfsm_srv_vattr_init(&postattr
, NFS_VER3
);
3434 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
3440 if (nfsrv_fsevents_enabled
&& !error
&& vp
) {
3441 add_fsevent(FSE_CREATE_FILE
, ctx
,
3448 * nameidone has to happen before we vnode_put(dvp)
3449 * since it may need to release the fs_nodelock on the dvp
3452 ni
.ni_cnd
.cn_nameiop
= 0;
3458 FREE(linkdata
, M_TEMP
);
3462 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
3463 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
3469 /* assemble reply */
3470 nd
->nd_repstat
= error
;
3471 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(nd
->nd_vers
, &nfh
) +
3472 NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_WCCDATA(nd
->nd_vers
));
3474 *mrepp
= nmrep
.nmc_mhead
;
3475 nfsmout_on_status(nd
, error
);
3476 if (nd
->nd_vers
== NFS_VER3
) {
3477 if (!nd
->nd_repstat
) {
3478 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3479 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, postattrerr
, &postattr
);
3481 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3482 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
3485 nfsm_chain_build_done(error
, &nmrep
);
3486 if (ni
.ni_cnd
.cn_nameiop
) {
3488 * nameidone has to happen before we vnode_put(dvp)
3489 * since it may need to release the fs_nodelock on the dvp
3500 FREE(linkdata
, M_TEMP
);
3502 nfsm_chain_cleanup(&nmrep
);
3513 struct nfsrv_descript
*nd
,
3514 struct nfsrv_sock
*slp
,
3518 struct vnode_attr dpreattr
, dpostattr
, postattr
;
3519 struct vnode_attr va
, *vap
= &va
;
3520 struct nameidata ni
;
3521 int error
, dpreattrerr
, dpostattrerr
, postattrerr
;
3523 vnode_t vp
, dvp
, dirp
;
3524 struct nfs_filehandle nfh
;
3525 struct nfs_export
*nx
= NULL
;
3526 struct nfs_export_options
*nxo
;
3528 kauth_acl_t xacl
= NULL
;
3529 struct nfsm_chain
*nmreq
, nmrep
;
3532 dpreattrerr
= dpostattrerr
= postattrerr
= ENOENT
;
3533 nmreq
= &nd
->nd_nmreq
;
3534 nfsm_chain_null(&nmrep
);
3537 * Save the original credential UID in case they are
3538 * mapped and we need to map the IDs in the attributes.
3540 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
3542 ni
.ni_cnd
.cn_nameiop
= 0;
3543 vp
= dvp
= dirp
= NULL
;
3545 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3546 nfsm_chain_get_32(error
, nmreq
, len
);
3547 nfsm_name_len_check(error
, nd
, len
);
3550 ni
.ni_cnd
.cn_nameiop
= CREATE
;
3551 ni
.ni_cnd
.cn_flags
= LOCKPARENT
;
3552 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
3554 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
3556 /* update export stats */
3557 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3559 /* update active user stats */
3560 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
3564 if (nd
->nd_vers
== NFS_VER3
) {
3565 nfsm_srv_pre_vattr_init(&dpreattr
);
3566 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
3573 ni
.ni_cnd
.cn_nameiop
= 0;
3580 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
3582 VATTR_SET(vap
, va_type
, VDIR
);
3586 * nameidone has to happen before we vnode_put(dvp)
3587 * since it may need to release the fs_nodelock on the dvp
3597 * If the credentials were mapped, we should
3598 * map the same values in the attributes.
3600 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nd
->nd_cr
) != saved_uid
)) {
3602 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nd
->nd_cr
));
3603 if (kauth_cred_ismember_gid(nd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
3604 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nd
->nd_cr
));
3607 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
, nxo
, 0);
3609 /* construct ACL and handle inheritance */
3611 error
= kauth_acl_inherit(dvp
,
3617 if (!error
&& xacl
!= NULL
)
3618 VATTR_SET(vap
, va_acl
, xacl
);
3620 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3621 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3623 /* validate new-file security information */
3625 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
3626 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
3628 * Most NFS servers just ignore the UID/GID attributes, so we
3629 * try ignoring them if that'll help the request succeed.
3631 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3632 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3633 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
3638 error
= VNOP_MKDIR(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
);
3641 if (nfsrv_fsevents_enabled
&& !error
)
3642 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
3645 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
3647 * If some of the requested attributes weren't handled by the VNOP,
3648 * use our fallback code.
3650 error
= vnode_setattr_fallback(vp
, vap
, ctx
);
3653 kauth_acl_free(xacl
);
3656 error
= nfsrv_vptofh(nx
, nd
->nd_vers
, NULL
, vp
, ctx
, &nfh
);
3658 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
3659 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
3660 if (nd
->nd_vers
== NFS_VER2
)
3661 error
= postattrerr
;
3667 * nameidone has to happen before we vnode_put(dvp)
3668 * since it may need to release the fs_nodelock on the dvp
3673 ni
.ni_cnd
.cn_nameiop
= 0;
3676 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
3677 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
3683 /* assemble reply */
3684 nd
->nd_repstat
= error
;
3685 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(nd
->nd_vers
, &nfh
) +
3686 NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_WCCDATA(nd
->nd_vers
));
3688 *mrepp
= nmrep
.nmc_mhead
;
3689 nfsmout_on_status(nd
, error
);
3690 if (nd
->nd_vers
== NFS_VER3
) {
3691 if (!nd
->nd_repstat
) {
3692 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3693 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, postattrerr
, &postattr
);
3695 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3696 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
3698 nfsm_chain_add_fh(error
, &nmrep
, NFS_VER2
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3700 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
3703 nfsm_chain_build_done(error
, &nmrep
);
3704 if (ni
.ni_cnd
.cn_nameiop
) {
3706 * nameidone has to happen before we vnode_put(dvp)
3707 * since it may need to release the fs_nodelock on the dvp
3717 nfsm_chain_cleanup(&nmrep
);
3728 struct nfsrv_descript
*nd
,
3729 struct nfsrv_sock
*slp
,
3733 int error
, dpreattrerr
, dpostattrerr
;
3736 vnode_t vp
, dvp
, dirp
;
3737 struct vnode_attr dpreattr
, dpostattr
;
3738 struct nfs_filehandle nfh
;
3739 struct nfs_export
*nx
= NULL
;
3740 struct nfs_export_options
*nxo
;
3741 struct nameidata ni
;
3742 struct nfsm_chain
*nmreq
, nmrep
;
3745 dpreattrerr
= dpostattrerr
= ENOENT
;
3746 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
3747 nmreq
= &nd
->nd_nmreq
;
3748 nfsm_chain_null(&nmrep
);
3750 vp
= dvp
= dirp
= NULL
;
3752 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3753 nfsm_chain_get_32(error
, nmreq
, len
);
3754 nfsm_name_len_check(error
, nd
, len
);
3757 ni
.ni_cnd
.cn_nameiop
= DELETE
;
3758 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
3759 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
3761 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
3763 /* update export stats */
3764 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3766 /* update active user stats */
3767 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
3771 if (nd
->nd_vers
== NFS_VER3
) {
3772 nfsm_srv_pre_vattr_init(&dpreattr
);
3773 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
3784 if (vnode_vtype(vp
) != VDIR
) {
3789 * No rmdir "." please.
3796 * The root of a mounted filesystem cannot be deleted.
3798 if (vnode_isvroot(vp
))
3801 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, ctx
, nxo
, 0);
3808 if (nfsrv_fsevents_enabled
&& need_fsevent(FSE_DELETE
, dvp
)) {
3810 if ((path
= get_pathbuff()) && !vn_getpath(vp
, path
, &plen
)) {
3811 get_fse_info(vp
, &finfo
, ctx
);
3813 release_pathbuff(path
);
3817 #endif /* CONFIG_FSE */
3819 error
= VNOP_RMDIR(dvp
, vp
, &ni
.ni_cnd
, ctx
);
3824 add_fsevent(FSE_DELETE
, ctx
,
3825 FSE_ARG_STRING
, plen
, path
,
3826 FSE_ARG_FINFO
, &finfo
,
3828 release_pathbuff(path
);
3830 #endif /* CONFIG_FSE */
3834 * nameidone has to happen before we vnode_put(dvp)
3835 * since it may need to release the fs_nodelock on the dvp
3843 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
3844 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
3850 /* assemble reply */
3851 nd
->nd_repstat
= error
;
3852 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCDATA(nd
->nd_vers
));
3854 *mrepp
= nmrep
.nmc_mhead
;
3855 nfsmout_on_status(nd
, error
);
3856 if (nd
->nd_vers
== NFS_VER3
)
3857 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3858 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
3860 nfsm_chain_build_done(error
, &nmrep
);
3864 nfsm_chain_cleanup(&nmrep
);
3871 * nfs readdir service
3872 * - mallocs what it thinks is enough to read
3873 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
3874 * - calls VNOP_READDIR()
3875 * - loops around building the reply
3876 * if the output generated exceeds count break out of loop
3877 * The nfsm_clget macro is used here so that the reply will be packed
3878 * tightly in mbuf clusters.
3879 * - it only knows that it has encountered eof when the VNOP_READDIR()
3881 * - as such one readdir rpc will return eof false although you are there
3882 * and then the next will return eof
3883 * - it trims out records with d_fileno == 0
3884 * this doesn't matter for Unix clients, but they might confuse clients
3886 * NB: It is tempting to set eof to true if the VNOP_READDIR() reads less
3887 * than requested, but this may not apply to all filesystems. For
3888 * example, client NFS does not { although it is never remote mounted
3890 * The alternate call nfsrv_readdirplus() does lookups as well.
3891 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
3892 * are supposed to cover. For readdir, the count is the total number of
3893 * bytes included in everything from the directory's postopattr through
3894 * the EOF flag. For readdirplus, the maxcount is the same, and the
3895 * dircount includes all that except for the entry attributes and handles.
3899 struct nfsrv_descript
*nd
,
3900 struct nfsrv_sock
*slp
,
3904 struct direntry
*dp
;
3905 char *cpos
, *cend
, *rbuf
;
3907 struct vnode_attr attr
;
3908 struct nfs_filehandle nfh
;
3909 struct nfs_export
*nx
;
3910 struct nfs_export_options
*nxo
;
3912 char uio_buf
[ UIO_SIZEOF(1) ];
3913 int len
, nlen
, rem
, xfer
, error
, attrerr
;
3914 int siz
, count
, fullsiz
, eofflag
, nentries
;
3915 u_quad_t off
, toff
, verf
;
3917 struct nfsm_chain
*nmreq
, nmrep
;
3921 count
= nentries
= 0;
3922 nmreq
= &nd
->nd_nmreq
;
3923 nfsm_chain_null(&nmrep
);
3927 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
3929 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3930 if (nd
->nd_vers
== NFS_VER3
) {
3931 nfsm_chain_get_64(error
, nmreq
, toff
);
3932 nfsm_chain_get_64(error
, nmreq
, verf
);
3934 nfsm_chain_get_32(error
, nmreq
, toff
);
3936 nfsm_chain_get_32(error
, nmreq
, count
);
3940 siz
= ((count
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
3941 xfer
= NFSRV_NDMAXDATA(nd
);
3946 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
3949 /* update export stats */
3950 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3952 /* update active user stats */
3953 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
3955 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
3958 if ((nd
->nd_vers
== NFS_VER2
) || (nxo
->nxo_flags
& NX_32BITCLIENTS
))
3959 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
3960 if (nd
->nd_vers
== NFS_VER3
) {
3961 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
3962 error
= attrerr
= vnode_getattr(vp
, &attr
, ctx
);
3963 if (!error
&& toff
&& verf
&& (verf
!= attr
.va_filerev
))
3964 error
= NFSERR_BAD_COOKIE
;
3967 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, ctx
, nxo
, 0);
3970 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
3972 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3973 &uio_buf
[0], sizeof(uio_buf
));
3974 if (!rbuf
|| !auio
) {
3979 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
3980 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
3982 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, ctx
);
3983 off
= uio_offset(auio
);
3985 if (nd
->nd_vers
== NFS_VER3
) {
3986 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
3987 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
3991 if (uio_resid(auio
) != 0) {
3992 siz
-= uio_resid(auio
);
3994 /* If nothing read, return empty reply with eof set */
3999 /* assemble reply */
4000 nd
->nd_repstat
= error
;
4001 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) +
4002 NFSX_COOKIEVERF(nd
->nd_vers
) + 2 * NFSX_UNSIGNED
);
4004 *mrepp
= nmrep
.nmc_mhead
;
4005 nfsmout_on_status(nd
, error
);
4006 if (nd
->nd_vers
== NFS_VER3
) {
4007 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4008 nfsm_chain_add_64(error
, &nmrep
, attr
.va_filerev
);
4010 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4011 nfsm_chain_add_32(error
, &nmrep
, TRUE
);
4012 nfsm_chain_build_done(error
, &nmrep
);
4018 * Check for degenerate cases of nothing useful read.
4019 * If so go try again
4023 dp
= (struct direntry
*)cpos
;
4024 while ((dp
->d_fileno
== 0) && (cpos
< cend
) && (nentries
> 0)) {
4025 cpos
+= dp
->d_reclen
;
4026 dp
= (struct direntry
*)cpos
;
4029 if ((cpos
>= cend
) || (nentries
== 0)) {
4038 /* assemble reply */
4039 nd
->nd_repstat
= error
;
4040 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) +
4041 NFSX_COOKIEVERF(nd
->nd_vers
) + siz
);
4043 *mrepp
= nmrep
.nmc_mhead
;
4044 nfsmout_on_status(nd
, error
);
4045 nmrep
.nmc_flags
|= NFSM_CHAIN_FLAG_ADD_CLUSTERS
;
4047 len
= 2 * NFSX_UNSIGNED
;
4048 if (nd
->nd_vers
== NFS_VER3
) {
4049 len
+= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
;
4050 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4051 nfsm_chain_add_64(error
, &nmrep
, attr
.va_filerev
);
4055 /* Loop through the records and build reply */
4056 while ((cpos
< cend
) && (nentries
> 0)) {
4057 if (dp
->d_fileno
!= 0) {
4058 nlen
= dp
->d_namlen
;
4059 if ((nd
->nd_vers
== NFS_VER2
) && (nlen
> NFS_MAXNAMLEN
))
4060 nlen
= NFS_MAXNAMLEN
;
4061 rem
= nfsm_rndup(nlen
)-nlen
;
4062 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
4063 if (nd
->nd_vers
== NFS_VER3
)
4064 len
+= 2 * NFSX_UNSIGNED
;
4069 /* Build the directory record xdr from the direntry. */
4070 nfsm_chain_add_32(error
, &nmrep
, TRUE
);
4071 if (nd
->nd_vers
== NFS_VER3
) {
4072 nfsm_chain_add_64(error
, &nmrep
, dp
->d_fileno
);
4074 nfsm_chain_add_32(error
, &nmrep
, dp
->d_fileno
);
4076 nfsm_chain_add_string(error
, &nmrep
, dp
->d_name
, nlen
);
4077 if (nd
->nd_vers
== NFS_VER3
) {
4078 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
4079 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
4080 nfsm_chain_add_64(error
, &nmrep
, dp
->d_seekoff
);
4082 nfsm_chain_add_32(error
, &nmrep
, dp
->d_seekoff
);
4086 cpos
+= dp
->d_reclen
;
4087 dp
= (struct direntry
*)cpos
;
4090 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4091 nfsm_chain_add_32(error
, &nmrep
, eofflag
? TRUE
: FALSE
);
4099 nd
->nd_repstat
= error
;
4100 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
));
4102 *mrepp
= nmrep
.nmc_mhead
;
4103 nfsmout_on_status(nd
, error
);
4104 if (nd
->nd_vers
== NFS_VER3
)
4105 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4107 nfsm_chain_build_done(error
, &nmrep
);
4109 nfsm_chain_cleanup(&nmrep
);
4117 struct nfsrv_descript
*nd
,
4118 struct nfsrv_sock
*slp
,
4122 struct direntry
*dp
;
4123 char *cpos
, *cend
, *rbuf
;
4125 struct nfs_filehandle dnfh
, nfh
;
4126 struct nfs_export
*nx
;
4127 struct nfs_export_options
*nxo
;
4129 char uio_buf
[ UIO_SIZEOF(1) ];
4130 struct vnode_attr attr
, va
, *vap
= &va
;
4131 int len
, nlen
, rem
, xfer
, error
, attrerr
, gotfh
, gotattr
;
4132 int siz
, dircount
, maxcount
, fullsiz
, eofflag
, dirlen
, nentries
, isdotdot
;
4133 u_quad_t off
, toff
, verf
;
4135 struct nfsm_chain
*nmreq
, nmrep
;
4140 nmreq
= &nd
->nd_nmreq
;
4141 nfsm_chain_null(&nmrep
);
4144 dircount
= maxcount
= 0;
4146 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
4148 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, dnfh
.nfh_fhp
, dnfh
.nfh_len
);
4149 nfsm_chain_get_64(error
, nmreq
, toff
);
4150 nfsm_chain_get_64(error
, nmreq
, verf
);
4151 nfsm_chain_get_32(error
, nmreq
, dircount
);
4152 nfsm_chain_get_32(error
, nmreq
, maxcount
);
4156 xfer
= NFSRV_NDMAXDATA(nd
);
4157 dircount
= ((dircount
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
4158 if (dircount
> xfer
)
4160 fullsiz
= siz
= dircount
;
4161 maxcount
= ((maxcount
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
4162 if (maxcount
> xfer
)
4165 error
= nfsrv_fhtovp(&dnfh
, nd
, &vp
, &nx
, &nxo
);
4168 /* update export stats */
4169 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4171 /* update active user stats */
4172 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4174 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4177 if (nxo
->nxo_flags
& NX_32BITCLIENTS
)
4178 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
4180 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4181 error
= attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4182 if (!error
&& toff
&& verf
&& (verf
!= attr
.va_filerev
))
4183 error
= NFSERR_BAD_COOKIE
;
4185 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, ctx
, nxo
, 0);
4188 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
4190 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
4191 &uio_buf
[0], sizeof(uio_buf
));
4192 if (!rbuf
|| !auio
) {
4198 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
4199 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
4201 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, ctx
);
4202 off
= uio_offset(auio
);
4203 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4204 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4207 if (uio_resid(auio
) != 0) {
4208 siz
-= uio_resid(auio
);
4210 /* If nothing read, return empty reply with eof set */
4215 /* assemble reply */
4216 nd
->nd_repstat
= error
;
4217 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3POSTOPATTR
+
4218 NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
);
4220 *mrepp
= nmrep
.nmc_mhead
;
4221 nfsmout_on_status(nd
, error
);
4222 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4223 nfsm_chain_add_64(error
, &nmrep
, attr
.va_filerev
);
4224 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4225 nfsm_chain_add_32(error
, &nmrep
, TRUE
);
4226 nfsm_chain_build_done(error
, &nmrep
);
4232 * Check for degenerate cases of nothing useful read.
4233 * If so go try again
4237 dp
= (struct direntry
*)cpos
;
4238 while ((dp
->d_fileno
== 0) && (cpos
< cend
) && (nentries
> 0)) {
4239 cpos
+= dp
->d_reclen
;
4240 dp
= (struct direntry
*)cpos
;
4243 if ((cpos
>= cend
) || (nentries
== 0)) {
4250 * Probe one of the directory entries to see if the filesystem
4253 if ((error
= VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, ctx
))) {
4254 if (error
== ENOTSUP
) /* let others get passed back */
4255 error
= NFSERR_NOTSUPP
;
4260 /* assemble reply */
4261 nd
->nd_repstat
= error
;
4262 error
= nfsrv_rephead(nd
, slp
, &nmrep
, maxcount
);
4264 *mrepp
= nmrep
.nmc_mhead
;
4265 nfsmout_on_status(nd
, error
);
4266 nmrep
.nmc_flags
|= NFSM_CHAIN_FLAG_ADD_CLUSTERS
;
4268 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
4269 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4270 nfsm_chain_add_64(error
, &nmrep
, attr
.va_filerev
);
4273 /* Loop through the records and build reply */
4274 while ((cpos
< cend
) && (nentries
> 0)) {
4275 if (dp
->d_fileno
!= 0) {
4276 nlen
= dp
->d_namlen
;
4277 rem
= nfsm_rndup(nlen
)-nlen
;
4278 gotfh
= gotattr
= 1;
4280 /* Got to get the vnode for lookup per entry. */
4281 if (VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, ctx
)) {
4282 /* Can't get the vnode... so no fh or attrs */
4283 gotfh
= gotattr
= 0;
4285 isdotdot
= ((dp
->d_namlen
== 2) &&
4286 (dp
->d_name
[0] == '.') && (dp
->d_name
[1] == '.'));
4287 if (nfsrv_vptofh(nx
, 0, (isdotdot
? &dnfh
: NULL
), nvp
, ctx
, &nfh
))
4289 nfsm_srv_vattr_init(vap
, NFS_VER3
);
4290 if (vnode_getattr(nvp
, vap
, ctx
))
4296 * If either the dircount or maxcount will be
4297 * exceeded, get out now. Both of these lengths
4298 * are calculated conservatively, including all
4301 len
+= 8 * NFSX_UNSIGNED
+ nlen
+ rem
;
4303 len
+= NFSX_V3FATTR
;
4305 len
+= NFSX_UNSIGNED
+ nfsm_rndup(nfh
.nfh_len
);
4306 dirlen
+= 6 * NFSX_UNSIGNED
+ nlen
+ rem
;
4307 if ((len
> maxcount
) || (dirlen
> dircount
)) {
4312 /* Build the directory record xdr from the direntry. */
4313 nfsm_chain_add_32(error
, &nmrep
, TRUE
);
4314 nfsm_chain_add_64(error
, &nmrep
, dp
->d_fileno
);
4315 nfsm_chain_add_string(error
, &nmrep
, dp
->d_name
, nlen
);
4316 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
4317 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
4318 nfsm_chain_add_64(error
, &nmrep
, dp
->d_seekoff
);
4319 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, (gotattr
? 0 : ENOENT
), vap
);
4321 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4323 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4326 cpos
+= dp
->d_reclen
;
4327 dp
= (struct direntry
*)cpos
;
4332 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4333 nfsm_chain_add_32(error
, &nmrep
, eofflag
? TRUE
: FALSE
);
4339 nd
->nd_repstat
= error
;
4340 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3POSTOPATTR
);
4342 *mrepp
= nmrep
.nmc_mhead
;
4343 nfsmout_on_status(nd
, error
);
4344 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4346 nfsm_chain_build_done(error
, &nmrep
);
4350 nfsm_chain_cleanup(&nmrep
);
4357 * nfs commit service
4361 struct nfsrv_descript
*nd
,
4362 struct nfsrv_sock
*slp
,
4367 struct nfs_filehandle nfh
;
4368 struct nfs_export
*nx
;
4369 struct nfs_export_options
*nxo
;
4370 int error
, preattrerr
, postattrerr
, count
;
4371 struct vnode_attr preattr
, postattr
;
4373 struct nfsm_chain
*nmreq
, nmrep
;
4376 preattrerr
= postattrerr
= ENOENT
;
4377 nmreq
= &nd
->nd_nmreq
;
4378 nfsm_chain_null(&nmrep
);
4382 * XXX At this time VNOP_FSYNC() does not accept offset and byte
4383 * count parameters, so those arguments are useless (someday maybe).
4386 nfsm_chain_get_fh_ptr(error
, nmreq
, NFS_VER3
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4387 nfsm_chain_get_64(error
, nmreq
, off
);
4388 nfsm_chain_get_32(error
, nmreq
, count
);
4391 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4394 /* update export stats */
4395 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4397 /* update active user stats */
4398 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4400 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4403 nfsm_srv_pre_vattr_init(&preattr
);
4404 preattrerr
= vnode_getattr(vp
, &preattr
, ctx
);
4406 error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
);
4408 nfsm_srv_vattr_init(&postattr
, 1);
4409 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
4415 /* assemble reply */
4416 nd
->nd_repstat
= error
;
4417 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
4419 *mrepp
= nmrep
.nmc_mhead
;
4420 nfsmout_on_status(nd
, error
);
4421 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
4422 preattrerr
, &preattr
, postattrerr
, &postattr
);
4423 if (!nd
->nd_repstat
) {
4424 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_sec
);
4425 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_usec
);
4428 nfsm_chain_build_done(error
, &nmrep
);
4430 nfsm_chain_cleanup(&nmrep
);
4437 * nfs statfs service
4441 struct nfsrv_descript
*nd
,
4442 struct nfsrv_sock
*slp
,
4449 struct vnode_attr attr
;
4450 struct nfs_filehandle nfh
;
4451 struct nfs_export
*nx
;
4452 struct nfs_export_options
*nxo
;
4454 struct nfsm_chain
*nmreq
, nmrep
;
4458 nmreq
= &nd
->nd_nmreq
;
4459 nfsm_chain_null(&nmrep
);
4463 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4465 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4468 /* update export stats */
4469 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4471 /* update active user stats */
4472 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4474 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4478 VFSATTR_WANTED(&va
, f_blocks
);
4479 VFSATTR_WANTED(&va
, f_bavail
);
4480 VFSATTR_WANTED(&va
, f_files
);
4481 VFSATTR_WANTED(&va
, f_ffree
);
4482 error
= vfs_getattr(vnode_mount(vp
), &va
, ctx
);
4483 blksize
= vnode_mount(vp
)->mnt_vfsstat
.f_bsize
;
4485 if (nd
->nd_vers
== NFS_VER3
) {
4486 nfsm_srv_vattr_init(&attr
, nd
->nd_vers
);
4487 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4494 /* assemble reply */
4495 nd
->nd_repstat
= error
;
4496 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_STATFS(nd
->nd_vers
));
4498 *mrepp
= nmrep
.nmc_mhead
;
4499 nfsmout_on_status(nd
, error
);
4500 if (nd
->nd_vers
== NFS_VER3
)
4501 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4502 nfsmout_if(nd
->nd_repstat
);
4504 if (nd
->nd_vers
== NFS_VER3
) {
4505 nfsm_chain_add_64(error
, &nmrep
, va
.f_blocks
* blksize
);
4506 nfsm_chain_add_64(error
, &nmrep
, va
.f_bfree
* blksize
);
4507 nfsm_chain_add_64(error
, &nmrep
, va
.f_bavail
* blksize
);
4508 nfsm_chain_add_64(error
, &nmrep
, va
.f_files
);
4509 nfsm_chain_add_64(error
, &nmrep
, va
.f_ffree
);
4510 nfsm_chain_add_64(error
, &nmrep
, va
.f_ffree
);
4511 nfsm_chain_add_32(error
, &nmrep
, 0); /* invarsec */
4513 nfsm_chain_add_32(error
, &nmrep
, NFS_V2MAXDATA
);
4514 nfsm_chain_add_32(error
, &nmrep
, blksize
);
4515 nfsm_chain_add_32(error
, &nmrep
, va
.f_blocks
);
4516 nfsm_chain_add_32(error
, &nmrep
, va
.f_bfree
);
4517 nfsm_chain_add_32(error
, &nmrep
, va
.f_bavail
);
4520 nfsm_chain_build_done(error
, &nmrep
);
4522 nfsm_chain_cleanup(&nmrep
);
4529 * nfs fsinfo service
4533 struct nfsrv_descript
*nd
,
4534 struct nfsrv_sock
*slp
,
4538 int error
, attrerr
, prefsize
, maxsize
;
4540 struct vnode_attr attr
;
4541 struct nfs_filehandle nfh
;
4542 struct nfs_export
*nx
;
4543 struct nfs_export_options
*nxo
;
4544 struct nfsm_chain
*nmreq
, nmrep
;
4548 nmreq
= &nd
->nd_nmreq
;
4549 nfsm_chain_null(&nmrep
);
4552 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4554 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4557 /* update export stats */
4558 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4560 /* update active user stats */
4561 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4563 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4566 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4567 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4573 /* assemble reply */
4574 nd
->nd_repstat
= error
;
4575 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
4577 *mrepp
= nmrep
.nmc_mhead
;
4578 nfsmout_on_status(nd
, error
);
4579 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4580 nfsmout_if(nd
->nd_repstat
);
4583 * XXX There should be file system VFS OP(s) to get this information.
4584 * For now, assume our usual NFS defaults.
4586 if (slp
->ns_sotype
== SOCK_DGRAM
) {
4587 maxsize
= NFS_MAXDGRAMDATA
;
4588 prefsize
= NFS_PREFDGRAMDATA
;
4590 maxsize
= prefsize
= NFSRV_MAXDATA
;
4592 nfsm_chain_add_32(error
, &nmrep
, maxsize
);
4593 nfsm_chain_add_32(error
, &nmrep
, prefsize
);
4594 nfsm_chain_add_32(error
, &nmrep
, NFS_FABLKSIZE
);
4595 nfsm_chain_add_32(error
, &nmrep
, maxsize
);
4596 nfsm_chain_add_32(error
, &nmrep
, prefsize
);
4597 nfsm_chain_add_32(error
, &nmrep
, NFS_FABLKSIZE
);
4598 nfsm_chain_add_32(error
, &nmrep
, prefsize
);
4599 nfsm_chain_add_64(error
, &nmrep
, 0xffffffffffffffffULL
);
4600 nfsm_chain_add_32(error
, &nmrep
, 0);
4601 nfsm_chain_add_32(error
, &nmrep
, 1);
4602 /* XXX link/symlink support should be taken from volume capabilities */
4603 nfsm_chain_add_32(error
, &nmrep
,
4604 NFSV3FSINFO_LINK
| NFSV3FSINFO_SYMLINK
|
4605 NFSV3FSINFO_HOMOGENEOUS
| NFSV3FSINFO_CANSETTIME
);
4608 nfsm_chain_build_done(error
, &nmrep
);
4610 nfsm_chain_cleanup(&nmrep
);
4617 * nfs pathconf service
4621 struct nfsrv_descript
*nd
,
4622 struct nfsrv_sock
*slp
,
4626 int error
, attrerr
, linkmax
, namemax
;
4627 int chownres
, notrunc
, case_sensitive
, case_preserving
;
4629 struct vnode_attr attr
;
4630 struct nfs_filehandle nfh
;
4631 struct nfs_export
*nx
;
4632 struct nfs_export_options
*nxo
;
4633 struct nfsm_chain
*nmreq
, nmrep
;
4637 nmreq
= &nd
->nd_nmreq
;
4638 nfsm_chain_null(&nmrep
);
4641 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4643 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4646 /* update export stats */
4647 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4649 /* update active user stats */
4650 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4652 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4655 error
= VNOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
, ctx
);
4657 error
= VNOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
, ctx
);
4659 error
= VNOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
, ctx
);
4661 error
= VNOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
, ctx
);
4663 error
= VNOP_PATHCONF(vp
, _PC_CASE_SENSITIVE
, &case_sensitive
, ctx
);
4665 error
= VNOP_PATHCONF(vp
, _PC_CASE_PRESERVING
, &case_preserving
, ctx
);
4667 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4668 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4674 /* assemble reply */
4675 nd
->nd_repstat
= error
;
4676 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
4678 *mrepp
= nmrep
.nmc_mhead
;
4679 nfsmout_on_status(nd
, error
);
4680 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4681 nfsmout_if(nd
->nd_repstat
);
4683 nfsm_chain_add_32(error
, &nmrep
, linkmax
);
4684 nfsm_chain_add_32(error
, &nmrep
, namemax
);
4685 nfsm_chain_add_32(error
, &nmrep
, notrunc
);
4686 nfsm_chain_add_32(error
, &nmrep
, chownres
);
4687 nfsm_chain_add_32(error
, &nmrep
, !case_sensitive
);
4688 nfsm_chain_add_32(error
, &nmrep
, case_preserving
);
4691 nfsm_chain_build_done(error
, &nmrep
);
4693 nfsm_chain_cleanup(&nmrep
);
4700 * Null operation, used by clients to ping server
4705 struct nfsrv_descript
*nd
,
4706 struct nfsrv_sock
*slp
,
4707 __unused vfs_context_t ctx
,
4710 int error
= NFSERR_RETVOID
;
4711 struct nfsm_chain nmrep
;
4714 * RPCSEC_GSS context setup ?
4716 if (nd
->nd_gss_context
)
4717 return(nfs_gss_svc_ctx_init(nd
, slp
, mrepp
));
4719 nfsm_chain_null(&nmrep
);
4721 /* assemble reply */
4722 nd
->nd_repstat
= error
;
4723 error
= nfsrv_rephead(nd
, slp
, &nmrep
, 0);
4725 *mrepp
= nmrep
.nmc_mhead
;
4727 nfsm_chain_build_done(error
, &nmrep
);
4729 nfsm_chain_cleanup(&nmrep
);
4736 * No operation, used for obsolete procedures
4741 struct nfsrv_descript
*nd
,
4742 struct nfsrv_sock
*slp
,
4743 __unused vfs_context_t ctx
,
4747 struct nfsm_chain nmrep
;
4749 nfsm_chain_null(&nmrep
);
4752 error
= nd
->nd_repstat
;
4754 error
= EPROCUNAVAIL
;
4756 /* assemble reply */
4757 nd
->nd_repstat
= error
;
4758 error
= nfsrv_rephead(nd
, slp
, &nmrep
, 0);
4760 *mrepp
= nmrep
.nmc_mhead
;
4762 nfsm_chain_build_done(error
, &nmrep
);
4764 nfsm_chain_cleanup(&nmrep
);
4770 int (*nfsrv_procs
[NFS_NPROCS
])(struct nfsrv_descript
*nd
,
4771 struct nfsrv_sock
*slp
,
4800 * Perform access checking for vnodes obtained from file handles that would
4801 * refer to files already opened by a Unix client. You cannot just use
4802 * vnode_authorize() for two reasons.
4803 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4804 * 2 - The owner is to be given access irrespective of mode bits so that
4805 * processes that chmod after opening a file don't break. I don't like
4806 * this because it opens a security hole, but since the nfs server opens
4807 * a security hole the size of a barn door anyhow, what the heck.
4809 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, vnode_authorize()
4810 * will return EPERM instead of EACCESS. EPERM is always an error.
4817 kauth_action_t action
,
4819 struct nfs_export_options
*nxo
,
4822 struct vnode_attr vattr
;
4825 if (action
& KAUTH_VNODE_WRITE_RIGHTS
) {
4827 * Disallow write attempts on read-only exports;
4828 * unless the file is a socket or a block or character
4829 * device resident on the file system.
4831 if (nxo
->nxo_flags
& NX_READONLY
) {
4832 switch (vnode_vtype(vp
)) {
4833 case VREG
: case VDIR
: case VLNK
: case VCPLX
:
4840 error
= vnode_authorize(vp
, dvp
, action
, ctx
);
4842 * Allow certain operations for the owner (reads and writes
4843 * on files that are already open). Picking up from FreeBSD.
4845 if (override
&& (error
== EACCES
)) {
4847 VATTR_WANTED(&vattr
, va_uid
);
4848 if ((vnode_getattr(vp
, &vattr
, ctx
) == 0) &&
4849 (kauth_cred_getuid(vfs_context_ucred(ctx
)) == vattr
.va_uid
))
4855 #endif /* NFSSERVER */