2 * Copyright (c) 2000-2011 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 <netinet/in.h>
94 #include <nfs/nfsproto.h>
95 #include <nfs/rpcv2.h>
97 #include <nfs/xdr_subs.h>
98 #include <nfs/nfsm_subs.h>
99 #include <nfs/nfsrvcache.h>
100 #include <nfs/nfs_gss.h>
108 int nfsd_thread_count
= 0;
109 int nfsd_thread_max
= 0;
110 lck_grp_t
*nfsd_lck_grp
;
111 lck_mtx_t
*nfsd_mutex
;
112 struct nfsd_head nfsd_head
, nfsd_queue
;
114 lck_grp_t
*nfsrv_slp_rwlock_group
;
115 lck_grp_t
*nfsrv_slp_mutex_group
;
116 struct nfsrv_sockhead nfsrv_socklist
, nfsrv_deadsocklist
, nfsrv_sockwg
,
117 nfsrv_sockwait
, nfsrv_sockwork
;
118 struct nfsrv_sock
*nfsrv_udpsock
= NULL
;
119 struct nfsrv_sock
*nfsrv_udp6sock
= NULL
;
122 struct nfsrv_expfs_list nfsrv_exports
;
123 struct nfsrv_export_hashhead
*nfsrv_export_hashtbl
= NULL
;
124 int nfsrv_export_hash_size
= NFSRVEXPHASHSZ
;
125 u_long nfsrv_export_hash
;
126 lck_grp_t
*nfsrv_export_rwlock_group
;
127 lck_rw_t nfsrv_export_rwlock
;
130 /* NFS server file modification event generator */
131 struct nfsrv_fmod_hashhead
*nfsrv_fmod_hashtbl
;
132 u_long nfsrv_fmod_hash
;
133 lck_grp_t
*nfsrv_fmod_grp
;
134 lck_mtx_t
*nfsrv_fmod_mutex
;
135 static int nfsrv_fmod_timer_on
= 0;
136 int nfsrv_fsevents_enabled
= 1;
139 /* NFS server timers */
141 thread_call_t nfsrv_fmod_timer_call
;
143 thread_call_t nfsrv_deadsock_timer_call
;
144 thread_call_t nfsrv_wg_timer_call
;
145 int nfsrv_wg_timer_on
;
147 /* globals for the active user list */
148 uint32_t nfsrv_user_stat_enabled
= 1;
149 uint32_t nfsrv_user_stat_node_count
= 0;
150 uint32_t nfsrv_user_stat_max_idle_sec
= NFSRV_USER_STAT_DEF_IDLE_SEC
;
151 uint32_t nfsrv_user_stat_max_nodes
= NFSRV_USER_STAT_DEF_MAX_NODES
;
152 lck_grp_t
*nfsrv_active_user_mutex_group
;
154 int nfsrv_wg_delay
= NFSRV_WGATHERDELAY
* 1000;
155 int nfsrv_wg_delay_v3
= 0;
159 int nfsrv_authorize(vnode_t
,vnode_t
,kauth_action_t
,vfs_context_t
,struct nfs_export_options
*,int);
160 int nfsrv_wg_coalesce(struct nfsrv_descript
*, struct nfsrv_descript
*);
161 void nfsrv_modified(vnode_t
, vfs_context_t
);
163 extern void IOSleep(int);
164 extern int safe_getpath(struct vnode
*dvp
, char *leafname
, char *path
, int _len
, int *truncated_path
);
167 * Initialize the data structures for the server.
170 #define NFSRV_NOT_INITIALIZED 0
171 #define NFSRV_INITIALIZING 1
172 #define NFSRV_INITIALIZED 2
173 static volatile UInt32 nfsrv_initted
= NFSRV_NOT_INITIALIZED
;
176 nfsrv_is_initialized(void)
178 return (nfsrv_initted
== NFSRV_INITIALIZED
);
184 /* make sure we init only once */
185 if (!OSCompareAndSwap(NFSRV_NOT_INITIALIZED
, NFSRV_INITIALIZING
, &nfsrv_initted
)) {
186 /* wait until initialization is complete */
187 while (!nfsrv_is_initialized())
192 if (sizeof (struct nfsrv_sock
) > NFS_SVCALLOC
)
193 printf("struct nfsrv_sock bloated (> %dbytes)\n",NFS_SVCALLOC
);
195 /* init nfsd mutex */
196 nfsd_lck_grp
= lck_grp_alloc_init("nfsd", LCK_GRP_ATTR_NULL
);
197 nfsd_mutex
= lck_mtx_alloc_init(nfsd_lck_grp
, LCK_ATTR_NULL
);
199 /* init slp rwlock */
200 nfsrv_slp_rwlock_group
= lck_grp_alloc_init("nfsrv-slp-rwlock", LCK_GRP_ATTR_NULL
);
201 nfsrv_slp_mutex_group
= lck_grp_alloc_init("nfsrv-slp-mutex", LCK_GRP_ATTR_NULL
);
203 /* init export data structures */
204 LIST_INIT(&nfsrv_exports
);
205 nfsrv_export_rwlock_group
= lck_grp_alloc_init("nfsrv-export-rwlock", LCK_GRP_ATTR_NULL
);
206 lck_rw_init(&nfsrv_export_rwlock
, nfsrv_export_rwlock_group
, LCK_ATTR_NULL
);
208 /* init active user list mutex structures */
209 nfsrv_active_user_mutex_group
= lck_grp_alloc_init("nfs-active-user-mutex", LCK_GRP_ATTR_NULL
);
211 /* init nfs server request cache mutex */
212 nfsrv_reqcache_lck_grp
= lck_grp_alloc_init("nfsrv_reqcache", LCK_GRP_ATTR_NULL
);
213 nfsrv_reqcache_mutex
= lck_mtx_alloc_init(nfsrv_reqcache_lck_grp
, LCK_ATTR_NULL
);
216 /* init NFS server file modified event generation */
217 nfsrv_fmod_hashtbl
= hashinit(NFSRVFMODHASHSZ
, M_TEMP
, &nfsrv_fmod_hash
);
218 nfsrv_fmod_grp
= lck_grp_alloc_init("nfsrv_fmod", LCK_GRP_ATTR_NULL
);
219 nfsrv_fmod_mutex
= lck_mtx_alloc_init(nfsrv_fmod_grp
, LCK_ATTR_NULL
);
222 /* initialize NFS server timer callouts */
224 nfsrv_fmod_timer_call
= thread_call_allocate(nfsrv_fmod_timer
, NULL
);
226 nfsrv_deadsock_timer_call
= thread_call_allocate(nfsrv_deadsock_timer
, NULL
);
227 nfsrv_wg_timer_call
= thread_call_allocate(nfsrv_wg_timer
, NULL
);
229 /* Init server data structures */
230 TAILQ_INIT(&nfsrv_socklist
);
231 TAILQ_INIT(&nfsrv_sockwait
);
232 TAILQ_INIT(&nfsrv_sockwork
);
233 TAILQ_INIT(&nfsrv_deadsocklist
);
234 TAILQ_INIT(&nfsrv_sockwg
);
235 TAILQ_INIT(&nfsd_head
);
236 TAILQ_INIT(&nfsd_queue
);
237 nfsrv_udpsock
= NULL
;
238 nfsrv_udp6sock
= NULL
;
240 /* Setup the up-call handling */
243 /* initialization complete */
244 nfsrv_initted
= NFSRV_INITIALIZED
;
250 * NFS version 2 and 3 server request processing functions
252 * These functions take the following parameters:
254 * struct nfsrv_descript *nd - the NFS request descriptor
255 * struct nfsrv_sock *slp - the NFS socket the request came in on
256 * vfs_context_t ctx - VFS context
257 * mbuf_t *mrepp - pointer to hold the reply mbuf list
259 * These routines generally have 3 phases:
261 * 1 - break down and validate the RPC request in the mbuf chain
262 * provided in nd->nd_nmreq.
263 * 2 - perform the vnode operations for the request
264 * (many are very similar to syscalls in vfs_syscalls.c and
265 * should therefore be kept in sync with those implementations)
266 * 3 - build the RPC reply in an mbuf chain (nmrep) and return the mbuf chain
271 * nfs v3 access service
275 struct nfsrv_descript
*nd
,
276 struct nfsrv_sock
*slp
,
280 struct nfsm_chain
*nmreq
, nmrep
;
283 struct vnode_attr vattr
;
284 struct nfs_filehandle nfh
;
286 kauth_action_t testaction
;
287 struct nfs_export
*nx
;
288 struct nfs_export_options
*nxo
;
293 nmreq
= &nd
->nd_nmreq
;
294 nfsm_chain_null(&nmrep
);
298 nfsm_chain_get_fh_ptr(error
, nmreq
, NFS_VER3
, nfh
.nfh_fhp
, nfh
.nfh_len
);
299 nfsm_chain_get_32(error
, nmreq
, nfsmode
);
301 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
304 /* update export stats */
305 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
307 /* update active user stats */
308 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
310 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
314 * Each NFS mode bit is tested separately.
316 * XXX this code is nominally correct, but returns a pessimistic
317 * rather than optimistic result. It will be necessary to add
318 * an NFS-specific interface to the vnode_authorize code to
319 * obtain good performance in the optimistic mode.
321 if (nfsmode
& NFS_ACCESS_READ
) {
322 testaction
= vnode_isdir(vp
) ? KAUTH_VNODE_LIST_DIRECTORY
: KAUTH_VNODE_READ_DATA
;
323 if (nfsrv_authorize(vp
, NULL
, testaction
, ctx
, nxo
, 0))
324 nfsmode
&= ~NFS_ACCESS_READ
;
326 if ((nfsmode
& NFS_ACCESS_LOOKUP
) &&
328 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, ctx
, nxo
, 0)))
329 nfsmode
&= ~NFS_ACCESS_LOOKUP
;
330 if (nfsmode
& NFS_ACCESS_MODIFY
) {
331 if (vnode_isdir(vp
)) {
333 KAUTH_VNODE_ADD_FILE
|
334 KAUTH_VNODE_ADD_SUBDIRECTORY
|
335 KAUTH_VNODE_DELETE_CHILD
;
338 KAUTH_VNODE_WRITE_DATA
;
340 if (nfsrv_authorize(vp
, NULL
, testaction
, ctx
, nxo
, 0))
341 nfsmode
&= ~NFS_ACCESS_MODIFY
;
343 if (nfsmode
& NFS_ACCESS_EXTEND
) {
344 if (vnode_isdir(vp
)) {
346 KAUTH_VNODE_ADD_FILE
|
347 KAUTH_VNODE_ADD_SUBDIRECTORY
;
350 KAUTH_VNODE_WRITE_DATA
|
351 KAUTH_VNODE_APPEND_DATA
;
353 if (nfsrv_authorize(vp
, NULL
, testaction
, ctx
, nxo
, 0))
354 nfsmode
&= ~NFS_ACCESS_EXTEND
;
358 * Note concerning NFS_ACCESS_DELETE:
359 * For hard links, the answer may be wrong if the vnode
360 * has multiple parents with different permissions.
361 * Also, some clients (e.g. MacOSX 10.3) may incorrectly
362 * interpret the missing/cleared DELETE bit.
363 * So we'll just leave the DELETE bit alone. At worst,
364 * we're telling the client it might be able to do
365 * something it really can't.
368 if ((nfsmode
& NFS_ACCESS_EXECUTE
) &&
370 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, ctx
, nxo
, 0)))
371 nfsmode
&= ~NFS_ACCESS_EXECUTE
;
373 /* get postop attributes */
374 nfsm_srv_vattr_init(&vattr
, NFS_VER3
);
375 attrerr
= vnode_getattr(vp
, &vattr
, ctx
);
379 nd
->nd_repstat
= error
;
380 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(NFS_VER3
) + NFSX_UNSIGNED
);
382 *mrepp
= nmrep
.nmc_mhead
;
383 nfsmout_on_status(nd
, error
);
384 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &vattr
);
386 nfsm_chain_add_32(error
, &nmrep
, nfsmode
);
388 nfsm_chain_build_done(error
, &nmrep
);
392 nfsm_chain_cleanup(&nmrep
);
399 * nfs getattr service
403 struct nfsrv_descript
*nd
,
404 struct nfsrv_sock
*slp
,
408 struct nfsm_chain
*nmreq
, nmrep
;
409 struct vnode_attr vattr
;
412 struct nfs_filehandle nfh
;
413 struct nfs_export
*nx
;
414 struct nfs_export_options
*nxo
;
417 nmreq
= &nd
->nd_nmreq
;
418 nfsm_chain_null(&nmrep
);
422 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
424 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
427 /* update export stats */
428 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
430 /* update active user stats */
431 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
433 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
436 nfsm_srv_vattr_init(&vattr
, nd
->nd_vers
);
437 error
= vnode_getattr(vp
, &vattr
, ctx
);
443 nd
->nd_repstat
= error
;
444 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_FATTR(nd
->nd_vers
));
446 *mrepp
= nmrep
.nmc_mhead
;
447 nfsmout_if(nd
->nd_repstat
);
448 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &vattr
);
450 nfsm_chain_build_done(error
, &nmrep
);
454 nfsm_chain_cleanup(&nmrep
);
461 * nfs setattr service
465 struct nfsrv_descript
*nd
,
466 struct nfsrv_sock
*slp
,
470 struct nfsm_chain
*nmreq
, nmrep
;
471 struct vnode_attr preattr
, postattr
;
472 struct vnode_attr vattr
, *vap
= &vattr
;
474 struct nfs_export
*nx
;
475 struct nfs_export_options
*nxo
;
476 int error
, preattrerr
, postattrerr
, gcheck
;
477 struct nfs_filehandle nfh
;
478 struct timespec guard
= { 0, 0 };
479 kauth_action_t action
;
483 preattrerr
= postattrerr
= ENOENT
;
485 nmreq
= &nd
->nd_nmreq
;
486 nfsm_chain_null(&nmrep
);
490 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
494 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
495 if (nd
->nd_vers
== NFS_VER3
) {
496 nfsm_chain_get_32(error
, nmreq
, gcheck
);
498 nfsm_chain_get_time(error
, nmreq
, nd
->nd_vers
, guard
.tv_sec
, guard
.tv_nsec
);
503 * Save the original credential UID in case they are
504 * mapped and we need to map the IDs in the attributes.
506 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
509 * Now that we have all the fields, lets do it.
511 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
514 /* update export stats */
515 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
517 /* update active user stats */
518 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
520 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
523 if (nd
->nd_vers
== NFS_VER3
) {
524 nfsm_srv_pre_vattr_init(&preattr
);
525 error
= preattrerr
= vnode_getattr(vp
, &preattr
, ctx
);
526 if (!error
&& gcheck
&& VATTR_IS_SUPPORTED(&preattr
, va_change_time
) &&
527 (preattr
.va_change_time
.tv_sec
!= guard
.tv_sec
||
528 preattr
.va_change_time
.tv_nsec
!= guard
.tv_nsec
))
529 error
= NFSERR_NOT_SYNC
;
530 if (!preattrerr
&& !VATTR_ALL_SUPPORTED(&preattr
))
536 * If the credentials were mapped, we should
537 * map the same values in the attributes.
539 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nd
->nd_cr
) != saved_uid
)) {
541 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nd
->nd_cr
));
542 if (kauth_cred_ismember_gid(nd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
543 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nd
->nd_cr
));
546 /* Authorize the attribute changes. */
547 error
= vnode_authattr(vp
, vap
, &action
, ctx
);
549 error
= nfsrv_authorize(vp
, NULL
, action
, ctx
, nxo
, 0);
551 /* set the new attributes */
553 error
= vnode_setattr(vp
, vap
, ctx
);
555 if (!error
|| (nd
->nd_vers
== NFS_VER3
)) {
556 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
557 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
567 nd
->nd_repstat
= error
;
568 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCORFATTR(nd
->nd_vers
));
570 *mrepp
= nmrep
.nmc_mhead
;
571 nfsmout_on_status(nd
, error
);
572 if (nd
->nd_vers
== NFS_VER3
)
573 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
574 preattrerr
, &preattr
, postattrerr
, &postattr
);
576 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
578 nfsm_chain_build_done(error
, &nmrep
);
580 nfsm_chain_cleanup(&nmrep
);
591 struct nfsrv_descript
*nd
,
592 struct nfsrv_sock
*slp
,
597 vnode_t vp
, dirp
= NULL
;
598 struct nfs_filehandle dnfh
, nfh
;
599 struct nfs_export
*nx
= NULL
;
600 struct nfs_export_options
*nxo
;
601 int error
, attrerr
, dirattrerr
, isdotdot
;
604 struct vnode_attr va
, dirattr
, *vap
= &va
;
605 struct nfsm_chain
*nmreq
, nmrep
;
608 attrerr
= dirattrerr
= ENOENT
;
609 nmreq
= &nd
->nd_nmreq
;
610 nfsm_chain_null(&nmrep
);
611 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
613 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, dnfh
.nfh_fhp
, dnfh
.nfh_len
);
614 nfsm_chain_get_32(error
, nmreq
, len
);
615 nfsm_name_len_check(error
, nd
, len
);
618 ni
.ni_cnd
.cn_nameiop
= LOOKUP
;
620 ni
.ni_op
= OP_LOOKUP
;
622 ni
.ni_cnd
.cn_flags
= LOCKLEAF
;
623 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
624 isdotdot
= ((len
== 2) && (ni
.ni_cnd
.cn_pnbuf
[0] == '.') && (ni
.ni_cnd
.cn_pnbuf
[1] == '.'));
626 error
= nfsrv_namei(nd
, ctx
, &ni
, &dnfh
, &dirp
, &nx
, &nxo
);
628 /* update export stats */
629 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
631 /* update active user stats */
632 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
637 if (nd
->nd_vers
== NFS_VER3
) {
638 nfsm_srv_vattr_init(&dirattr
, NFS_VER3
);
639 dirattrerr
= vnode_getattr(dirp
, &dirattr
, ctx
);
648 error
= nfsrv_vptofh(nx
, nd
->nd_vers
, (isdotdot
? &dnfh
: NULL
), vp
, ctx
, &nfh
);
650 nfsm_srv_vattr_init(vap
, nd
->nd_vers
);
651 attrerr
= vnode_getattr(vp
, vap
, ctx
);
657 nd
->nd_repstat
= error
;
658 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(nd
->nd_vers
, &nfh
) +
659 NFSX_POSTOPORFATTR(nd
->nd_vers
) + NFSX_POSTOPATTR(nd
->nd_vers
));
661 *mrepp
= nmrep
.nmc_mhead
;
662 if (nd
->nd_repstat
) {
663 if (nd
->nd_vers
== NFS_VER3
)
664 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, dirattrerr
, &dirattr
);
667 nfsm_chain_add_fh(error
, &nmrep
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
668 if (nd
->nd_vers
== NFS_VER3
) {
669 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, vap
);
670 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, dirattrerr
, &dirattr
);
672 error
= nfsm_chain_add_fattr(nd
, &nmrep
, vap
);
675 nfsm_chain_build_done(error
, &nmrep
);
677 nfsm_chain_cleanup(&nmrep
);
684 * nfs readlink service
688 struct nfsrv_descript
*nd
,
689 struct nfsrv_sock
*slp
,
693 int error
, mpcnt
, tlen
, len
, attrerr
;
695 struct vnode_attr vattr
;
696 struct nfs_filehandle nfh
;
697 struct nfs_export
*nx
;
698 struct nfs_export_options
*nxo
;
699 struct nfsm_chain
*nmreq
, nmrep
;
702 char uio_buf
[ UIO_SIZEOF(4) ];
703 char *uio_bufp
= &uio_buf
[0];
704 int uio_buflen
= UIO_SIZEOF(4);
708 nmreq
= &nd
->nd_nmreq
;
709 nfsm_chain_null(&nmrep
);
712 len
= NFS_MAXPATHLEN
;
714 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
717 /* get mbuf list to hold symlink path */
718 error
= nfsm_mbuf_get_list(len
, &mpath
, &mpcnt
);
721 uio_buflen
= UIO_SIZEOF(mpcnt
);
722 MALLOC(uio_bufp
, char*, uio_buflen
, M_TEMP
, M_WAITOK
);
727 auio
= uio_createwithbuffer(mpcnt
, 0, UIO_SYSSPACE
, UIO_READ
, uio_bufp
, uio_buflen
);
732 for (mp
= mpath
; mp
; mp
= mbuf_next(mp
))
733 uio_addiov(auio
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), mbuf_len(mp
));
735 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
738 /* update export stats */
739 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
741 /* update active user stats */
742 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
744 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
747 if (vnode_vtype(vp
) != VLNK
) {
748 if (nd
->nd_vers
== NFS_VER3
)
755 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, ctx
, nxo
, 0);
757 error
= VNOP_READLINK(vp
, auio
, ctx
);
759 if (nd
->nd_vers
== NFS_VER3
) {
760 nfsm_srv_vattr_init(&vattr
, NFS_VER3
);
761 attrerr
= vnode_getattr(vp
, &vattr
, ctx
);
773 nd
->nd_repstat
= error
;
774 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_UNSIGNED
);
776 *mrepp
= nmrep
.nmc_mhead
;
777 nfsmout_on_status(nd
, error
);
778 if (nd
->nd_vers
== NFS_VER3
)
779 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &vattr
);
780 if (error
|| nd
->nd_repstat
) {
781 nfsm_chain_build_done(error
, &nmrep
);
784 if (auio
&& (uio_resid(auio
) > 0)) {
785 len
-= uio_resid(auio
);
786 tlen
= nfsm_rndup(len
);
787 nfsm_adj(mpath
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
789 nfsm_chain_add_32(error
, &nmrep
, len
);
790 nfsm_chain_build_done(error
, &nmrep
);
792 error
= mbuf_setnext(nmrep
.nmc_mcur
, mpath
);
800 if (uio_bufp
!= &uio_buf
[0])
801 FREE(uio_bufp
, M_TEMP
);
803 nfsm_chain_cleanup(&nmrep
);
814 struct nfsrv_descript
*nd
,
815 struct nfsrv_sock
*slp
,
819 int error
, attrerr
, mreadcnt
;
820 uint32_t reqlen
, maxlen
, count
, len
, tlen
, left
;
823 struct nfs_filehandle nfh
;
824 struct nfs_export
*nx
;
825 struct nfs_export_options
*nxo
;
827 char *uio_bufp
= NULL
;
828 struct vnode_attr vattr
, *vap
= &vattr
;
831 char uio_buf
[ UIO_SIZEOF(0) ];
832 struct nfsm_chain
*nmreq
, nmrep
;
836 nmreq
= &nd
->nd_nmreq
;
837 nfsm_chain_null(&nmrep
);
841 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
843 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
845 if (nd
->nd_vers
== NFS_VER3
)
846 nfsm_chain_get_64(error
, nmreq
, off
);
848 nfsm_chain_get_32(error
, nmreq
, off
);
849 nfsm_chain_get_32(error
, nmreq
, reqlen
);
850 maxlen
= NFSRV_NDMAXDATA(nd
);
854 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
857 /* update export stats */
858 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
860 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
863 if (vnode_vtype(vp
) != VREG
) {
864 if (nd
->nd_vers
== NFS_VER3
)
867 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
871 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, ctx
, nxo
, 1)))
872 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, ctx
, nxo
, 1);
874 nfsm_srv_vattr_init(vap
, nd
->nd_vers
);
875 attrerr
= vnode_getattr(vp
, vap
, ctx
);
880 if ((u_quad_t
)off
>= vap
->va_data_size
)
882 else if (((u_quad_t
)off
+ reqlen
) > vap
->va_data_size
)
883 count
= nfsm_rndup(vap
->va_data_size
- off
);
889 /* get mbuf list to hold read data */
890 error
= nfsm_mbuf_get_list(count
, &mread
, &mreadcnt
);
892 MALLOC(uio_bufp
, char *, UIO_SIZEOF(mreadcnt
), M_TEMP
, M_WAITOK
);
894 auio
= uio_createwithbuffer(mreadcnt
, off
, UIO_SYSSPACE
,
895 UIO_READ
, uio_bufp
, UIO_SIZEOF(mreadcnt
));
896 if (!uio_bufp
|| !auio
) {
900 for (m
= mread
; m
; m
= mbuf_next(m
))
901 uio_addiov(auio
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(m
)), mbuf_len(m
));
902 error
= VNOP_READ(vp
, auio
, IO_NODELOCKED
, ctx
);
904 auio
= uio_createwithbuffer(0, 0, UIO_SYSSPACE
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
912 if (!error
|| (nd
->nd_vers
== NFS_VER3
)) {
913 nfsm_srv_vattr_init(vap
, nd
->nd_vers
);
914 attrerr
= vnode_getattr(vp
, vap
, ctx
);
915 if (!error
&& (nd
->nd_vers
== NFS_VER2
))
916 error
= attrerr
; /* NFSv2 must have attributes to return */
923 /* trim off any data not actually read */
924 len
-= uio_resid(auio
);
925 tlen
= nfsm_rndup(len
);
926 if (count
!= tlen
|| tlen
!= len
)
927 nfsm_adj(mread
, count
- tlen
, tlen
- len
);
931 nd
->nd_repstat
= error
;
932 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPORFATTR(nd
->nd_vers
) + 3 * NFSX_UNSIGNED
);
934 *mrepp
= nmrep
.nmc_mhead
;
935 nfsmout_on_status(nd
, error
);
936 if (nd
->nd_vers
== NFS_VER3
)
937 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, vap
);
938 if (error
|| nd
->nd_repstat
) {
939 nfsm_chain_build_done(error
, &nmrep
);
942 if (nd
->nd_vers
== NFS_VER3
) {
943 nfsm_chain_add_32(error
, &nmrep
, len
);
944 nfsm_chain_add_32(error
, &nmrep
, (len
< reqlen
) ? TRUE
: FALSE
);
946 error
= nfsm_chain_add_fattr(nd
, &nmrep
, vap
);
948 nfsm_chain_add_32(error
, &nmrep
, len
);
949 nfsm_chain_build_done(error
, &nmrep
);
951 error
= mbuf_setnext(nmrep
.nmc_mcur
, mread
);
955 /* update export stats */
956 NFSStatAdd64(&nx
->nx_stats
.bytes_read
, len
);
958 /* update active user stats */
959 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, len
, 0);
965 if (uio_bufp
!= NULL
)
966 FREE(uio_bufp
, M_TEMP
);
968 nfsm_chain_cleanup(&nmrep
);
976 * NFS File modification reporting
978 * When the contents of a file are changed, a "content modified"
979 * fsevent needs to be issued. Normally this would be done at
980 * file close time. This is difficult for NFS because the protocol
981 * has no "close" operation. The client sends a stream of write
982 * requests that just stop. So we keep a hash table full of
983 * vnodes that have been written to recently, and issue a
984 * "content modified" fsevent only if there are no writes to
985 * a vnode for nfsrv_fmod_pendtime milliseconds.
987 int nfsrv_fmod_pending
; /* count of vnodes being written to */
988 int nfsrv_fmod_pendtime
= 1000; /* msec to wait */
989 int nfsrv_fmod_min_interval
= 100; /* msec min interval between callbacks */
992 * This function is called via the kernel's callout
993 * mechanism. Calls are made only when there are
994 * vnodes pending a fsevent creation, and no more
995 * frequently than every nfsrv_fmod_min_interval ms.
998 nfsrv_fmod_timer(__unused
void *param0
, __unused
void *param1
)
1000 struct nfsrv_fmod_hashhead
*headp
, firehead
;
1001 struct nfsrv_fmod
*fp
, *nfp
, *pfp
;
1002 uint64_t timenow
, next_deadline
;
1003 int interval
= 0, i
, fmod_fire
;
1005 LIST_INIT(&firehead
);
1006 lck_mtx_lock(nfsrv_fmod_mutex
);
1008 clock_get_uptime(&timenow
);
1009 clock_interval_to_deadline(nfsrv_fmod_pendtime
, 1000 * 1000,
1013 * Scan all the hash chains
1016 for (i
= 0; i
< NFSRVFMODHASHSZ
; i
++) {
1018 * For each hash chain, look for an entry
1019 * that has exceeded the deadline.
1021 headp
= &nfsrv_fmod_hashtbl
[i
];
1022 LIST_FOREACH(fp
, headp
, fm_link
) {
1023 if (timenow
>= fp
->fm_deadline
)
1025 if (fp
->fm_deadline
< next_deadline
)
1026 next_deadline
= fp
->fm_deadline
;
1030 * If we have an entry that's exceeded the
1031 * deadline, then the same is true for all
1032 * following entries in the chain, since they're
1033 * sorted in time order.
1037 /* move each entry to the fire list */
1038 nfp
= LIST_NEXT(fp
, fm_link
);
1039 LIST_REMOVE(fp
, fm_link
);
1042 LIST_INSERT_AFTER(pfp
, fp
, fm_link
);
1044 LIST_INSERT_HEAD(&firehead
, fp
, fm_link
);
1051 lck_mtx_unlock(nfsrv_fmod_mutex
);
1053 * Fire off the content modified fsevent for each
1054 * entry and free it.
1056 LIST_FOREACH_SAFE(fp
, &firehead
, fm_link
, nfp
) {
1057 if (nfsrv_fsevents_enabled
) {
1058 fp
->fm_context
.vc_thread
= current_thread();
1059 add_fsevent(FSE_CONTENT_MODIFIED
, &fp
->fm_context
,
1060 FSE_ARG_VNODE
, fp
->fm_vp
,
1063 vnode_put(fp
->fm_vp
);
1064 kauth_cred_unref(&fp
->fm_context
.vc_ucred
);
1065 LIST_REMOVE(fp
, fm_link
);
1068 lck_mtx_lock(nfsrv_fmod_mutex
);
1069 nfsrv_fmod_pending
-= fmod_fire
;
1074 * If there are still pending entries, set up another
1075 * callout to handle them later. Set the timeout deadline
1076 * so that the callout happens when the oldest pending
1077 * entry is ready to send its fsevent.
1079 if (nfsrv_fmod_pending
> 0) {
1080 interval
= (next_deadline
- timenow
) / (1000 * 1000);
1081 if (interval
< nfsrv_fmod_min_interval
)
1082 interval
= nfsrv_fmod_min_interval
;
1085 nfsrv_fmod_timer_on
= interval
> 0;
1086 if (nfsrv_fmod_timer_on
)
1087 nfs_interval_timer_start(nfsrv_fmod_timer_call
, interval
);
1089 lck_mtx_unlock(nfsrv_fmod_mutex
);
1093 * When a vnode has been written to, enter it in the hash
1094 * table of vnodes pending creation of an fsevent. If the
1095 * callout timer isn't already running, schedule a callback
1096 * for nfsrv_fmod_pendtime msec from now.
1099 nfsrv_modified(vnode_t vp
, vfs_context_t ctx
)
1102 struct nfsrv_fmod
*fp
;
1103 struct nfsrv_fmod_hashhead
*head
;
1105 lck_mtx_lock(nfsrv_fmod_mutex
);
1108 * Compute the time in the future when the
1109 * content modified fsevent is to be issued.
1111 clock_interval_to_deadline(nfsrv_fmod_pendtime
, 1000 * 1000, &deadline
);
1114 * Check if there's already a file content change fsevent
1115 * pending for this vnode. If there is, update its
1116 * timestamp and make sure it's at the front of the hash chain.
1118 head
= &nfsrv_fmod_hashtbl
[NFSRVFMODHASH(vp
)];
1119 LIST_FOREACH(fp
, head
, fm_link
) {
1120 if (vp
== fp
->fm_vp
) {
1121 fp
->fm_deadline
= deadline
;
1122 if (fp
!= LIST_FIRST(head
)) {
1123 LIST_REMOVE(fp
, fm_link
);
1124 LIST_INSERT_HEAD(head
, fp
, fm_link
);
1126 lck_mtx_unlock(nfsrv_fmod_mutex
);
1132 * First content change fsevent for this vnode.
1133 * Allocate a new file mod entry and add it
1134 * on the front of the hash chain.
1136 if (vnode_get(vp
) != 0)
1138 MALLOC(fp
, struct nfsrv_fmod
*, sizeof(*fp
), M_TEMP
, M_WAITOK
);
1144 kauth_cred_ref(vfs_context_ucred(ctx
));
1145 fp
->fm_context
= *ctx
;
1146 fp
->fm_deadline
= deadline
;
1147 LIST_INSERT_HEAD(head
, fp
, fm_link
);
1150 * If added to an empty hash table, then set the
1151 * callout timer to go off after nfsrv_fmod_pendtime.
1153 nfsrv_fmod_pending
++;
1154 if (!nfsrv_fmod_timer_on
) {
1155 nfsrv_fmod_timer_on
= 1;
1156 nfs_interval_timer_start(nfsrv_fmod_timer_call
,
1157 nfsrv_fmod_pendtime
);
1160 lck_mtx_unlock(nfsrv_fmod_mutex
);
1163 #endif /* CONFIG_FSE */
1170 struct nfsrv_descript
*nd
,
1171 struct nfsrv_sock
*slp
,
1175 struct vnode_attr preattr
, postattr
;
1176 int error
, preattrerr
, postattrerr
;
1177 int ioflags
, len
, retlen
;
1179 int stable
= NFS_WRITE_FILESYNC
;
1182 struct nfs_filehandle nfh
;
1183 struct nfs_export
*nx
;
1184 struct nfs_export_options
*nxo
;
1186 char *uio_bufp
= NULL
;
1189 struct nfsm_chain
*nmreq
, nmrep
;
1191 if (nd
->nd_nmreq
.nmc_mhead
== NULL
) {
1197 preattrerr
= postattrerr
= ENOENT
;
1198 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
1199 nmreq
= &nd
->nd_nmreq
;
1200 nfsm_chain_null(&nmrep
);
1204 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
1206 if (nd
->nd_vers
== NFS_VER3
) {
1207 nfsm_chain_get_64(error
, nmreq
, off
);
1208 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1209 nfsm_chain_get_32(error
, nmreq
, stable
);
1211 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1212 nfsm_chain_get_32(error
, nmreq
, off
);
1213 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1215 stable
= NFS_WRITE_UNSTABLE
;
1217 nfsm_chain_get_32(error
, nmreq
, len
);
1222 * For NFS Version 2, it is not obvious what a write of zero length
1223 * should do, but I might as well be consistent with Version 3,
1224 * which is to return ok so long as there are no permission problems.
1228 error
= nfsm_chain_trim_data(nmreq
, len
, &mlen
);
1233 if ((len
> NFSRV_MAXDATA
) || (len
< 0) || (mlen
< len
)) {
1237 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
1240 /* update export stats */
1241 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
1243 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
1246 if (nd
->nd_vers
== NFS_VER3
) {
1247 nfsm_srv_pre_vattr_init(&preattr
);
1248 preattrerr
= vnode_getattr(vp
, &preattr
, ctx
);
1250 if (vnode_vtype(vp
) != VREG
) {
1251 if (nd
->nd_vers
== NFS_VER3
)
1254 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1257 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, ctx
, nxo
, 1);
1261 for (mcount
=0, m
=nmreq
->nmc_mcur
; m
; m
= mbuf_next(m
))
1262 if (mbuf_len(m
) > 0)
1264 MALLOC(uio_bufp
, char *, UIO_SIZEOF(mcount
), M_TEMP
, M_WAITOK
);
1266 auio
= uio_createwithbuffer(mcount
, off
, UIO_SYSSPACE
, UIO_WRITE
, uio_bufp
, UIO_SIZEOF(mcount
));
1267 if (!uio_bufp
|| !auio
)
1270 for (m
= nmreq
->nmc_mcur
; m
; m
= mbuf_next(m
))
1271 if ((mlen
= mbuf_len(m
)) > 0)
1272 uio_addiov(auio
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(m
)), mlen
);
1274 * XXX The IO_METASYNC flag indicates that all metadata (and not just
1275 * enough to ensure data integrity) mus be written to stable storage
1276 * synchronously. (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1278 if (stable
== NFS_WRITE_UNSTABLE
)
1279 ioflags
= IO_NODELOCKED
;
1280 else if (stable
== NFS_WRITE_DATASYNC
)
1281 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1283 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1285 error
= VNOP_WRITE(vp
, auio
, ioflags
, ctx
);
1286 OSAddAtomic64(1, &nfsstats
.srvvop_writes
);
1288 /* update export stats */
1289 NFSStatAdd64(&nx
->nx_stats
.bytes_written
, len
);
1291 /* update active user stats */
1292 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, len
);
1295 if (nfsrv_fsevents_enabled
&& !error
&& need_fsevent(FSE_CONTENT_MODIFIED
, vp
))
1296 nfsrv_modified(vp
, ctx
);
1299 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
1300 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
1301 if (!error
&& (nd
->nd_vers
== NFS_VER2
))
1302 error
= postattrerr
; /* NFSv2 must have attributes to return */
1307 /* assemble reply */
1308 nd
->nd_repstat
= error
;
1309 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_PREOPATTR(nd
->nd_vers
) +
1310 NFSX_POSTOPORFATTR(nd
->nd_vers
) + 2 * NFSX_UNSIGNED
+
1311 NFSX_WRITEVERF(nd
->nd_vers
));
1313 *mrepp
= nmrep
.nmc_mhead
;
1314 nfsmout_on_status(nd
, error
);
1315 if (nd
->nd_vers
== NFS_VER3
) {
1316 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
1317 preattrerr
, &preattr
, postattrerr
, &postattr
);
1318 nfsmout_if(error
|| nd
->nd_repstat
);
1319 nfsm_chain_add_32(error
, &nmrep
, retlen
);
1320 /* If nfsrv_async is set, then pretend the write was FILESYNC. */
1321 if ((stable
== NFS_WRITE_UNSTABLE
) && !nfsrv_async
)
1322 nfsm_chain_add_32(error
, &nmrep
, stable
);
1324 nfsm_chain_add_32(error
, &nmrep
, NFS_WRITE_FILESYNC
);
1325 /* write verifier */
1326 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_sec
);
1327 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_usec
);
1329 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
1332 nfsm_chain_build_done(error
, &nmrep
);
1335 if (uio_bufp
!= NULL
)
1336 FREE(uio_bufp
, M_TEMP
);
1338 nfsm_chain_cleanup(&nmrep
);
1345 * NFS write service with write gathering support. Called when
1346 * nfsrv_wg_delay > 0.
1347 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1348 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1352 #define NWDELAYHASH(sock, f) \
1353 (&(sock)->ns_wdelayhashtbl[(*((u_int32_t *)(f))) % NFS_WDELAYHASHSIZ])
1354 /* These macros compare nfsrv_descript structures. */
1355 #define NFSW_CONTIG(o, n) \
1356 (((o)->nd_eoff >= (n)->nd_off) && nfsrv_fhmatch(&(o)->nd_fh, &(n)->nd_fh))
1358 * XXX The following is an incorrect comparison; it fails to take into account
1359 * XXX scoping of MAC labels, but we currently lack KPI for credential
1362 #define NFSW_SAMECRED(o, n) \
1363 (!bcmp((caddr_t)(o)->nd_cr, (caddr_t)(n)->nd_cr, \
1364 sizeof (struct ucred)))
1368 struct nfsrv_descript
**ndp
,
1369 struct nfsrv_sock
*slp
,
1373 struct nfsrv_descript
*nd
, *wp
, *owp
, *swp
;
1374 struct nfs_export
*nx
;
1375 struct nfs_export_options
*nxo
;
1376 struct nfsrv_wg_delayhash
*wpp
;
1378 struct vnode_attr preattr
, postattr
;
1379 int error
, mlen
, i
, ioflags
, tlen
;
1380 int preattrerr
, postattrerr
;
1384 char *uio_bufp
= NULL
;
1387 struct nfsm_chain
*nmreq
, nmrep
;
1390 preattrerr
= postattrerr
= ENOENT
;
1391 nfsm_chain_null(&nmrep
);
1398 nmreq
= &nd
->nd_nmreq
;
1399 LIST_INIT(&nd
->nd_coalesce
);
1401 nd
->nd_stable
= NFS_WRITE_FILESYNC
;
1403 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1404 nd
->nd_time
= cur_usec
+
1405 ((nd
->nd_vers
== NFS_VER3
) ? nfsrv_wg_delay_v3
: nfsrv_wg_delay
);
1407 /* Now, get the write header... */
1408 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nd
->nd_fh
.nfh_fhp
, nd
->nd_fh
.nfh_len
);
1409 /* XXX shouldn't we be checking for invalid FHs before doing any more work? */
1411 if (nd
->nd_vers
== NFS_VER3
) {
1412 nfsm_chain_get_64(error
, nmreq
, nd
->nd_off
);
1413 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1414 nfsm_chain_get_32(error
, nmreq
, nd
->nd_stable
);
1416 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1417 nfsm_chain_get_32(error
, nmreq
, nd
->nd_off
);
1418 nfsm_chain_adv(error
, nmreq
, NFSX_UNSIGNED
);
1420 nd
->nd_stable
= NFS_WRITE_UNSTABLE
;
1422 nfsm_chain_get_32(error
, nmreq
, nd
->nd_len
);
1424 nd
->nd_eoff
= nd
->nd_off
+ nd
->nd_len
;
1426 if (nd
->nd_len
> 0) {
1427 error
= nfsm_chain_trim_data(nmreq
, nd
->nd_len
, &mlen
);
1433 if ((nd
->nd_len
> NFSRV_MAXDATA
) || (nd
->nd_len
< 0) || (mlen
< nd
->nd_len
)) {
1436 nd
->nd_repstat
= error
;
1437 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCDATA(nd
->nd_vers
));
1439 nd
->nd_mrep
= nmrep
.nmc_mhead
;
1440 if (nd
->nd_vers
== NFS_VER3
)
1441 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
1442 preattrerr
, &preattr
, postattrerr
, &postattr
);
1444 nfsm_chain_build_done(error
, &nmrep
);
1449 * Add this entry to the hash and time queues.
1451 lck_mtx_lock(&slp
->ns_wgmutex
);
1453 wp
= slp
->ns_tq
.lh_first
;
1454 while (wp
&& wp
->nd_time
< nd
->nd_time
) {
1456 wp
= wp
->nd_tq
.le_next
;
1459 LIST_INSERT_AFTER(owp
, nd
, nd_tq
);
1461 LIST_INSERT_HEAD(&slp
->ns_tq
, nd
, nd_tq
);
1464 wpp
= NWDELAYHASH(slp
, nd
->nd_fh
.nfh_fid
);
1467 while (wp
&& !nfsrv_fhmatch(&nd
->nd_fh
, &wp
->nd_fh
)) {
1469 wp
= wp
->nd_hash
.le_next
;
1471 while (wp
&& (wp
->nd_off
< nd
->nd_off
) &&
1472 nfsrv_fhmatch(&nd
->nd_fh
, &wp
->nd_fh
)) {
1474 wp
= wp
->nd_hash
.le_next
;
1477 LIST_INSERT_AFTER(owp
, nd
, nd_hash
);
1479 * Search the hash list for overlapping entries and
1482 for(; nd
&& NFSW_CONTIG(owp
, nd
); nd
= wp
) {
1483 wp
= nd
->nd_hash
.le_next
;
1484 if (NFSW_SAMECRED(owp
, nd
))
1485 nfsrv_wg_coalesce(owp
, nd
);
1488 LIST_INSERT_HEAD(wpp
, nd
, nd_hash
);
1492 lck_mtx_lock(&slp
->ns_wgmutex
);
1496 * Now, do VNOP_WRITE()s for any one(s) that need to be done now
1497 * and generate the associated reply mbuf list(s).
1501 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1502 for (nd
= slp
->ns_tq
.lh_first
; nd
; nd
= owp
) {
1503 owp
= nd
->nd_tq
.le_next
;
1504 if (nd
->nd_time
> cur_usec
)
1508 LIST_REMOVE(nd
, nd_tq
);
1509 LIST_REMOVE(nd
, nd_hash
);
1510 nmreq
= &nd
->nd_nmreq
;
1511 preattrerr
= postattrerr
= ENOENT
;
1513 /* save the incoming uid before mapping, */
1514 /* for updating active user stats later */
1515 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
1517 error
= nfsrv_fhtovp(&nd
->nd_fh
, nd
, &vp
, &nx
, &nxo
);
1519 /* update per-export stats */
1520 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
1522 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
1527 if (nd
->nd_vers
== NFS_VER3
) {
1528 nfsm_srv_pre_vattr_init(&preattr
);
1529 preattrerr
= vnode_getattr(vp
, &preattr
, ctx
);
1531 if (vnode_vtype(vp
) != VREG
) {
1532 if (nd
->nd_vers
== NFS_VER3
)
1535 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1540 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, ctx
, nxo
, 1);
1542 if (nd
->nd_stable
== NFS_WRITE_UNSTABLE
)
1543 ioflags
= IO_NODELOCKED
;
1544 else if (nd
->nd_stable
== NFS_WRITE_DATASYNC
)
1545 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1547 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1549 if (!error
&& ((nd
->nd_eoff
- nd
->nd_off
) > 0)) {
1550 for (i
=0, m
=nmreq
->nmc_mhead
; m
; m
= mbuf_next(m
))
1551 if (mbuf_len(m
) > 0)
1554 MALLOC(uio_bufp
, char *, UIO_SIZEOF(i
), M_TEMP
, M_WAITOK
);
1556 auio
= uio_createwithbuffer(i
, nd
->nd_off
, UIO_SYSSPACE
,
1557 UIO_WRITE
, uio_bufp
, UIO_SIZEOF(i
));
1558 if (!uio_bufp
|| !auio
)
1561 for (m
= nmreq
->nmc_mhead
; m
; m
= mbuf_next(m
))
1562 if ((tlen
= mbuf_len(m
)) > 0)
1563 uio_addiov(auio
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(m
)), tlen
);
1564 error
= VNOP_WRITE(vp
, auio
, ioflags
, ctx
);
1565 OSAddAtomic64(1, &nfsstats
.srvvop_writes
);
1567 /* update export stats */
1568 NFSStatAdd64(&nx
->nx_stats
.bytes_written
, nd
->nd_len
);
1569 /* update active user stats */
1570 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, nd
->nd_len
);
1573 if (nfsrv_fsevents_enabled
&& !error
&& need_fsevent(FSE_CONTENT_MODIFIED
, vp
))
1574 nfsrv_modified(vp
, ctx
);
1578 FREE(uio_bufp
, M_TEMP
);
1583 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
1584 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
1589 * Loop around generating replies for all write rpcs that have
1590 * now been completed.
1595 nd
->nd_repstat
= error
;
1596 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCDATA(nd
->nd_vers
));
1597 if (!error
&& (nd
->nd_vers
== NFS_VER3
)) {
1598 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
1599 preattrerr
, &preattr
, postattrerr
, &postattr
);
1602 nd
->nd_repstat
= error
;
1603 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_PREOPATTR(nd
->nd_vers
) +
1604 NFSX_POSTOPORFATTR(nd
->nd_vers
) + 2 * NFSX_UNSIGNED
+
1605 NFSX_WRITEVERF(nd
->nd_vers
));
1606 if (!error
&& (nd
->nd_vers
== NFS_VER3
)) {
1607 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
1608 preattrerr
, &preattr
, postattrerr
, &postattr
);
1609 nfsm_chain_add_32(error
, &nmrep
, nd
->nd_len
);
1610 nfsm_chain_add_32(error
, &nmrep
, nd
->nd_stable
);
1611 /* write verifier */
1612 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_sec
);
1613 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_usec
);
1614 } else if (!error
) {
1615 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
1618 nfsm_chain_build_done(error
, &nmrep
);
1620 nd
->nd_mrep
= nmrep
.nmc_mhead
;
1623 * Done. Put it at the head of the timer queue so that
1624 * the final phase can return the reply.
1628 LIST_INSERT_HEAD(&slp
->ns_tq
, nd
, nd_tq
);
1630 nd
= swp
->nd_coalesce
.lh_first
;
1632 LIST_REMOVE(nd
, nd_tq
);
1636 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1641 * Search for a reply to return.
1643 for (nd
= slp
->ns_tq
.lh_first
; nd
; nd
= nd
->nd_tq
.le_next
)
1645 LIST_REMOVE(nd
, nd_tq
);
1646 *mrepp
= nd
->nd_mrep
;
1650 slp
->ns_wgtime
= slp
->ns_tq
.lh_first
? slp
->ns_tq
.lh_first
->nd_time
: 0;
1651 lck_mtx_unlock(&slp
->ns_wgmutex
);
1654 * If we've just created a write pending gather,
1655 * start the timer to check on it soon to make sure
1656 * the write will be completed.
1658 * Add/Remove the socket in the nfsrv_sockwg queue as needed.
1660 lck_mtx_lock(nfsd_mutex
);
1661 if (slp
->ns_wgtime
) {
1662 if (slp
->ns_wgq
.tqe_next
== SLPNOLIST
) {
1663 TAILQ_INSERT_HEAD(&nfsrv_sockwg
, slp
, ns_wgq
);
1665 if (!nfsrv_wg_timer_on
) {
1666 nfsrv_wg_timer_on
= 1;
1667 nfs_interval_timer_start(nfsrv_wg_timer_call
,
1668 NFSRV_WGATHERDELAY
);
1670 } else if (slp
->ns_wgq
.tqe_next
!= SLPNOLIST
) {
1671 TAILQ_REMOVE(&nfsrv_sockwg
, slp
, ns_wgq
);
1672 slp
->ns_wgq
.tqe_next
= SLPNOLIST
;
1674 lck_mtx_unlock(nfsd_mutex
);
1680 * Coalesce the write request nd into owp. To do this we must:
1681 * - remove nd from the queues
1682 * - merge nd->nd_nmreq into owp->nd_nmreq
1683 * - update the nd_eoff and nd_stable for owp
1684 * - put nd on owp's nd_coalesce list
1687 nfsrv_wg_coalesce(struct nfsrv_descript
*owp
, struct nfsrv_descript
*nd
)
1691 struct nfsrv_descript
*p
;
1693 LIST_REMOVE(nd
, nd_hash
);
1694 LIST_REMOVE(nd
, nd_tq
);
1695 if (owp
->nd_eoff
< nd
->nd_eoff
) {
1696 overlap
= owp
->nd_eoff
- nd
->nd_off
;
1700 mbuf_adj(nd
->nd_nmreq
.nmc_mhead
, overlap
);
1701 mp
= owp
->nd_nmreq
.nmc_mhead
;
1702 while ((mpnext
= mbuf_next(mp
)))
1704 error
= mbuf_setnext(mp
, nd
->nd_nmreq
.nmc_mhead
);
1707 owp
->nd_eoff
= nd
->nd_eoff
;
1709 mbuf_freem(nd
->nd_nmreq
.nmc_mhead
);
1711 nd
->nd_nmreq
.nmc_mhead
= NULL
;
1712 nd
->nd_nmreq
.nmc_mcur
= NULL
;
1713 if (nd
->nd_stable
== NFS_WRITE_FILESYNC
)
1714 owp
->nd_stable
= NFS_WRITE_FILESYNC
;
1715 else if ((nd
->nd_stable
== NFS_WRITE_DATASYNC
) &&
1716 (owp
->nd_stable
== NFS_WRITE_UNSTABLE
))
1717 owp
->nd_stable
= NFS_WRITE_DATASYNC
;
1718 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nd
, nd_tq
);
1721 * If nd had anything else coalesced into it, transfer them
1722 * to owp, otherwise their replies will never get sent.
1724 while ((p
= nd
->nd_coalesce
.lh_first
)) {
1725 LIST_REMOVE(p
, nd_tq
);
1726 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1732 * Scan the write gathering queues for writes that need to be
1736 nfsrv_wg_timer(__unused
void *param0
, __unused
void *param1
)
1739 uint64_t cur_usec
, next_usec
;
1741 struct nfsrv_sock
*slp
;
1742 int writes_pending
= 0;
1745 cur_usec
= (uint64_t)now
.tv_sec
* 1000000 + (uint64_t)now
.tv_usec
;
1746 next_usec
= cur_usec
+ (NFSRV_WGATHERDELAY
* 1000);
1748 lck_mtx_lock(nfsd_mutex
);
1749 TAILQ_FOREACH(slp
, &nfsrv_sockwg
, ns_wgq
) {
1750 if (slp
->ns_wgtime
) {
1752 if (slp
->ns_wgtime
<= cur_usec
) {
1753 lck_rw_lock_exclusive(&slp
->ns_rwlock
);
1754 slp
->ns_flag
|= SLP_DOWRITES
;
1755 lck_rw_done(&slp
->ns_rwlock
);
1756 nfsrv_wakenfsd(slp
);
1759 if (slp
->ns_wgtime
< next_usec
)
1760 next_usec
= slp
->ns_wgtime
;
1764 if (writes_pending
== 0) {
1765 nfsrv_wg_timer_on
= 0;
1766 lck_mtx_unlock(nfsd_mutex
);
1769 lck_mtx_unlock(nfsd_mutex
);
1772 * Return the number of msec to wait again
1774 interval
= (next_usec
- cur_usec
) / 1000;
1777 nfs_interval_timer_start(nfsrv_wg_timer_call
, interval
);
1781 * Sort the group list in increasing numerical order.
1782 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1783 * that used to be here.)
1786 nfsrv_group_sort(gid_t
*list
, int num
)
1791 /* Insertion sort. */
1792 for (i
= 1; i
< num
; i
++) {
1794 /* find correct slot for value v, moving others up */
1795 for (j
= i
; --j
>= 0 && v
< list
[j
];)
1796 list
[j
+ 1] = list
[j
];
1802 * nfs create service
1803 * now does a truncate to 0 length via. setattr if it already exists
1807 struct nfsrv_descript
*nd
,
1808 struct nfsrv_sock
*slp
,
1812 struct vnode_attr dpreattr
, dpostattr
, postattr
;
1813 struct vnode_attr va
, *vap
= &va
;
1814 struct nameidata ni
;
1815 int error
, rdev
, dpreattrerr
, dpostattrerr
, postattrerr
;
1816 int how
, exclusive_flag
;
1817 uint32_t len
= 0, cnflags
;
1818 vnode_t vp
, dvp
, dirp
;
1819 struct nfs_filehandle nfh
;
1820 struct nfs_export
*nx
= NULL
;
1821 struct nfs_export_options
*nxo
;
1823 u_char cverf
[NFSX_V3CREATEVERF
];
1825 struct nfsm_chain
*nmreq
, nmrep
;
1828 dpreattrerr
= dpostattrerr
= postattrerr
= ENOENT
;
1829 nmreq
= &nd
->nd_nmreq
;
1830 nfsm_chain_null(&nmrep
);
1831 vp
= dvp
= dirp
= NULL
;
1833 ni
.ni_cnd
.cn_nameiop
= 0;
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
;
1847 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1848 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
1850 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
1852 /* update export stats */
1853 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
1855 /* update active user stats */
1856 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
1860 if (nd
->nd_vers
== NFS_VER3
) {
1861 nfsm_srv_pre_vattr_init(&dpreattr
);
1862 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
1870 ni
.ni_cnd
.cn_nameiop
= 0;
1878 if (nd
->nd_vers
== NFS_VER3
) {
1879 nfsm_chain_get_32(error
, nmreq
, how
);
1882 case NFS_CREATE_GUARDED
:
1887 case NFS_CREATE_UNCHECKED
:
1888 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
1890 case NFS_CREATE_EXCLUSIVE
:
1891 nfsm_chain_get_opaque(error
, nmreq
, NFSX_V3CREATEVERF
, cverf
);
1894 VATTR_SET(vap
, va_mode
, 0);
1897 VATTR_SET(vap
, va_type
, VREG
);
1901 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
1903 v_type
= vap
->va_type
;
1906 VATTR_SET(vap
, va_type
, v_type
);
1912 rdev
= vap
->va_data_size
;
1913 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
1922 * If it doesn't exist, create it
1923 * otherwise just truncate to 0 length
1924 * should I set the mode too ??
1927 kauth_acl_t xacl
= NULL
;
1929 /* authorize before creating */
1930 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
, nxo
, 0);
1932 /* construct ACL and handle inheritance */
1934 error
= kauth_acl_inherit(dvp
,
1940 if (!error
&& xacl
!= NULL
)
1941 VATTR_SET(vap
, va_acl
, xacl
);
1943 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
1944 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
1946 * Server policy is to alway use the mapped rpc credential for
1947 * file system object creation. This has the nice side effect of
1948 * enforcing BSD creation semantics
1950 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
1951 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
1953 /* validate new-file security information */
1955 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
1957 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1960 error
= VNOP_CREATE(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
);
1962 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
1964 * If some of the requested attributes weren't handled by the VNOP,
1965 * use our fallback code.
1967 error
= vnode_setattr_fallback(vp
, vap
, ctx
);
1970 kauth_acl_free(xacl
);
1973 if (exclusive_flag
) {
1976 bcopy(cverf
, (caddr_t
)&vap
->va_access_time
,
1978 VATTR_SET_ACTIVE(vap
, va_access_time
);
1979 // skip authorization, as this is an
1980 // NFS internal implementation detail.
1981 error
= vnode_setattr(vp
, vap
, ctx
);
1985 if (nfsrv_fsevents_enabled
&& need_fsevent(FSE_CREATE_FILE
, vp
)) {
1986 add_fsevent(FSE_CREATE_FILE
, ctx
,
1993 } else if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
||
1994 vap
->va_type
== VFIFO
) {
1995 if (vap
->va_type
== VCHR
&& rdev
== (int)0xffffffff)
1996 VATTR_SET(vap
, va_type
, VFIFO
);
1997 if (vap
->va_type
!= VFIFO
) {
1998 error
= suser(nd
->nd_cr
, NULL
);
2001 VATTR_SET(vap
, va_rdev
, (dev_t
)rdev
);
2003 error
= VNOP_MKNOD(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
);
2006 kauth_acl_free(xacl
);
2015 ni
.ni_cnd
.cn_nameiop
= LOOKUP
;
2017 ni
.ni_op
= OP_LOOKUP
;
2019 ni
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
2020 ni
.ni_cnd
.cn_context
= ctx
;
2021 ni
.ni_startdir
= dvp
;
2023 cnflags
= ni
.ni_cnd
.cn_flags
; /* store in case we have to restore */
2024 while ((error
= lookup(&ni
)) == ERECYCLE
) {
2025 ni
.ni_cnd
.cn_flags
= cnflags
;
2026 ni
.ni_cnd
.cn_nameptr
= ni
.ni_cnd
.cn_pnbuf
;
2027 ni
.ni_usedvp
= ni
.ni_dvp
= ni
.ni_startdir
= dvp
;
2030 if (ni
.ni_cnd
.cn_flags
& ISSYMLINK
)
2039 * nameidone has to happen before we vnode_put(dvp)
2040 * since it may need to release the fs_nodelock on the dvp
2043 ni
.ni_cnd
.cn_nameiop
= 0;
2048 * nameidone has to happen before we vnode_put(dvp)
2049 * since it may need to release the fs_nodelock on the dvp
2052 ni
.ni_cnd
.cn_nameiop
= 0;
2056 if (!error
&& VATTR_IS_ACTIVE(vap
, va_data_size
)) {
2057 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
,
2060 tempsize
= vap
->va_data_size
;
2062 VATTR_SET(vap
, va_data_size
, tempsize
);
2063 error
= vnode_setattr(vp
, vap
, ctx
);
2068 error
= nfsrv_vptofh(nx
, nd
->nd_vers
, NULL
, vp
, ctx
, &nfh
);
2070 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
2071 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
2072 if (nd
->nd_vers
== NFS_VER2
)
2073 error
= postattrerr
;
2079 if (nd
->nd_vers
== NFS_VER3
) {
2080 if (exclusive_flag
&& !error
&&
2081 bcmp(cverf
, &postattr
.va_access_time
, NFSX_V3CREATEVERF
))
2083 nfsm_srv_vattr_init(&dpostattr
, NFS_VER3
);
2084 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
2090 /* assemble reply */
2091 nd
->nd_repstat
= error
;
2092 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(nd
->nd_vers
, &nfh
) +
2093 NFSX_FATTR(nd
->nd_vers
) + NFSX_WCCDATA(nd
->nd_vers
));
2095 *mrepp
= nmrep
.nmc_mhead
;
2096 nfsmout_on_status(nd
, error
);
2097 if (nd
->nd_vers
== NFS_VER3
) {
2098 if (!nd
->nd_repstat
) {
2099 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2100 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, postattrerr
, &postattr
);
2102 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
2103 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
2105 nfsm_chain_add_fh(error
, &nmrep
, NFS_VER2
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2107 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
2110 nfsm_chain_build_done(error
, &nmrep
);
2111 if (ni
.ni_cnd
.cn_nameiop
) {
2113 * nameidone has to happen before we vnode_put(dvp)
2114 * since it may need to release the fs_nodelock on the dvp
2125 nfsm_chain_cleanup(&nmrep
);
2132 * nfs v3 mknod service
2136 struct nfsrv_descript
*nd
,
2137 struct nfsrv_sock
*slp
,
2141 struct vnode_attr dpreattr
, dpostattr
, postattr
;
2142 struct vnode_attr va
, *vap
= &va
;
2143 struct nameidata ni
;
2144 int error
, dpreattrerr
, dpostattrerr
, postattrerr
;
2145 uint32_t len
= 0, cnflags
;
2146 u_int32_t major
= 0, minor
= 0;
2149 vnode_t vp
, dvp
, dirp
;
2150 struct nfs_filehandle nfh
;
2151 struct nfs_export
*nx
= NULL
;
2152 struct nfs_export_options
*nxo
;
2154 kauth_acl_t xacl
= NULL
;
2155 struct nfsm_chain
*nmreq
, nmrep
;
2158 dpreattrerr
= dpostattrerr
= postattrerr
= ENOENT
;
2159 nmreq
= &nd
->nd_nmreq
;
2160 nfsm_chain_null(&nmrep
);
2161 vp
= dvp
= dirp
= NULL
;
2162 ni
.ni_cnd
.cn_nameiop
= 0;
2164 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
2166 nfsm_chain_get_fh_ptr(error
, nmreq
, NFS_VER3
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2167 nfsm_chain_get_32(error
, nmreq
, len
);
2168 nfsm_name_len_check(error
, nd
, len
);
2171 ni
.ni_cnd
.cn_nameiop
= CREATE
;
2175 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2176 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
2178 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
2180 /* update export stats */
2181 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
2183 /* update active user stats */
2184 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
2188 nfsm_srv_pre_vattr_init(&dpreattr
);
2189 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
2192 ni
.ni_cnd
.cn_nameiop
= 0;
2199 nfsm_chain_get_32(error
, nmreq
, nvtype
);
2201 vtyp
= nfstov_type(nvtype
, NFS_VER3
);
2202 if (!error
&& (vtyp
!= VCHR
) && (vtyp
!= VBLK
) && (vtyp
!= VSOCK
) && (vtyp
!= VFIFO
)) {
2203 error
= NFSERR_BADTYPE
;
2208 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
2209 if ((vtyp
== VCHR
) || (vtyp
== VBLK
)) {
2210 nfsm_chain_get_32(error
, nmreq
, major
);
2211 nfsm_chain_get_32(error
, nmreq
, minor
);
2213 VATTR_SET(vap
, va_rdev
, makedev(major
, minor
));
2218 * If it doesn't exist, create it.
2224 VATTR_SET(vap
, va_type
, vtyp
);
2226 /* authorize before creating */
2227 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
, nxo
, 0);
2229 /* construct ACL and handle inheritance */
2231 error
= kauth_acl_inherit(dvp
,
2237 if (!error
&& xacl
!= NULL
)
2238 VATTR_SET(vap
, va_acl
, xacl
);
2240 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
2241 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
2243 * Server policy is to alway use the mapped rpc credential for
2244 * file system object creation. This has the nice side effect of
2245 * enforcing BSD creation semantics
2247 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
2248 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
2250 /* validate new-file security information */
2252 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
2257 if (vtyp
== VSOCK
) {
2258 error
= VNOP_CREATE(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
);
2260 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
2262 * If some of the requested attributes weren't handled by the VNOP,
2263 * use our fallback code.
2265 error
= vnode_setattr_fallback(vp
, vap
, ctx
);
2267 if (vtyp
!= VFIFO
&& (error
= suser(nd
->nd_cr
, (u_short
*)0)))
2269 if ((error
= VNOP_MKNOD(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
)))
2276 ni
.ni_cnd
.cn_nameiop
= LOOKUP
;
2278 ni
.ni_op
= OP_LOOKUP
;
2280 ni
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
2281 ni
.ni_cnd
.cn_context
= vfs_context_current();
2282 ni
.ni_startdir
= dvp
;
2284 cnflags
= ni
.ni_cnd
.cn_flags
; /* store in case we have to restore */
2285 while ((error
= lookup(&ni
)) == ERECYCLE
) {
2286 ni
.ni_cnd
.cn_flags
= cnflags
;
2287 ni
.ni_cnd
.cn_nameptr
= ni
.ni_cnd
.cn_pnbuf
;
2288 ni
.ni_usedvp
= ni
.ni_dvp
= ni
.ni_startdir
= dvp
;
2292 if (ni
.ni_cnd
.cn_flags
& ISSYMLINK
)
2298 kauth_acl_free(xacl
);
2301 * nameidone has to happen before we vnode_put(dvp)
2302 * since it may need to release the fs_nodelock on the dvp
2305 ni
.ni_cnd
.cn_nameiop
= 0;
2311 error
= nfsrv_vptofh(nx
, NFS_VER3
, NULL
, vp
, ctx
, &nfh
);
2313 nfsm_srv_vattr_init(&postattr
, NFS_VER3
);
2314 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
2322 nfsm_srv_vattr_init(&dpostattr
, NFS_VER3
);
2323 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
2328 /* assemble reply */
2329 nd
->nd_repstat
= error
;
2330 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(NFS_VER3
, &nfh
) +
2331 NFSX_POSTOPATTR(NFS_VER3
) + NFSX_WCCDATA(NFS_VER3
));
2333 *mrepp
= nmrep
.nmc_mhead
;
2334 nfsmout_on_status(nd
, error
);
2335 if (!nd
->nd_repstat
) {
2336 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2337 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, postattrerr
, &postattr
);
2339 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
2340 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
2342 nfsm_chain_build_done(error
, &nmrep
);
2343 if (ni
.ni_cnd
.cn_nameiop
) {
2345 * nameidone has to happen before we vnode_put(dvp)
2346 * since it may need to release the fs_nodelock on the dvp
2361 nfsm_chain_cleanup(&nmrep
);
2368 * nfs remove service
2372 struct nfsrv_descript
*nd
,
2373 struct nfsrv_sock
*slp
,
2377 struct nameidata ni
;
2378 int error
, dpreattrerr
, dpostattrerr
;
2381 vnode_t vp
, dvp
, dirp
= NULL
;
2382 struct vnode_attr dpreattr
, dpostattr
;
2383 struct nfs_filehandle nfh
;
2384 struct nfs_export
*nx
= NULL
;
2385 struct nfs_export_options
*nxo
;
2386 struct nfsm_chain
*nmreq
, nmrep
;
2389 dpreattrerr
= dpostattrerr
= ENOENT
;
2390 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
2391 dvp
= vp
= dirp
= NULL
;
2392 nmreq
= &nd
->nd_nmreq
;
2393 nfsm_chain_null(&nmrep
);
2395 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
2396 nfsm_chain_get_32(error
, nmreq
, len
);
2397 nfsm_name_len_check(error
, nd
, len
);
2400 ni
.ni_cnd
.cn_nameiop
= DELETE
;
2402 ni
.ni_op
= OP_UNLINK
;
2404 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2405 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
2407 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
2409 /* update export stats */
2410 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
2412 /* update active user stats */
2413 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
2417 if (nd
->nd_vers
== NFS_VER3
) {
2418 nfsm_srv_pre_vattr_init(&dpreattr
);
2419 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
2430 if (vnode_vtype(vp
) == VDIR
)
2431 error
= EPERM
; /* POSIX */
2432 else if (vnode_isvroot(vp
))
2434 * The root of a mounted filesystem cannot be deleted.
2438 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, ctx
, nxo
, 0);
2446 if (nfsrv_fsevents_enabled
&& need_fsevent(FSE_DELETE
, dvp
)) {
2448 if ((path
= get_pathbuff()) && !vn_getpath(vp
, path
, &plen
)) {
2449 get_fse_info(vp
, &finfo
, ctx
);
2451 release_pathbuff(path
);
2456 error
= VNOP_REMOVE(dvp
, vp
, &ni
.ni_cnd
, 0, ctx
);
2461 add_fsevent(FSE_DELETE
, ctx
,
2462 FSE_ARG_STRING
, plen
, path
,
2463 FSE_ARG_FINFO
, &finfo
,
2465 release_pathbuff(path
);
2471 * nameidone has to happen before we vnode_put(dvp)
2472 * since it may need to release the fs_nodelock on the dvp
2482 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
2483 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
2487 /* assemble reply */
2488 nd
->nd_repstat
= error
;
2489 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCDATA(nd
->nd_vers
));
2491 *mrepp
= nmrep
.nmc_mhead
;
2492 nfsmout_on_status(nd
, error
);
2493 if (nd
->nd_vers
== NFS_VER3
)
2494 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
2495 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
2497 nfsm_chain_build_done(error
, &nmrep
);
2499 nfsm_chain_cleanup(&nmrep
);
2506 * nfs rename service
2510 struct nfsrv_descript
*nd
,
2511 struct nfsrv_sock
*slp
,
2515 kauth_cred_t saved_cred
= NULL
;
2518 uint32_t fromlen
, tolen
;
2519 int fdpreattrerr
, fdpostattrerr
;
2520 int tdpreattrerr
, tdpostattrerr
;
2521 char *frompath
= NULL
, *topath
= NULL
;
2522 struct nameidata fromni
, toni
;
2523 vnode_t fvp
, tvp
, tdvp
, fdvp
, fdirp
, tdirp
;
2524 struct vnode_attr fdpreattr
, fdpostattr
;
2525 struct vnode_attr tdpreattr
, tdpostattr
;
2526 struct nfs_filehandle fnfh
, tnfh
;
2527 struct nfs_export
*fnx
, *tnx
;
2528 struct nfs_export_options
*fnxo
, *tnxo
;
2529 enum vtype fvtype
, tvtype
;
2530 int holding_mntlock
;
2532 struct nfsm_chain
*nmreq
, nmrep
;
2533 char *from_name
, *to_name
;
2535 int from_len
=0, to_len
=0;
2536 fse_info from_finfo
, to_finfo
;
2538 u_char didstats
= 0;
2542 fdpreattrerr
= fdpostattrerr
= ENOENT
;
2543 tdpreattrerr
= tdpostattrerr
= ENOENT
;
2544 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
2545 fromlen
= tolen
= 0;
2546 frompath
= topath
= NULL
;
2547 fdirp
= tdirp
= NULL
;
2548 nmreq
= &nd
->nd_nmreq
;
2549 nfsm_chain_null(&nmrep
);
2552 * these need to be set before calling any code
2553 * that they may take us out through the error path.
2555 holding_mntlock
= 0;
2560 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, fnfh
.nfh_fhp
, fnfh
.nfh_len
);
2561 nfsm_chain_get_32(error
, nmreq
, fromlen
);
2562 nfsm_name_len_check(error
, nd
, fromlen
);
2564 error
= nfsm_chain_get_path_namei(nmreq
, fromlen
, &fromni
);
2566 frompath
= fromni
.ni_cnd
.cn_pnbuf
;
2568 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, tnfh
.nfh_fhp
, tnfh
.nfh_len
);
2569 nfsm_chain_get_32(error
, nmreq
, tolen
);
2570 nfsm_name_len_check(error
, nd
, tolen
);
2572 error
= nfsm_chain_get_path_namei(nmreq
, tolen
, &toni
);
2574 topath
= toni
.ni_cnd
.cn_pnbuf
;
2577 * Remember our original uid so that we can reset cr_uid before
2578 * the second nfsrv_namei() call, in case it is remapped.
2580 saved_cred
= nd
->nd_cr
;
2581 kauth_cred_ref(saved_cred
);
2583 fromni
.ni_cnd
.cn_nameiop
= DELETE
;
2585 fromni
.ni_op
= OP_UNLINK
;
2587 fromni
.ni_cnd
.cn_flags
= WANTPARENT
;
2589 fromni
.ni_cnd
.cn_pnbuf
= frompath
;
2591 fromni
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2592 fromni
.ni_cnd
.cn_flags
|= HASBUF
;
2594 error
= nfsrv_namei(nd
, ctx
, &fromni
, &fnfh
, &fdirp
, &fnx
, &fnxo
);
2597 fdvp
= fromni
.ni_dvp
;
2601 if (nd
->nd_vers
== NFS_VER3
) {
2602 nfsm_srv_pre_vattr_init(&fdpreattr
);
2603 fdpreattrerr
= vnode_getattr(fdirp
, &fdpreattr
, ctx
);
2609 fvtype
= vnode_vtype(fvp
);
2611 /* reset credential if it was remapped */
2612 if (nd
->nd_cr
!= saved_cred
) {
2613 kauth_cred_ref(saved_cred
);
2614 kauth_cred_unref(&nd
->nd_cr
);
2615 ctx
->vc_ucred
= nd
->nd_cr
= saved_cred
;
2618 toni
.ni_cnd
.cn_nameiop
= RENAME
;
2620 toni
.ni_op
= OP_RENAME
;
2622 toni
.ni_cnd
.cn_flags
= WANTPARENT
;
2624 toni
.ni_cnd
.cn_pnbuf
= topath
;
2626 toni
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2627 toni
.ni_cnd
.cn_flags
|= HASBUF
;
2630 toni
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2633 error
= nfsrv_namei(nd
, ctx
, &toni
, &tnfh
, &tdirp
, &tnx
, &tnxo
);
2636 * Translate error code for rename("dir1", "dir2/.").
2638 if (error
== EISDIR
&& fvtype
== VDIR
) {
2639 if (nd
->nd_vers
== NFS_VER3
)
2650 /* update export stats once only */
2652 /* update export stats */
2653 NFSStatAdd64(&tnx
->nx_stats
.ops
, 1);
2655 /* update active user stats */
2656 nfsrv_update_user_stat(tnx
, nd
, saved_uid
, 1, 0, 0);
2662 if (nd
->nd_vers
== NFS_VER3
) {
2663 nfsm_srv_pre_vattr_init(&tdpreattr
);
2664 tdpreattrerr
= vnode_getattr(tdirp
, &tdpreattr
, ctx
);
2672 tvtype
= vnode_vtype(tvp
);
2674 if (fvtype
== VDIR
&& tvtype
!= VDIR
) {
2675 if (nd
->nd_vers
== NFS_VER3
)
2680 } else if (fvtype
!= VDIR
&& tvtype
== VDIR
) {
2681 if (nd
->nd_vers
== NFS_VER3
)
2687 if (tvtype
== VDIR
&& vnode_mountedhere(tvp
)) {
2688 if (nd
->nd_vers
== NFS_VER3
)
2696 if (nd
->nd_vers
== NFS_VER3
)
2706 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
2707 * the node is moving between directories and we need rights to remove from the
2708 * old and add to the new.
2710 * If tvp already exists and is not a directory, we need to be allowed to delete it.
2712 * Note that we do not inherit when renaming. XXX this needs to be revisited to
2713 * implement the deferred-inherit bit.
2719 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
2722 } else if (tdvp
!= fdvp
) {
2726 /* moving out of fdvp, must have delete rights */
2727 if ((error
= nfsrv_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, ctx
, fnxo
, 0)) != 0)
2729 /* moving into tdvp or tvp, must have rights to add */
2730 if ((error
= nfsrv_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
2732 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2733 ctx
, tnxo
, 0)) != 0)
2736 /* node staying in same directory, must be allowed to add new name */
2737 if ((error
= nfsrv_authorize(fdvp
, NULL
,
2738 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2739 ctx
, fnxo
, 0)) != 0)
2742 /* overwriting tvp */
2743 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
2744 ((error
= nfsrv_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, ctx
, tnxo
, 0)) != 0))
2747 /* XXX more checks? */
2750 /* authorization denied */
2755 if ((vnode_mount(fvp
) != vnode_mount(tdvp
)) ||
2756 (tvp
&& (vnode_mount(fvp
) != vnode_mount(tvp
)))) {
2757 if (nd
->nd_vers
== NFS_VER3
)
2764 * The following edge case is caught here:
2765 * (to cannot be a descendent of from)
2778 if (tdvp
->v_parent
== fvp
) {
2779 if (nd
->nd_vers
== NFS_VER3
)
2785 if (fvtype
== VDIR
&& vnode_mountedhere(fvp
)) {
2786 if (nd
->nd_vers
== NFS_VER3
)
2793 * If source is the same as the destination (that is the
2794 * same vnode) then there is nothing to do...
2795 * EXCEPT if the underlying file system supports case
2796 * insensitivity and is case preserving. In this case
2797 * the file system needs to handle the special case of
2798 * getting the same vnode as target (fvp) and source (tvp).
2800 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2801 * and _PC_CASE_PRESERVING can have this exception, and they need to
2802 * handle the special case of getting the same vnode as target and
2803 * source. NOTE: Then the target is unlocked going into vnop_rename,
2804 * so not to cause locking problems. There is a single reference on tvp.
2806 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2807 * that correct behaviour then is just to remove the source (link)
2809 if ((fvp
== tvp
) && (fdvp
== tdvp
)) {
2810 if (fromni
.ni_cnd
.cn_namelen
== toni
.ni_cnd
.cn_namelen
&&
2811 !bcmp(fromni
.ni_cnd
.cn_nameptr
, toni
.ni_cnd
.cn_nameptr
,
2812 fromni
.ni_cnd
.cn_namelen
)) {
2817 if (holding_mntlock
&& vnode_mount(fvp
) != locked_mp
) {
2819 * we're holding a reference and lock
2820 * on locked_mp, but it no longer matches
2821 * what we want to do... so drop our hold
2823 mount_unlock_renames(locked_mp
);
2824 mount_drop(locked_mp
, 0);
2825 holding_mntlock
= 0;
2827 if (tdvp
!= fdvp
&& fvtype
== VDIR
) {
2829 * serialize renames that re-shape
2830 * the tree... if holding_mntlock is
2831 * set, then we're ready to go...
2833 * first need to drop the iocounts
2834 * we picked up, second take the
2835 * lock to serialize the access,
2836 * then finally start the lookup
2837 * process over with the lock held
2839 if (!holding_mntlock
) {
2841 * need to grab a reference on
2842 * the mount point before we
2843 * drop all the iocounts... once
2844 * the iocounts are gone, the mount
2847 locked_mp
= vnode_mount(fvp
);
2848 mount_ref(locked_mp
, 0);
2850 /* make a copy of to path to pass to nfsrv_namei() again */
2851 MALLOC_ZONE(topath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2853 bcopy(toni
.ni_cnd
.cn_pnbuf
, topath
, tolen
+ 1);
2856 * nameidone has to happen before we vnode_put(tdvp)
2857 * since it may need to release the fs_nodelock on the tdvp
2865 /* make a copy of from path to pass to nfsrv_namei() again */
2866 MALLOC_ZONE(frompath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2868 bcopy(fromni
.ni_cnd
.cn_pnbuf
, frompath
, fromlen
+ 1);
2871 * nameidone has to happen before we vnode_put(fdvp)
2872 * since it may need to release the fs_nodelock on the fdvp
2887 mount_lock_renames(locked_mp
);
2888 holding_mntlock
= 1;
2893 fdpreattrerr
= tdpreattrerr
= ENOENT
;
2895 if (!topath
|| !frompath
) {
2896 /* we couldn't allocate a path, so bail */
2901 /* reset credential if it was remapped */
2902 if (nd
->nd_cr
!= saved_cred
) {
2903 kauth_cred_ref(saved_cred
);
2904 kauth_cred_unref(&nd
->nd_cr
);
2905 ctx
->vc_ucred
= nd
->nd_cr
= saved_cred
;
2912 * when we dropped the iocounts to take
2913 * the lock, we allowed the identity of
2914 * the various vnodes to change... if they did,
2915 * we may no longer be dealing with a rename
2916 * that reshapes the tree... once we're holding
2917 * the iocounts, the vnodes can't change type
2918 * so we're free to drop the lock at this point
2921 if (holding_mntlock
) {
2922 mount_unlock_renames(locked_mp
);
2923 mount_drop(locked_mp
, 0);
2924 holding_mntlock
= 0;
2928 // save these off so we can later verify that fvp is the same
2930 oname
= fvp
->v_name
;
2931 oparent
= fvp
->v_parent
;
2934 * If generating an fsevent, then
2935 * stash any pre-rename info we may need.
2938 if (nfsrv_fsevents_enabled
&& need_fsevent(FSE_RENAME
, fvp
)) {
2939 int from_truncated
= 0, to_truncated
= 0;
2941 get_fse_info(fvp
, &from_finfo
, ctx
);
2943 get_fse_info(tvp
, &to_finfo
, ctx
);
2945 from_name
= get_pathbuff();
2947 from_len
= safe_getpath(fdvp
, fromni
.ni_cnd
.cn_nameptr
, from_name
, MAXPATHLEN
, &from_truncated
);
2950 to_name
= from_name
? get_pathbuff() : NULL
;
2952 to_len
= safe_getpath(tdvp
, toni
.ni_cnd
.cn_nameptr
, to_name
, MAXPATHLEN
, &to_truncated
);
2955 if (from_truncated
|| to_truncated
) {
2956 from_finfo
.mode
|= FSE_TRUNCATED_PATH
;
2963 #else /* CONFIG_FSE */
2966 #endif /* CONFIG_FSE */
2968 error
= VNOP_RENAME(fromni
.ni_dvp
, fromni
.ni_vp
, &fromni
.ni_cnd
,
2969 toni
.ni_dvp
, toni
.ni_vp
, &toni
.ni_cnd
, ctx
);
2971 * fix up name & parent pointers. note that we first
2972 * check that fvp has the same name/parent pointers it
2973 * had before the rename call... this is a 'weak' check
2976 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
2978 update_flags
= VNODE_UPDATE_NAME
;
2980 update_flags
|= VNODE_UPDATE_PARENT
;
2981 vnode_update_identity(fvp
, tdvp
, toni
.ni_cnd
.cn_nameptr
,
2982 toni
.ni_cnd
.cn_namelen
, toni
.ni_cnd
.cn_hash
, update_flags
);
2986 * If the rename is OK and we've got the paths
2987 * then add an fsevent.
2990 if (nfsrv_fsevents_enabled
&& !error
&& from_name
&& to_name
) {
2992 add_fsevent(FSE_RENAME
, ctx
,
2993 FSE_ARG_STRING
, from_len
, from_name
,
2994 FSE_ARG_FINFO
, &from_finfo
,
2995 FSE_ARG_STRING
, to_len
, to_name
,
2996 FSE_ARG_FINFO
, &to_finfo
,
2999 add_fsevent(FSE_RENAME
, ctx
,
3000 FSE_ARG_STRING
, from_len
, from_name
,
3001 FSE_ARG_FINFO
, &from_finfo
,
3002 FSE_ARG_STRING
, to_len
, to_name
,
3007 release_pathbuff(from_name
);
3009 release_pathbuff(to_name
);
3010 #endif /* CONFIG_FSE */
3011 from_name
= to_name
= NULL
;
3014 if (holding_mntlock
) {
3015 mount_unlock_renames(locked_mp
);
3016 mount_drop(locked_mp
, 0);
3017 holding_mntlock
= 0;
3021 * nameidone has to happen before we vnode_put(tdvp)
3022 * since it may need to release the fs_nodelock on the tdvp
3033 * nameidone has to happen before we vnode_put(fdvp)
3034 * since it may need to release the fs_nodelock on the fdvp
3045 nfsm_srv_vattr_init(&fdpostattr
, nd
->nd_vers
);
3046 fdpostattrerr
= vnode_getattr(fdirp
, &fdpostattr
, ctx
);
3051 nfsm_srv_vattr_init(&tdpostattr
, nd
->nd_vers
);
3052 tdpostattrerr
= vnode_getattr(tdirp
, &tdpostattr
, ctx
);
3058 /* assemble reply */
3059 nd
->nd_repstat
= error
;
3060 error
= nfsrv_rephead(nd
, slp
, &nmrep
, 2 * NFSX_WCCDATA(nd
->nd_vers
));
3062 *mrepp
= nmrep
.nmc_mhead
;
3063 nfsmout_on_status(nd
, error
);
3064 if (nd
->nd_vers
== NFS_VER3
) {
3065 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3066 fdpreattrerr
, &fdpreattr
, fdpostattrerr
, &fdpostattr
);
3067 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3068 tdpreattrerr
, &tdpreattr
, tdpostattrerr
, &tdpostattr
);
3071 nfsm_chain_build_done(error
, &nmrep
);
3072 if (holding_mntlock
) {
3073 mount_unlock_renames(locked_mp
);
3074 mount_drop(locked_mp
, 0);
3078 * nameidone has to happen before we vnode_put(tdvp)
3079 * since it may need to release the fs_nodelock on the tdvp
3089 * nameidone has to happen before we vnode_put(fdvp)
3090 * since it may need to release the fs_nodelock on the fdvp
3103 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
3105 FREE_ZONE(topath
, MAXPATHLEN
, M_NAMEI
);
3107 kauth_cred_unref(&saved_cred
);
3109 nfsm_chain_cleanup(&nmrep
);
3120 struct nfsrv_descript
*nd
,
3121 struct nfsrv_sock
*slp
,
3125 struct nameidata ni
;
3126 int error
, dpreattrerr
, dpostattrerr
, attrerr
;
3128 vnode_t vp
, xp
, dvp
, dirp
;
3129 struct vnode_attr dpreattr
, dpostattr
, attr
;
3130 struct nfs_filehandle nfh
, dnfh
;
3131 struct nfs_export
*nx
;
3132 struct nfs_export_options
*nxo
;
3133 struct nfsm_chain
*nmreq
, nmrep
;
3136 dpreattrerr
= dpostattrerr
= attrerr
= ENOENT
;
3137 vp
= xp
= dvp
= dirp
= NULL
;
3138 nmreq
= &nd
->nd_nmreq
;
3139 nfsm_chain_null(&nmrep
);
3141 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3142 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, dnfh
.nfh_fhp
, dnfh
.nfh_len
);
3143 nfsm_chain_get_32(error
, nmreq
, len
);
3144 nfsm_name_len_check(error
, nd
, len
);
3146 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
3149 /* update export stats */
3150 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3152 /* update active user stats */
3153 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
3155 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
3158 /* we're not allowed to link to directories... */
3159 if (vnode_vtype(vp
) == VDIR
) {
3160 error
= EPERM
; /* POSIX */
3164 /* ...or to anything that kauth doesn't want us to (eg. immutable items) */
3165 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, ctx
, nxo
, 0)) != 0)
3168 ni
.ni_cnd
.cn_nameiop
= CREATE
;
3172 ni
.ni_cnd
.cn_flags
= LOCKPARENT
;
3173 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
3175 error
= nfsrv_namei(nd
, ctx
, &ni
, &dnfh
, &dirp
, &nx
, &nxo
);
3177 if (nd
->nd_vers
== NFS_VER3
) {
3178 nfsm_srv_pre_vattr_init(&dpreattr
);
3179 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
3192 else if (vnode_mount(vp
) != vnode_mount(dvp
))
3195 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
, nxo
, 0);
3198 error
= VNOP_LINK(vp
, dvp
, &ni
.ni_cnd
, ctx
);
3201 if (nfsrv_fsevents_enabled
&& !error
&& need_fsevent(FSE_CREATE_FILE
, dvp
)) {
3202 char *target_path
= NULL
;
3203 int plen
, truncated
=0;
3206 /* build the path to the new link file */
3207 target_path
= get_pathbuff();
3209 plen
= safe_getpath(dvp
, ni
.ni_cnd
.cn_nameptr
, target_path
, MAXPATHLEN
, &truncated
);
3211 if (get_fse_info(vp
, &finfo
, ctx
) == 0) {
3213 finfo
.mode
|= FSE_TRUNCATED_PATH
;
3215 add_fsevent(FSE_CREATE_FILE
, ctx
,
3216 FSE_ARG_STRING
, plen
, target_path
,
3217 FSE_ARG_FINFO
, &finfo
,
3221 release_pathbuff(target_path
);
3227 * nameidone has to happen before we vnode_put(dvp)
3228 * since it may need to release the fs_nodelock on the dvp
3236 if (nd
->nd_vers
== NFS_VER3
) {
3237 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
3238 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
3241 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
3242 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
3250 /* assemble reply */
3251 nd
->nd_repstat
= error
;
3252 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_WCCDATA(nd
->nd_vers
));
3254 *mrepp
= nmrep
.nmc_mhead
;
3255 nfsmout_on_status(nd
, error
);
3256 if (nd
->nd_vers
== NFS_VER3
) {
3257 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
3258 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3259 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
3262 nfsm_chain_build_done(error
, &nmrep
);
3266 nfsm_chain_cleanup(&nmrep
);
3273 * nfs symbolic link service
3277 struct nfsrv_descript
*nd
,
3278 struct nfsrv_sock
*slp
,
3282 struct vnode_attr dpreattr
, dpostattr
, postattr
;
3283 struct vnode_attr va
, *vap
= &va
;
3284 struct nameidata ni
;
3285 int error
, dpreattrerr
, dpostattrerr
, postattrerr
;
3286 uint32_t len
= 0, linkdatalen
, cnflags
;
3289 vnode_t vp
, dvp
, dirp
;
3290 struct nfs_filehandle nfh
;
3291 struct nfs_export
*nx
= NULL
;
3292 struct nfs_export_options
*nxo
;
3294 char uio_buf
[ UIO_SIZEOF(1) ];
3295 struct nfsm_chain
*nmreq
, nmrep
;
3298 dpreattrerr
= dpostattrerr
= postattrerr
= ENOENT
;
3299 nmreq
= &nd
->nd_nmreq
;
3300 nfsm_chain_null(&nmrep
);
3304 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
3306 ni
.ni_cnd
.cn_nameiop
= 0;
3309 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3310 nfsm_chain_get_32(error
, nmreq
, len
);
3311 nfsm_name_len_check(error
, nd
, len
);
3314 ni
.ni_cnd
.cn_nameiop
= CREATE
;
3318 ni
.ni_cnd
.cn_flags
= LOCKPARENT
;
3319 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
3321 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
3323 /* update export stats */
3324 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3326 /* update active user stats */
3327 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
3331 if (nd
->nd_vers
== NFS_VER3
) {
3332 nfsm_srv_pre_vattr_init(&dpreattr
);
3333 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
3340 ni
.ni_cnd
.cn_nameiop
= 0;
3347 if (nd
->nd_vers
== NFS_VER3
)
3348 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
3349 nfsm_chain_get_32(error
, nmreq
, linkdatalen
);
3350 if (!error
&& (((nd
->nd_vers
== NFS_VER2
) && (linkdatalen
> NFS_MAXPATHLEN
)) ||
3351 ((nd
->nd_vers
== NFS_VER3
) && (linkdatalen
> MAXPATHLEN
))))
3352 error
= NFSERR_NAMETOL
;
3354 MALLOC(linkdata
, caddr_t
, linkdatalen
+ 1, M_TEMP
, M_WAITOK
);
3356 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3357 &uio_buf
[0], sizeof(uio_buf
));
3358 if (!linkdata
|| !auio
) {
3362 uio_addiov(auio
, CAST_USER_ADDR_T(linkdata
), linkdatalen
);
3363 error
= nfsm_chain_get_uio(nmreq
, linkdatalen
, auio
);
3364 if (!error
&& (nd
->nd_vers
== NFS_VER2
))
3365 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
3367 *(linkdata
+ linkdatalen
) = '\0';
3373 VATTR_SET(vap
, va_type
, VLNK
);
3374 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3375 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3377 * Server policy is to alway use the mapped rpc credential for
3378 * file system object creation. This has the nice side effect of
3379 * enforcing BSD creation semantics
3381 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3382 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3384 /* authorize before creating */
3385 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, ctx
, nxo
, 0);
3387 /* validate given attributes */
3389 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
3392 error
= VNOP_SYMLINK(dvp
, &vp
, &ni
.ni_cnd
, vap
, linkdata
, ctx
);
3394 if (!error
&& (nd
->nd_vers
== NFS_VER3
)) {
3396 ni
.ni_cnd
.cn_nameiop
= LOOKUP
;
3398 ni
.ni_op
= OP_LOOKUP
;
3400 ni
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| FOLLOW
);
3401 ni
.ni_cnd
.cn_flags
|= (NOFOLLOW
| LOCKLEAF
);
3402 ni
.ni_cnd
.cn_context
= ctx
;
3403 ni
.ni_startdir
= dvp
;
3405 cnflags
= ni
.ni_cnd
.cn_flags
; /* store in case we have to restore */
3406 while ((error
= lookup(&ni
)) == ERECYCLE
) {
3407 ni
.ni_cnd
.cn_flags
= cnflags
;
3408 ni
.ni_cnd
.cn_nameptr
= ni
.ni_cnd
.cn_pnbuf
;
3409 ni
.ni_usedvp
= ni
.ni_dvp
= ni
.ni_startdir
= dvp
;
3415 error
= nfsrv_vptofh(nx
, NFS_VER3
, NULL
, vp
, ctx
, &nfh
);
3417 nfsm_srv_vattr_init(&postattr
, NFS_VER3
);
3418 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
3424 if (nfsrv_fsevents_enabled
&& !error
&& vp
) {
3425 add_fsevent(FSE_CREATE_FILE
, ctx
,
3432 * nameidone has to happen before we vnode_put(dvp)
3433 * since it may need to release the fs_nodelock on the dvp
3436 ni
.ni_cnd
.cn_nameiop
= 0;
3442 FREE(linkdata
, M_TEMP
);
3446 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
3447 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
3453 /* assemble reply */
3454 nd
->nd_repstat
= error
;
3455 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(nd
->nd_vers
, &nfh
) +
3456 NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_WCCDATA(nd
->nd_vers
));
3458 *mrepp
= nmrep
.nmc_mhead
;
3459 nfsmout_on_status(nd
, error
);
3460 if (nd
->nd_vers
== NFS_VER3
) {
3461 if (!nd
->nd_repstat
) {
3462 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3463 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, postattrerr
, &postattr
);
3465 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3466 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
3469 nfsm_chain_build_done(error
, &nmrep
);
3470 if (ni
.ni_cnd
.cn_nameiop
) {
3472 * nameidone has to happen before we vnode_put(dvp)
3473 * since it may need to release the fs_nodelock on the dvp
3484 FREE(linkdata
, M_TEMP
);
3486 nfsm_chain_cleanup(&nmrep
);
3498 struct nfsrv_descript
*nd
,
3499 struct nfsrv_sock
*slp
,
3503 struct vnode_attr dpreattr
, dpostattr
, postattr
;
3504 struct vnode_attr va
, *vap
= &va
;
3505 struct nameidata ni
;
3506 int error
, dpreattrerr
, dpostattrerr
, postattrerr
;
3508 vnode_t vp
, dvp
, dirp
;
3509 struct nfs_filehandle nfh
;
3510 struct nfs_export
*nx
= NULL
;
3511 struct nfs_export_options
*nxo
;
3513 kauth_acl_t xacl
= NULL
;
3514 struct nfsm_chain
*nmreq
, nmrep
;
3517 dpreattrerr
= dpostattrerr
= postattrerr
= ENOENT
;
3518 nmreq
= &nd
->nd_nmreq
;
3519 nfsm_chain_null(&nmrep
);
3521 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
3523 ni
.ni_cnd
.cn_nameiop
= 0;
3524 vp
= dvp
= dirp
= NULL
;
3526 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3527 nfsm_chain_get_32(error
, nmreq
, len
);
3528 nfsm_name_len_check(error
, nd
, len
);
3531 ni
.ni_cnd
.cn_nameiop
= CREATE
;
3535 ni
.ni_cnd
.cn_flags
= LOCKPARENT
;
3536 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
3538 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
3540 /* update export stats */
3541 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3543 /* update active user stats */
3544 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
3548 if (nd
->nd_vers
== NFS_VER3
) {
3549 nfsm_srv_pre_vattr_init(&dpreattr
);
3550 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
3557 ni
.ni_cnd
.cn_nameiop
= 0;
3564 error
= nfsm_chain_get_sattr(nd
, nmreq
, vap
);
3566 VATTR_SET(vap
, va_type
, VDIR
);
3570 * nameidone has to happen before we vnode_put(dvp)
3571 * since it may need to release the fs_nodelock on the dvp
3580 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, ctx
, nxo
, 0);
3582 /* construct ACL and handle inheritance */
3584 error
= kauth_acl_inherit(dvp
,
3590 if (!error
&& xacl
!= NULL
)
3591 VATTR_SET(vap
, va_acl
, xacl
);
3594 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3595 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3597 * We don't support the S_ISGID bit for directories. Solaris and other
3598 * SRV4 derived systems might set this to get BSD semantics, which we enforce
3601 if (VATTR_IS_ACTIVE(vap
, va_mode
))
3602 vap
->va_mode
&= ~S_ISGID
;
3604 * Server policy is to alway use the mapped rpc credential for
3605 * file system object creation. This has the nice side effect of
3606 * enforcing BSD creation semantics
3608 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3609 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3611 /* validate new-file security information */
3613 error
= vnode_authattr_new(dvp
, vap
, 0, ctx
);
3615 * vnode_authattr_new can return errors other than EPERM, but that's not going to
3616 * sit well with our clients so we map all errors to EPERM.
3622 error
= VNOP_MKDIR(dvp
, &vp
, &ni
.ni_cnd
, vap
, ctx
);
3625 if (nfsrv_fsevents_enabled
&& !error
)
3626 add_fsevent(FSE_CREATE_DIR
, ctx
, FSE_ARG_VNODE
, vp
, FSE_ARG_DONE
);
3629 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
3631 * If some of the requested attributes weren't handled by the VNOP,
3632 * use our fallback code.
3634 error
= vnode_setattr_fallback(vp
, vap
, ctx
);
3637 kauth_acl_free(xacl
);
3640 error
= nfsrv_vptofh(nx
, nd
->nd_vers
, NULL
, vp
, ctx
, &nfh
);
3642 nfsm_srv_vattr_init(&postattr
, nd
->nd_vers
);
3643 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
3644 if (nd
->nd_vers
== NFS_VER2
)
3645 error
= postattrerr
;
3651 * nameidone has to happen before we vnode_put(dvp)
3652 * since it may need to release the fs_nodelock on the dvp
3657 ni
.ni_cnd
.cn_nameiop
= 0;
3660 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
3661 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
3667 /* assemble reply */
3668 nd
->nd_repstat
= error
;
3669 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_SRVFH(nd
->nd_vers
, &nfh
) +
3670 NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_WCCDATA(nd
->nd_vers
));
3672 *mrepp
= nmrep
.nmc_mhead
;
3673 nfsmout_on_status(nd
, error
);
3674 if (nd
->nd_vers
== NFS_VER3
) {
3675 if (!nd
->nd_repstat
) {
3676 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3677 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, postattrerr
, &postattr
);
3679 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3680 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
3682 nfsm_chain_add_fh(error
, &nmrep
, NFS_VER2
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3684 error
= nfsm_chain_add_fattr(nd
, &nmrep
, &postattr
);
3687 nfsm_chain_build_done(error
, &nmrep
);
3688 if (ni
.ni_cnd
.cn_nameiop
) {
3690 * nameidone has to happen before we vnode_put(dvp)
3691 * since it may need to release the fs_nodelock on the dvp
3701 nfsm_chain_cleanup(&nmrep
);
3712 struct nfsrv_descript
*nd
,
3713 struct nfsrv_sock
*slp
,
3717 int error
, dpreattrerr
, dpostattrerr
;
3720 vnode_t vp
, dvp
, dirp
;
3721 struct vnode_attr dpreattr
, dpostattr
;
3722 struct nfs_filehandle nfh
;
3723 struct nfs_export
*nx
= NULL
;
3724 struct nfs_export_options
*nxo
;
3725 struct nameidata ni
;
3726 struct nfsm_chain
*nmreq
, nmrep
;
3729 dpreattrerr
= dpostattrerr
= ENOENT
;
3730 saved_uid
= kauth_cred_getuid(nd
->nd_cr
);
3731 nmreq
= &nd
->nd_nmreq
;
3732 nfsm_chain_null(&nmrep
);
3734 vp
= dvp
= dirp
= NULL
;
3736 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3737 nfsm_chain_get_32(error
, nmreq
, len
);
3738 nfsm_name_len_check(error
, nd
, len
);
3741 ni
.ni_cnd
.cn_nameiop
= DELETE
;
3743 ni
.ni_op
= OP_UNLINK
;
3745 ni
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
3746 error
= nfsm_chain_get_path_namei(nmreq
, len
, &ni
);
3748 error
= nfsrv_namei(nd
, ctx
, &ni
, &nfh
, &dirp
, &nx
, &nxo
);
3750 /* update export stats */
3751 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3753 /* update active user stats */
3754 nfsrv_update_user_stat(nx
, nd
, saved_uid
, 1, 0, 0);
3758 if (nd
->nd_vers
== NFS_VER3
) {
3759 nfsm_srv_pre_vattr_init(&dpreattr
);
3760 dpreattrerr
= vnode_getattr(dirp
, &dpreattr
, ctx
);
3771 if (vnode_vtype(vp
) != VDIR
) {
3776 * No rmdir "." please.
3783 * The root of a mounted filesystem cannot be deleted.
3785 if (vnode_isvroot(vp
))
3788 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, ctx
, nxo
, 0);
3795 if (nfsrv_fsevents_enabled
&& need_fsevent(FSE_DELETE
, dvp
)) {
3797 if ((path
= get_pathbuff()) && !vn_getpath(vp
, path
, &plen
)) {
3798 get_fse_info(vp
, &finfo
, ctx
);
3800 release_pathbuff(path
);
3804 #endif /* CONFIG_FSE */
3806 error
= VNOP_RMDIR(dvp
, vp
, &ni
.ni_cnd
, ctx
);
3811 add_fsevent(FSE_DELETE
, ctx
,
3812 FSE_ARG_STRING
, plen
, path
,
3813 FSE_ARG_FINFO
, &finfo
,
3815 release_pathbuff(path
);
3817 #endif /* CONFIG_FSE */
3821 * nameidone has to happen before we vnode_put(dvp)
3822 * since it may need to release the fs_nodelock on the dvp
3830 nfsm_srv_vattr_init(&dpostattr
, nd
->nd_vers
);
3831 dpostattrerr
= vnode_getattr(dirp
, &dpostattr
, ctx
);
3837 /* assemble reply */
3838 nd
->nd_repstat
= error
;
3839 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_WCCDATA(nd
->nd_vers
));
3841 *mrepp
= nmrep
.nmc_mhead
;
3842 nfsmout_on_status(nd
, error
);
3843 if (nd
->nd_vers
== NFS_VER3
)
3844 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
3845 dpreattrerr
, &dpreattr
, dpostattrerr
, &dpostattr
);
3847 nfsm_chain_build_done(error
, &nmrep
);
3851 nfsm_chain_cleanup(&nmrep
);
3858 * nfs readdir service
3859 * - mallocs what it thinks is enough to read
3860 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
3861 * - calls VNOP_READDIR()
3862 * - loops around building the reply
3863 * if the output generated exceeds count break out of loop
3864 * The nfsm_clget macro is used here so that the reply will be packed
3865 * tightly in mbuf clusters.
3866 * - it only knows that it has encountered eof when the VNOP_READDIR()
3868 * - as such one readdir rpc will return eof false although you are there
3869 * and then the next will return eof
3870 * - it trims out records with d_fileno == 0
3871 * this doesn't matter for Unix clients, but they might confuse clients
3873 * NB: It is tempting to set eof to true if the VNOP_READDIR() reads less
3874 * than requested, but this may not apply to all filesystems. For
3875 * example, client NFS does not { although it is never remote mounted
3877 * The alternate call nfsrv_readdirplus() does lookups as well.
3878 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
3879 * are supposed to cover. For readdir, the count is the total number of
3880 * bytes included in everything from the directory's postopattr through
3881 * the EOF flag. For readdirplus, the maxcount is the same, and the
3882 * dircount includes all that except for the entry attributes and handles.
3886 struct nfsrv_descript
*nd
,
3887 struct nfsrv_sock
*slp
,
3891 struct direntry
*dp
;
3892 char *cpos
, *cend
, *rbuf
;
3894 struct vnode_attr attr
;
3895 struct nfs_filehandle nfh
;
3896 struct nfs_export
*nx
;
3897 struct nfs_export_options
*nxo
;
3899 char uio_buf
[ UIO_SIZEOF(1) ];
3900 int len
, nlen
, rem
, xfer
, error
, attrerr
;
3901 int siz
, count
, fullsiz
, eofflag
, nentries
;
3902 u_quad_t off
, toff
, verf
;
3904 struct nfsm_chain
*nmreq
, nmrep
;
3908 count
= nentries
= 0;
3909 nmreq
= &nd
->nd_nmreq
;
3910 nfsm_chain_null(&nmrep
);
3914 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
3916 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
3917 if (nd
->nd_vers
== NFS_VER3
) {
3918 nfsm_chain_get_64(error
, nmreq
, toff
);
3919 nfsm_chain_get_64(error
, nmreq
, verf
);
3921 nfsm_chain_get_32(error
, nmreq
, toff
);
3923 nfsm_chain_get_32(error
, nmreq
, count
);
3927 siz
= ((count
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
3928 xfer
= NFSRV_NDMAXDATA(nd
);
3933 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
3936 /* update export stats */
3937 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
3939 /* update active user stats */
3940 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
3942 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
3945 if (nxo
->nxo_flags
& NX_MANGLEDNAMES
|| nd
->nd_vers
== NFS_VER2
)
3946 vnopflag
|= VNODE_READDIR_NAMEMAX
;
3948 if ((nd
->nd_vers
== NFS_VER2
) || (nxo
->nxo_flags
& NX_32BITCLIENTS
))
3949 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
3951 if (nd
->nd_vers
== NFS_VER3
) {
3952 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
3953 error
= attrerr
= vnode_getattr(vp
, &attr
, ctx
);
3954 if (!error
&& toff
&& verf
&& (verf
!= attr
.va_filerev
))
3955 error
= NFSERR_BAD_COOKIE
;
3958 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, ctx
, nxo
, 0);
3961 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
3963 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3964 &uio_buf
[0], sizeof(uio_buf
));
3965 if (!rbuf
|| !auio
) {
3970 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
3971 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
3973 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, ctx
);
3974 off
= uio_offset(auio
);
3976 if (nd
->nd_vers
== NFS_VER3
) {
3977 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
3978 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
3982 if (uio_resid(auio
) != 0) {
3983 siz
-= uio_resid(auio
);
3985 /* If nothing read, return empty reply with eof set */
3990 /* assemble reply */
3991 nd
->nd_repstat
= error
;
3992 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) +
3993 NFSX_COOKIEVERF(nd
->nd_vers
) + 2 * NFSX_UNSIGNED
);
3995 *mrepp
= nmrep
.nmc_mhead
;
3996 nfsmout_on_status(nd
, error
);
3997 if (nd
->nd_vers
== NFS_VER3
) {
3998 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
3999 nfsm_chain_add_64(error
, &nmrep
, attr
.va_filerev
);
4001 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4002 nfsm_chain_add_32(error
, &nmrep
, TRUE
);
4003 nfsm_chain_build_done(error
, &nmrep
);
4009 * Check for degenerate cases of nothing useful read.
4010 * If so go try again
4014 dp
= (struct direntry
*)cpos
;
4015 while ((dp
->d_fileno
== 0) && (cpos
< cend
) && (nentries
> 0)) {
4016 cpos
+= dp
->d_reclen
;
4017 dp
= (struct direntry
*)cpos
;
4020 if ((cpos
>= cend
) || (nentries
== 0)) {
4029 /* assemble reply */
4030 nd
->nd_repstat
= error
;
4031 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) +
4032 NFSX_COOKIEVERF(nd
->nd_vers
) + siz
);
4034 *mrepp
= nmrep
.nmc_mhead
;
4035 nfsmout_on_status(nd
, error
);
4036 nmrep
.nmc_flags
|= NFSM_CHAIN_FLAG_ADD_CLUSTERS
;
4038 len
= 2 * NFSX_UNSIGNED
;
4039 if (nd
->nd_vers
== NFS_VER3
) {
4040 len
+= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
;
4041 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4042 nfsm_chain_add_64(error
, &nmrep
, attr
.va_filerev
);
4046 /* Loop through the records and build reply */
4047 while ((cpos
< cend
) && (nentries
> 0)) {
4048 if (dp
->d_fileno
!= 0) {
4049 nlen
= dp
->d_namlen
;
4050 if ((nd
->nd_vers
== NFS_VER2
) && (nlen
> NFS_MAXNAMLEN
))
4051 nlen
= NFS_MAXNAMLEN
;
4052 rem
= nfsm_rndup(nlen
)-nlen
;
4053 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
4054 if (nd
->nd_vers
== NFS_VER3
)
4055 len
+= 2 * NFSX_UNSIGNED
;
4060 /* Build the directory record xdr from the direntry. */
4061 nfsm_chain_add_32(error
, &nmrep
, TRUE
);
4062 if (nd
->nd_vers
== NFS_VER3
) {
4063 nfsm_chain_add_64(error
, &nmrep
, dp
->d_fileno
);
4065 nfsm_chain_add_32(error
, &nmrep
, dp
->d_fileno
);
4067 nfsm_chain_add_string(error
, &nmrep
, dp
->d_name
, nlen
);
4068 if (nd
->nd_vers
== NFS_VER3
) {
4069 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
4070 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
4071 nfsm_chain_add_64(error
, &nmrep
, dp
->d_seekoff
);
4073 nfsm_chain_add_32(error
, &nmrep
, dp
->d_seekoff
);
4077 cpos
+= dp
->d_reclen
;
4078 dp
= (struct direntry
*)cpos
;
4081 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4082 nfsm_chain_add_32(error
, &nmrep
, eofflag
? TRUE
: FALSE
);
4090 nd
->nd_repstat
= error
;
4091 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
));
4093 *mrepp
= nmrep
.nmc_mhead
;
4094 nfsmout_on_status(nd
, error
);
4095 if (nd
->nd_vers
== NFS_VER3
)
4096 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4098 nfsm_chain_build_done(error
, &nmrep
);
4100 nfsm_chain_cleanup(&nmrep
);
4108 struct nfsrv_descript
*nd
,
4109 struct nfsrv_sock
*slp
,
4113 struct direntry
*dp
;
4114 char *cpos
, *cend
, *rbuf
;
4116 struct nfs_filehandle dnfh
, nfh
;
4117 struct nfs_export
*nx
;
4118 struct nfs_export_options
*nxo
;
4120 char uio_buf
[ UIO_SIZEOF(1) ];
4121 struct vnode_attr attr
, va
, *vap
= &va
;
4122 int len
, nlen
, rem
, xfer
, error
, attrerr
, gotfh
, gotattr
;
4123 int siz
, dircount
, maxcount
, fullsiz
, eofflag
, dirlen
, nentries
, isdotdot
;
4124 u_quad_t off
, toff
, verf
;
4126 struct nfsm_chain
*nmreq
, nmrep
;
4131 nmreq
= &nd
->nd_nmreq
;
4132 nfsm_chain_null(&nmrep
);
4135 dircount
= maxcount
= 0;
4137 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
4139 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, dnfh
.nfh_fhp
, dnfh
.nfh_len
);
4140 nfsm_chain_get_64(error
, nmreq
, toff
);
4141 nfsm_chain_get_64(error
, nmreq
, verf
);
4142 nfsm_chain_get_32(error
, nmreq
, dircount
);
4143 nfsm_chain_get_32(error
, nmreq
, maxcount
);
4147 xfer
= NFSRV_NDMAXDATA(nd
);
4148 dircount
= ((dircount
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
4149 if (dircount
> xfer
)
4151 fullsiz
= siz
= dircount
;
4152 maxcount
= ((maxcount
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
4153 if (maxcount
> xfer
)
4156 error
= nfsrv_fhtovp(&dnfh
, nd
, &vp
, &nx
, &nxo
);
4159 /* update export stats */
4160 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4162 /* update active user stats */
4163 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4165 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4168 if (nxo
->nxo_flags
& NX_32BITCLIENTS
)
4169 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
4171 if (nxo
->nxo_flags
& NX_MANGLEDNAMES
)
4172 vnopflag
|= VNODE_READDIR_NAMEMAX
;
4174 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4175 error
= attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4176 if (!error
&& toff
&& verf
&& (verf
!= attr
.va_filerev
))
4177 error
= NFSERR_BAD_COOKIE
;
4179 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, ctx
, nxo
, 0);
4182 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
4184 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
4185 &uio_buf
[0], sizeof(uio_buf
));
4186 if (!rbuf
|| !auio
) {
4192 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
4193 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
4195 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, ctx
);
4196 off
= uio_offset(auio
);
4197 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4198 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4201 if (uio_resid(auio
) != 0) {
4202 siz
-= uio_resid(auio
);
4204 /* If nothing read, return empty reply with eof set */
4209 /* assemble reply */
4210 nd
->nd_repstat
= error
;
4211 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3POSTOPATTR
+
4212 NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
);
4214 *mrepp
= nmrep
.nmc_mhead
;
4215 nfsmout_on_status(nd
, error
);
4216 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4217 nfsm_chain_add_64(error
, &nmrep
, attr
.va_filerev
);
4218 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4219 nfsm_chain_add_32(error
, &nmrep
, TRUE
);
4220 nfsm_chain_build_done(error
, &nmrep
);
4226 * Check for degenerate cases of nothing useful read.
4227 * If so go try again
4231 dp
= (struct direntry
*)cpos
;
4232 while ((dp
->d_fileno
== 0) && (cpos
< cend
) && (nentries
> 0)) {
4233 cpos
+= dp
->d_reclen
;
4234 dp
= (struct direntry
*)cpos
;
4237 if ((cpos
>= cend
) || (nentries
== 0)) {
4244 * Probe one of the directory entries to see if the filesystem
4247 if ((error
= VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, ctx
))) {
4248 if (error
== ENOTSUP
) /* let others get passed back */
4249 error
= NFSERR_NOTSUPP
;
4254 /* assemble reply */
4255 nd
->nd_repstat
= error
;
4256 error
= nfsrv_rephead(nd
, slp
, &nmrep
, maxcount
);
4258 *mrepp
= nmrep
.nmc_mhead
;
4259 nfsmout_on_status(nd
, error
);
4260 nmrep
.nmc_flags
|= NFSM_CHAIN_FLAG_ADD_CLUSTERS
;
4262 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
4263 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4264 nfsm_chain_add_64(error
, &nmrep
, attr
.va_filerev
);
4267 /* Loop through the records and build reply */
4268 while ((cpos
< cend
) && (nentries
> 0)) {
4269 if (dp
->d_fileno
!= 0) {
4270 nlen
= dp
->d_namlen
;
4271 rem
= nfsm_rndup(nlen
)-nlen
;
4272 gotfh
= gotattr
= 1;
4274 /* Got to get the vnode for lookup per entry. */
4275 if (VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, ctx
)) {
4276 /* Can't get the vnode... so no fh or attrs */
4277 gotfh
= gotattr
= 0;
4279 isdotdot
= ((dp
->d_namlen
== 2) &&
4280 (dp
->d_name
[0] == '.') && (dp
->d_name
[1] == '.'));
4281 if (nfsrv_vptofh(nx
, 0, (isdotdot
? &dnfh
: NULL
), nvp
, ctx
, &nfh
))
4283 nfsm_srv_vattr_init(vap
, NFS_VER3
);
4284 if (vnode_getattr(nvp
, vap
, ctx
))
4290 * If either the dircount or maxcount will be
4291 * exceeded, get out now. Both of these lengths
4292 * are calculated conservatively, including all
4295 len
+= 8 * NFSX_UNSIGNED
+ nlen
+ rem
;
4297 len
+= NFSX_V3FATTR
;
4299 len
+= NFSX_UNSIGNED
+ nfsm_rndup(nfh
.nfh_len
);
4300 dirlen
+= 6 * NFSX_UNSIGNED
+ nlen
+ rem
;
4301 if ((len
> maxcount
) || (dirlen
> dircount
)) {
4306 /* Build the directory record xdr from the direntry. */
4307 nfsm_chain_add_32(error
, &nmrep
, TRUE
);
4308 nfsm_chain_add_64(error
, &nmrep
, dp
->d_fileno
);
4309 nfsm_chain_add_string(error
, &nmrep
, dp
->d_name
, nlen
);
4310 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
4311 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
4312 nfsm_chain_add_64(error
, &nmrep
, dp
->d_seekoff
);
4313 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, (gotattr
? 0 : ENOENT
), vap
);
4315 nfsm_chain_add_postop_fh(error
, &nmrep
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4317 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4320 cpos
+= dp
->d_reclen
;
4321 dp
= (struct direntry
*)cpos
;
4326 nfsm_chain_add_32(error
, &nmrep
, FALSE
);
4327 nfsm_chain_add_32(error
, &nmrep
, eofflag
? TRUE
: FALSE
);
4333 nd
->nd_repstat
= error
;
4334 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3POSTOPATTR
);
4336 *mrepp
= nmrep
.nmc_mhead
;
4337 nfsmout_on_status(nd
, error
);
4338 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4340 nfsm_chain_build_done(error
, &nmrep
);
4344 nfsm_chain_cleanup(&nmrep
);
4351 * nfs commit service
4355 struct nfsrv_descript
*nd
,
4356 struct nfsrv_sock
*slp
,
4361 struct nfs_filehandle nfh
;
4362 struct nfs_export
*nx
;
4363 struct nfs_export_options
*nxo
;
4364 int error
, preattrerr
, postattrerr
, count
;
4365 struct vnode_attr preattr
, postattr
;
4367 struct nfsm_chain
*nmreq
, nmrep
;
4370 preattrerr
= postattrerr
= ENOENT
;
4371 nmreq
= &nd
->nd_nmreq
;
4372 nfsm_chain_null(&nmrep
);
4376 * XXX At this time VNOP_FSYNC() does not accept offset and byte
4377 * count parameters, so those arguments are useless (someday maybe).
4380 nfsm_chain_get_fh_ptr(error
, nmreq
, NFS_VER3
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4381 nfsm_chain_get_64(error
, nmreq
, off
);
4382 nfsm_chain_get_32(error
, nmreq
, count
);
4385 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4388 /* update export stats */
4389 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4391 /* update active user stats */
4392 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4394 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4397 nfsm_srv_pre_vattr_init(&preattr
);
4398 preattrerr
= vnode_getattr(vp
, &preattr
, ctx
);
4400 error
= VNOP_FSYNC(vp
, MNT_WAIT
, ctx
);
4402 nfsm_srv_vattr_init(&postattr
, 1);
4403 postattrerr
= vnode_getattr(vp
, &postattr
, ctx
);
4409 /* assemble reply */
4410 nd
->nd_repstat
= error
;
4411 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
4413 *mrepp
= nmrep
.nmc_mhead
;
4414 nfsmout_on_status(nd
, error
);
4415 nfsm_chain_add_wcc_data(error
, nd
, &nmrep
,
4416 preattrerr
, &preattr
, postattrerr
, &postattr
);
4417 if (!nd
->nd_repstat
) {
4418 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_sec
);
4419 nfsm_chain_add_32(error
, &nmrep
, nx
->nx_exptime
.tv_usec
);
4422 nfsm_chain_build_done(error
, &nmrep
);
4424 nfsm_chain_cleanup(&nmrep
);
4431 * nfs statfs service
4435 struct nfsrv_descript
*nd
,
4436 struct nfsrv_sock
*slp
,
4443 struct vnode_attr attr
;
4444 struct nfs_filehandle nfh
;
4445 struct nfs_export
*nx
;
4446 struct nfs_export_options
*nxo
;
4448 struct nfsm_chain
*nmreq
, nmrep
;
4452 nmreq
= &nd
->nd_nmreq
;
4453 nfsm_chain_null(&nmrep
);
4457 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4459 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4462 /* update export stats */
4463 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4465 /* update active user stats */
4466 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4468 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4472 VFSATTR_WANTED(&va
, f_blocks
);
4473 VFSATTR_WANTED(&va
, f_bavail
);
4474 VFSATTR_WANTED(&va
, f_files
);
4475 VFSATTR_WANTED(&va
, f_ffree
);
4476 error
= vfs_getattr(vnode_mount(vp
), &va
, ctx
);
4477 blksize
= vnode_mount(vp
)->mnt_vfsstat
.f_bsize
;
4479 if (nd
->nd_vers
== NFS_VER3
) {
4480 nfsm_srv_vattr_init(&attr
, nd
->nd_vers
);
4481 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4488 /* assemble reply */
4489 nd
->nd_repstat
= error
;
4490 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_POSTOPATTR(nd
->nd_vers
) + NFSX_STATFS(nd
->nd_vers
));
4492 *mrepp
= nmrep
.nmc_mhead
;
4493 nfsmout_on_status(nd
, error
);
4494 if (nd
->nd_vers
== NFS_VER3
)
4495 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4496 nfsmout_if(nd
->nd_repstat
);
4498 if (nd
->nd_vers
== NFS_VER3
) {
4499 nfsm_chain_add_64(error
, &nmrep
, va
.f_blocks
* blksize
);
4500 nfsm_chain_add_64(error
, &nmrep
, va
.f_bfree
* blksize
);
4501 nfsm_chain_add_64(error
, &nmrep
, va
.f_bavail
* blksize
);
4502 nfsm_chain_add_64(error
, &nmrep
, va
.f_files
);
4503 nfsm_chain_add_64(error
, &nmrep
, va
.f_ffree
);
4504 nfsm_chain_add_64(error
, &nmrep
, va
.f_ffree
);
4505 nfsm_chain_add_32(error
, &nmrep
, 0); /* invarsec */
4507 nfsm_chain_add_32(error
, &nmrep
, NFS_V2MAXDATA
);
4508 nfsm_chain_add_32(error
, &nmrep
, blksize
);
4509 nfsm_chain_add_32(error
, &nmrep
, va
.f_blocks
);
4510 nfsm_chain_add_32(error
, &nmrep
, va
.f_bfree
);
4511 nfsm_chain_add_32(error
, &nmrep
, va
.f_bavail
);
4514 nfsm_chain_build_done(error
, &nmrep
);
4516 nfsm_chain_cleanup(&nmrep
);
4523 * nfs fsinfo service
4527 struct nfsrv_descript
*nd
,
4528 struct nfsrv_sock
*slp
,
4532 int error
, attrerr
, prefsize
, maxsize
;
4534 struct vnode_attr attr
;
4535 struct nfs_filehandle nfh
;
4536 struct nfs_export
*nx
;
4537 struct nfs_export_options
*nxo
;
4538 struct nfsm_chain
*nmreq
, nmrep
;
4542 nmreq
= &nd
->nd_nmreq
;
4543 nfsm_chain_null(&nmrep
);
4546 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4548 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4551 /* update export stats */
4552 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4554 /* update active user stats */
4555 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4557 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4560 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4561 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4567 /* assemble reply */
4568 nd
->nd_repstat
= error
;
4569 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
4571 *mrepp
= nmrep
.nmc_mhead
;
4572 nfsmout_on_status(nd
, error
);
4573 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4574 nfsmout_if(nd
->nd_repstat
);
4577 * XXX There should be file system VFS OP(s) to get this information.
4578 * For now, assume our usual NFS defaults.
4580 if (slp
->ns_sotype
== SOCK_DGRAM
) {
4581 maxsize
= NFS_MAXDGRAMDATA
;
4582 prefsize
= NFS_PREFDGRAMDATA
;
4584 maxsize
= prefsize
= NFSRV_MAXDATA
;
4586 nfsm_chain_add_32(error
, &nmrep
, maxsize
);
4587 nfsm_chain_add_32(error
, &nmrep
, prefsize
);
4588 nfsm_chain_add_32(error
, &nmrep
, NFS_FABLKSIZE
);
4589 nfsm_chain_add_32(error
, &nmrep
, maxsize
);
4590 nfsm_chain_add_32(error
, &nmrep
, prefsize
);
4591 nfsm_chain_add_32(error
, &nmrep
, NFS_FABLKSIZE
);
4592 nfsm_chain_add_32(error
, &nmrep
, prefsize
);
4593 nfsm_chain_add_64(error
, &nmrep
, 0xffffffffffffffffULL
);
4594 nfsm_chain_add_32(error
, &nmrep
, 0);
4595 nfsm_chain_add_32(error
, &nmrep
, 1);
4596 /* XXX link/symlink support should be taken from volume capabilities */
4597 nfsm_chain_add_32(error
, &nmrep
,
4598 NFSV3FSINFO_LINK
| NFSV3FSINFO_SYMLINK
|
4599 NFSV3FSINFO_HOMOGENEOUS
| NFSV3FSINFO_CANSETTIME
);
4602 nfsm_chain_build_done(error
, &nmrep
);
4604 nfsm_chain_cleanup(&nmrep
);
4611 * nfs pathconf service
4615 struct nfsrv_descript
*nd
,
4616 struct nfsrv_sock
*slp
,
4620 int error
, attrerr
, linkmax
, namemax
;
4621 int chownres
, notrunc
, case_sensitive
, case_preserving
;
4623 struct vnode_attr attr
;
4624 struct nfs_filehandle nfh
;
4625 struct nfs_export
*nx
;
4626 struct nfs_export_options
*nxo
;
4627 struct nfsm_chain
*nmreq
, nmrep
;
4631 nmreq
= &nd
->nd_nmreq
;
4632 nfsm_chain_null(&nmrep
);
4635 nfsm_chain_get_fh_ptr(error
, nmreq
, nd
->nd_vers
, nfh
.nfh_fhp
, nfh
.nfh_len
);
4637 error
= nfsrv_fhtovp(&nfh
, nd
, &vp
, &nx
, &nxo
);
4640 /* update export stats */
4641 NFSStatAdd64(&nx
->nx_stats
.ops
, 1);
4643 /* update active user stats */
4644 nfsrv_update_user_stat(nx
, nd
, kauth_cred_getuid(nd
->nd_cr
), 1, 0, 0);
4646 error
= nfsrv_credcheck(nd
, ctx
, nx
, nxo
);
4649 error
= VNOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
, ctx
);
4651 error
= VNOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
, ctx
);
4653 error
= VNOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
, ctx
);
4655 error
= VNOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
, ctx
);
4657 error
= VNOP_PATHCONF(vp
, _PC_CASE_SENSITIVE
, &case_sensitive
, ctx
);
4659 error
= VNOP_PATHCONF(vp
, _PC_CASE_PRESERVING
, &case_preserving
, ctx
);
4661 nfsm_srv_vattr_init(&attr
, NFS_VER3
);
4662 attrerr
= vnode_getattr(vp
, &attr
, ctx
);
4668 /* assemble reply */
4669 nd
->nd_repstat
= error
;
4670 error
= nfsrv_rephead(nd
, slp
, &nmrep
, NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
4672 *mrepp
= nmrep
.nmc_mhead
;
4673 nfsmout_on_status(nd
, error
);
4674 nfsm_chain_add_postop_attr(error
, nd
, &nmrep
, attrerr
, &attr
);
4675 nfsmout_if(nd
->nd_repstat
);
4677 nfsm_chain_add_32(error
, &nmrep
, linkmax
);
4678 nfsm_chain_add_32(error
, &nmrep
, namemax
);
4679 nfsm_chain_add_32(error
, &nmrep
, notrunc
);
4680 nfsm_chain_add_32(error
, &nmrep
, chownres
);
4681 nfsm_chain_add_32(error
, &nmrep
, !case_sensitive
);
4682 nfsm_chain_add_32(error
, &nmrep
, case_preserving
);
4685 nfsm_chain_build_done(error
, &nmrep
);
4687 nfsm_chain_cleanup(&nmrep
);
4694 * Null operation, used by clients to ping server
4699 struct nfsrv_descript
*nd
,
4700 struct nfsrv_sock
*slp
,
4701 __unused vfs_context_t ctx
,
4704 int error
= NFSERR_RETVOID
;
4705 struct nfsm_chain nmrep
;
4708 * RPCSEC_GSS context setup ?
4710 if (nd
->nd_gss_context
)
4711 return(nfs_gss_svc_ctx_init(nd
, slp
, mrepp
));
4713 nfsm_chain_null(&nmrep
);
4715 /* assemble reply */
4716 nd
->nd_repstat
= error
;
4717 error
= nfsrv_rephead(nd
, slp
, &nmrep
, 0);
4719 *mrepp
= nmrep
.nmc_mhead
;
4721 nfsm_chain_build_done(error
, &nmrep
);
4723 nfsm_chain_cleanup(&nmrep
);
4730 * No operation, used for obsolete procedures
4735 struct nfsrv_descript
*nd
,
4736 struct nfsrv_sock
*slp
,
4737 __unused vfs_context_t ctx
,
4741 struct nfsm_chain nmrep
;
4743 nfsm_chain_null(&nmrep
);
4746 error
= nd
->nd_repstat
;
4748 error
= EPROCUNAVAIL
;
4750 /* assemble reply */
4751 nd
->nd_repstat
= error
;
4752 error
= nfsrv_rephead(nd
, slp
, &nmrep
, 0);
4754 *mrepp
= nmrep
.nmc_mhead
;
4756 nfsm_chain_build_done(error
, &nmrep
);
4758 nfsm_chain_cleanup(&nmrep
);
4764 int (*nfsrv_procs
[NFS_NPROCS
])(struct nfsrv_descript
*nd
,
4765 struct nfsrv_sock
*slp
,
4794 * Perform access checking for vnodes obtained from file handles that would
4795 * refer to files already opened by a Unix client. You cannot just use
4796 * vnode_authorize() for two reasons.
4797 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4798 * 2 - The owner is to be given access irrespective of mode bits so that
4799 * processes that chmod after opening a file don't break. I don't like
4800 * this because it opens a security hole, but since the nfs server opens
4801 * a security hole the size of a barn door anyhow, what the heck.
4803 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, vnode_authorize()
4804 * will return EPERM instead of EACCESS. EPERM is always an error.
4811 kauth_action_t action
,
4813 struct nfs_export_options
*nxo
,
4816 struct vnode_attr vattr
;
4819 if (action
& KAUTH_VNODE_WRITE_RIGHTS
) {
4821 * Disallow write attempts on read-only exports;
4822 * unless the file is a socket or a block or character
4823 * device resident on the file system.
4825 if (nxo
->nxo_flags
& NX_READONLY
) {
4826 switch (vnode_vtype(vp
)) {
4827 case VREG
: case VDIR
: case VLNK
: case VCPLX
:
4834 error
= vnode_authorize(vp
, dvp
, action
, ctx
);
4836 * Allow certain operations for the owner (reads and writes
4837 * on files that are already open). Picking up from FreeBSD.
4839 if (override
&& (error
== EACCES
)) {
4841 VATTR_WANTED(&vattr
, va_uid
);
4842 if ((vnode_getattr(vp
, &vattr
, ctx
) == 0) &&
4843 (kauth_cred_getuid(vfs_context_ucred(ctx
)) == vattr
.va_uid
))
4849 #endif /* NFSSERVER */