2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
30 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
32 * Copyright (c) 1989, 1993
33 * The Regents of the University of California. All rights reserved.
35 * This code is derived from software contributed to Berkeley by
36 * Rick Macklem at The University of Guelph.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * @(#)nfs_serv.c 8.7 (Berkeley) 5/14/95
67 * FreeBSD-Id: nfs_serv.c,v 1.52 1997/10/28 15:59:05 bde Exp $
71 * nfs version 2 and 3 server calls to vnode ops
72 * - these routines generally have 3 phases
73 * 1 - break down and validate rpc request in mbuf list
74 * 2 - do the vnode ops for the request
75 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
76 * 3 - build the rpc reply in an mbuf list
78 * - do not mix the phases, since the nfsm_?? macros can return failures
79 * on a bad rpc or similar and do not do any vnode_rele()s or vnode_put()s
81 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
82 * error number iff error != 0 whereas
83 * returning an error from the server function implies a fatal error
84 * such as a badly constructed rpc request that should be dropped without
86 * For Version 3, nfsm_reply() does not return for the error case, since
87 * most version 3 rpcs return more than the status for error cases.
90 #include <sys/param.h>
91 #include <sys/systm.h>
93 #include <sys/kauth.h>
94 #include <sys/unistd.h>
95 #include <sys/malloc.h>
96 #include <sys/vnode.h>
97 #include <sys/mount_internal.h>
98 #include <sys/socket.h>
99 #include <sys/socketvar.h>
100 #include <sys/kpi_mbuf.h>
101 #include <sys/dirent.h>
102 #include <sys/stat.h>
103 #include <sys/kernel.h>
104 #include <sys/sysctl.h>
106 #include <sys/vnode_internal.h>
107 #include <sys/uio_internal.h>
108 #include <libkern/OSAtomic.h>
111 #include <sys/vmparam.h>
113 #include <nfs/nfsproto.h>
114 #include <nfs/rpcv2.h>
116 #include <nfs/xdr_subs.h>
117 #include <nfs/nfsm_subs.h>
119 nfstype nfsv3_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFSOCK
,
122 nfstype nfsv2_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFNON
,
125 extern u_long nfs_xdrneg1
;
126 extern u_long nfs_false
, nfs_true
;
127 extern enum vtype nv3tov_type
[8];
128 extern struct nfsstats nfsstats
;
130 int nfsrvw_procrastinate
= NFS_GATHERDELAY
* 1000;
131 int nfsrvw_procrastinate_v3
= 0;
135 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
136 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, async
, CTLFLAG_RW
, &nfs_async
, 0, "");
139 static int nfsrv_authorize(vnode_t
,vnode_t
,kauth_action_t
,vfs_context_t
,struct nfs_export_options
*,int);
140 static void nfsrvw_coalesce(struct nfsrv_descript
*, struct nfsrv_descript
*);
142 #define THREAD_SAFE_FS(VP) \
143 ((VP)->v_mount ? (VP)->v_mount->mnt_vtable->vfc_threadsafe : 0)
146 * nfs v3 access service
149 nfsrv3_access(nfsd
, slp
, procp
, mrq
)
150 struct nfsrv_descript
*nfsd
;
151 struct nfssvc_sock
*slp
;
155 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
156 mbuf_t nam
= nfsd
->nd_nam
;
157 caddr_t dpos
= nfsd
->nd_dpos
;
159 struct nfs_filehandle nfh
;
163 int error
= 0, getret
;
165 mbuf_t mb
, mreq
, mb2
;
166 struct vnode_attr vattr
, *vap
= &vattr
;
168 kauth_action_t testaction
;
169 struct vfs_context context
;
170 struct nfs_export
*nx
;
171 struct nfs_export_options
*nxo
;
174 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
175 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
176 nfsm_reply(NFSX_UNSIGNED
);
177 nfsm_srvpostop_attr(1, NULL
);
180 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
182 nfsm_reply(NFSX_UNSIGNED
);
183 nfsm_srvpostop_attr(1, NULL
);
186 nfsmode
= fxdr_unsigned(u_long
, *tl
);
188 context
.vc_proc
= procp
;
189 context
.vc_ucred
= nfsd
->nd_cr
;
192 * Each NFS mode bit is tested separately.
194 * XXX this code is nominally correct, but returns a pessimistic
195 * rather than optimistic result. It will be necessary to add
196 * an NFS-specific interface to the vnode_authorize code to
197 * obtain good performance in the optimistic mode.
199 if (nfsmode
& NFSV3ACCESS_READ
) {
200 if (vnode_isdir(vp
)) {
202 KAUTH_VNODE_LIST_DIRECTORY
|
203 KAUTH_VNODE_READ_EXTATTRIBUTES
;
206 KAUTH_VNODE_READ_DATA
|
207 KAUTH_VNODE_READ_EXTATTRIBUTES
;
209 if (nfsrv_authorize(vp
, NULL
, testaction
, &context
, nxo
, 0))
210 nfsmode
&= ~NFSV3ACCESS_READ
;
212 if ((nfsmode
& NFSV3ACCESS_LOOKUP
) &&
214 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, &context
, nxo
, 0)))
215 nfsmode
&= ~NFSV3ACCESS_LOOKUP
;
216 if (nfsmode
& NFSV3ACCESS_MODIFY
) {
217 if (vnode_isdir(vp
)) {
219 KAUTH_VNODE_ADD_FILE
|
220 KAUTH_VNODE_ADD_SUBDIRECTORY
|
221 KAUTH_VNODE_DELETE_CHILD
;
224 KAUTH_VNODE_WRITE_DATA
;
226 if (nfsrv_authorize(vp
, NULL
, testaction
, &context
, nxo
, 0))
227 nfsmode
&= ~NFSV3ACCESS_MODIFY
;
229 if (nfsmode
& NFSV3ACCESS_EXTEND
) {
230 if (vnode_isdir(vp
)) {
232 KAUTH_VNODE_ADD_FILE
|
233 KAUTH_VNODE_ADD_SUBDIRECTORY
;
236 KAUTH_VNODE_WRITE_DATA
|
237 KAUTH_VNODE_APPEND_DATA
;
239 if (nfsrv_authorize(vp
, NULL
, testaction
, &context
, nxo
, 0))
240 nfsmode
&= ~NFSV3ACCESS_EXTEND
;
244 * Note concerning NFSV3ACCESS_DELETE:
245 * For hard links, the answer may be wrong if the vnode
246 * has multiple parents with different permissions.
247 * Also, some clients (e.g. MacOSX 10.3) may incorrectly
248 * interpret the missing/cleared DELETE bit.
249 * So we'll just leave the DELETE bit alone. At worst,
250 * we're telling the client it might be able to do
251 * something it really can't.
254 if ((nfsmode
& NFSV3ACCESS_EXECUTE
) &&
256 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, &context
, nxo
, 0)))
257 nfsmode
&= ~NFSV3ACCESS_EXECUTE
;
259 nfsm_srv_vattr_init(vap
, 1);
260 getret
= vnode_getattr(vp
, vap
, &context
);
262 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED
);
263 nfsm_srvpostop_attr(getret
, vap
);
264 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
265 *tl
= txdr_unsigned(nfsmode
);
271 * nfs getattr service
274 nfsrv_getattr(nfsd
, slp
, procp
, mrq
)
275 struct nfsrv_descript
*nfsd
;
276 struct nfssvc_sock
*slp
;
280 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
281 mbuf_t nam
= nfsd
->nd_nam
;
282 caddr_t dpos
= nfsd
->nd_dpos
;
283 struct nfs_fattr
*fp
;
284 struct vnode_attr va
;
285 struct vnode_attr
*vap
= &va
;
287 struct nfs_filehandle nfh
;
293 mbuf_t mb
, mb2
, mreq
;
294 struct vfs_context context
;
295 struct nfs_export
*nx
;
296 struct nfs_export_options
*nxo
;
297 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
300 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
304 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
309 context
.vc_proc
= procp
;
310 context
.vc_ucred
= nfsd
->nd_cr
;
312 nfsm_srv_vattr_init(vap
, v3
);
313 error
= vnode_getattr(vp
, vap
, &context
);
315 nfsm_reply(NFSX_FATTR(v3
));
318 nfsm_build(fp
, struct nfs_fattr
*, NFSX_FATTR(v3
));
319 nfsm_srvfillattr(vap
, fp
);
325 * nfs setattr service
328 nfsrv_setattr(nfsd
, slp
, procp
, mrq
)
329 struct nfsrv_descript
*nfsd
;
330 struct nfssvc_sock
*slp
;
334 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
335 mbuf_t nam
= nfsd
->nd_nam
;
336 caddr_t dpos
= nfsd
->nd_dpos
;
337 struct vnode_attr preat
;
338 struct vnode_attr postat
;
339 struct vnode_attr va
;
340 struct vnode_attr
*vap
= &va
;
341 struct nfsv2_sattr
*sp
;
342 struct nfs_fattr
*fp
;
344 struct nfs_filehandle nfh
;
345 struct nfs_export
*nx
;
346 struct nfs_export_options
*nxo
;
350 int error
= 0, preat_ret
= 1, postat_ret
= 1;
351 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), gcheck
= 0;
353 mbuf_t mb
, mb2
, mreq
;
354 struct timespec guard
;
355 struct vfs_context context
;
356 kauth_action_t action
;
363 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
364 gcheck
= fxdr_unsigned(int, *tl
);
366 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
367 fxdr_nfsv3time(tl
, &guard
);
370 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
372 * Nah nah nah nah na nah
373 * There is a bug in the Sun client that puts 0xffff in the mode
374 * field of sattr when it should put in 0xffffffff. The u_short
375 * doesn't sign extend.
376 * --> check the low order 2 bytes for 0xffff
378 if ((fxdr_unsigned(int, sp
->sa_mode
) & 0xffff) != 0xffff)
379 VATTR_SET(vap
, va_mode
, nfstov_mode(sp
->sa_mode
));
380 if (sp
->sa_uid
!= nfs_xdrneg1
)
381 VATTR_SET(vap
, va_uid
, fxdr_unsigned(uid_t
, sp
->sa_uid
));
382 if (sp
->sa_gid
!= nfs_xdrneg1
)
383 VATTR_SET(vap
, va_gid
, fxdr_unsigned(gid_t
, sp
->sa_gid
));
384 if (sp
->sa_size
!= nfs_xdrneg1
)
385 VATTR_SET(vap
, va_data_size
, fxdr_unsigned(u_quad_t
, sp
->sa_size
));
386 if (sp
->sa_atime
.nfsv2_sec
!= nfs_xdrneg1
) {
387 fxdr_nfsv2time(&sp
->sa_atime
, &vap
->va_access_time
);
388 VATTR_SET_ACTIVE(vap
, va_access_time
);
390 if (sp
->sa_mtime
.nfsv2_sec
!= nfs_xdrneg1
) {
391 fxdr_nfsv2time(&sp
->sa_mtime
, &vap
->va_modify_time
);
392 VATTR_SET_ACTIVE(vap
, va_modify_time
);
397 * Save the original credential UID in case they are
398 * mapped and we need to map the IDs in the attributes.
400 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
403 * Now that we have all the fields, lets do it.
405 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
406 nfsm_reply(2 * NFSX_UNSIGNED
);
407 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
410 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
412 nfsm_reply(2 * NFSX_UNSIGNED
);
413 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
417 context
.vc_proc
= procp
;
418 context
.vc_ucred
= nfsd
->nd_cr
;
421 nfsm_srv_pre_vattr_init(&preat
, v3
);
422 error
= preat_ret
= vnode_getattr(vp
, &preat
, &context
);
423 if (!error
&& gcheck
&& VATTR_IS_SUPPORTED(&preat
, va_change_time
) &&
424 (preat
.va_change_time
.tv_sec
!= guard
.tv_sec
||
425 preat
.va_change_time
.tv_nsec
!= guard
.tv_nsec
))
426 error
= NFSERR_NOT_SYNC
;
427 if (!preat_ret
&& !VATTR_ALL_SUPPORTED(&preat
))
431 nfsm_reply(NFSX_WCCDATA(v3
));
432 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
438 * If the credentials were mapped, we should
439 * map the same values in the attributes.
441 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
443 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
444 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
445 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
449 * Authorize the attribute changes.
451 if (((error
= vnode_authattr(vp
, vap
, &action
, &context
))) ||
452 ((error
= nfsrv_authorize(vp
, NULL
, action
, &context
, nxo
, 0))))
454 error
= vnode_setattr(vp
, vap
, &context
);
456 nfsm_srv_vattr_init(&postat
, v3
);
457 postat_ret
= vnode_getattr(vp
, &postat
, &context
);
462 nfsm_reply(NFSX_WCCORFATTR(v3
));
464 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
467 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
468 nfsm_srvfillattr(&postat
, fp
);
478 nfsrv_lookup(nfsd
, slp
, procp
, mrq
)
479 struct nfsrv_descript
*nfsd
;
480 struct nfssvc_sock
*slp
;
484 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
485 mbuf_t nam
= nfsd
->nd_nam
;
486 caddr_t dpos
= nfsd
->nd_dpos
;
487 struct nfs_fattr
*fp
;
488 struct nameidata nd
, *ndp
= &nd
;
489 /* XXX Revisit when enabling WebNFS */
490 #ifdef WEBNFS_ENABLED
491 struct nameidata ind
;
493 vnode_t vp
, dirp
= NULL
;
494 struct nfs_filehandle dnfh
, nfh
;
495 struct nfs_export
*nx
;
496 struct nfs_export_options
*nxo
;
501 int error
= 0, len
, dirattr_ret
= 1, isdotdot
;
502 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), pubflag
;
504 mbuf_t mb
, mb2
, mreq
;
505 struct vnode_attr va
, dirattr
, *vap
= &va
;
506 struct vfs_context context
;
508 context
.vc_proc
= procp
;
509 context
.vc_ucred
= nfsd
->nd_cr
;
511 nfsm_srvmtofh(&dnfh
);
512 nfsm_srvnamesiz(len
, v3
);
514 pubflag
= nfs_ispublicfh(&dnfh
);
516 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
517 nd
.ni_cnd
.cn_flags
= LOCKLEAF
;
518 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, pubflag
, &len
, &nd
);
519 isdotdot
= ((len
== 2) && (nd
.ni_cnd
.cn_pnbuf
[0] == '.') && (nd
.ni_cnd
.cn_pnbuf
[1] == '.'));
521 error
= nfs_namei(nfsd
, &context
, &nd
, &dnfh
, nam
, pubflag
, &dirp
, &nx
, &nxo
);
523 /* XXX Revisit when enabling WebNFS */
524 #ifdef WEBNFS_ENABLED
525 if (!error
&& pubflag
) {
526 if (vnode_vtype(nd
.ni_vp
) == VDIR
&& nfs_pub
.np_index
!= NULL
) {
528 * Setup call to lookup() to see if we can find
529 * the index file. Arguably, this doesn't belong
533 ind
.ni_pathlen
= strlen(nfs_pub
.np_index
);
534 ind
.ni_cnd
.cn_nameptr
= ind
.ni_cnd
.cn_pnbuf
=
536 ind
.ni_startdir
= nd
.ni_vp
;
537 ind
.ni_usedvp
= nd
.ni_vp
;
539 if (!(error
= lookup(&ind
))) {
541 * Found an index file. Get rid of
542 * the old references.
547 vnode_put(nd
.ni_startdir
);
553 * If the public filehandle was used, check that this lookup
554 * didn't result in a filehandle outside the publicly exported
558 if (!error
&& vnode_mount(ndp
->ni_vp
) != nfs_pub
.np_mount
) {
568 nfsm_srv_vattr_init(&dirattr
, v3
);
569 dirattr_ret
= vnode_getattr(dirp
, &dirattr
, &context
);
575 nfsm_reply(NFSX_POSTOPATTR(v3
));
576 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
582 error
= nfsrv_vptofh(nx
, !v3
, (isdotdot
? &dnfh
: NULL
), vp
, &context
, &nfh
);
584 nfsm_srv_vattr_init(vap
, v3
);
585 error
= vnode_getattr(vp
, vap
, &context
);
588 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_POSTOPORFATTR(v3
) + NFSX_POSTOPATTR(v3
));
590 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
593 nfsm_srvfhtom(&nfh
, v3
);
595 nfsm_srvpostop_attr(0, vap
);
596 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
598 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
599 nfsm_srvfillattr(vap
, fp
);
606 * nfs readlink service
609 nfsrv_readlink(nfsd
, slp
, procp
, mrq
)
610 struct nfsrv_descript
*nfsd
;
611 struct nfssvc_sock
*slp
;
615 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
616 mbuf_t nam
= nfsd
->nd_nam
;
617 caddr_t dpos
= nfsd
->nd_dpos
;
622 int error
= 0, i
, tlen
, len
, getret
= 1;
623 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
625 mbuf_t mb
, mb2
, mp2
, mp3
, mreq
;
627 struct vnode_attr attr
;
628 struct nfs_filehandle nfh
;
629 struct nfs_export
*nx
;
630 struct nfs_export_options
*nxo
;
632 char uio_buf
[ UIO_SIZEOF(4) ];
633 char *uio_bufp
= &uio_buf
[0];
634 int uio_buflen
= UIO_SIZEOF(4);
636 struct vfs_context context
;
644 while (len
< NFS_MAXPATHLEN
) {
646 if ((error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mp
)))
648 mblen
= mbuf_maxlen(mp
);
649 mbuf_setlen(mp
, mblen
);
653 if ((error
= mbuf_setnext(mp2
, mp
))) {
659 if ((len
+ mblen
) > NFS_MAXPATHLEN
) {
660 mbuf_setlen(mp
, NFS_MAXPATHLEN
- len
);
661 len
= NFS_MAXPATHLEN
;
667 uio_buflen
= UIO_SIZEOF(i
);
668 MALLOC(uio_bufp
, char*, uio_buflen
, M_TEMP
, M_WAITOK
);
672 nfsm_reply(2 * NFSX_UNSIGNED
);
673 nfsm_srvpostop_attr(1, NULL
);
677 uiop
= uio_createwithbuffer(i
, 0, UIO_SYSSPACE
, UIO_READ
, uio_bufp
, uio_buflen
);
681 if (uio_bufp
!= &uio_buf
[0]) {
682 FREE(uio_bufp
, M_TEMP
);
683 uio_bufp
= &uio_buf
[0];
685 nfsm_reply(2 * NFSX_UNSIGNED
);
686 nfsm_srvpostop_attr(1, NULL
);
691 uio_addiov(uiop
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), mbuf_len(mp
));
695 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
697 if (uio_bufp
!= &uio_buf
[0]) {
698 FREE(uio_bufp
, M_TEMP
);
699 uio_bufp
= &uio_buf
[0];
701 nfsm_reply(2 * NFSX_UNSIGNED
);
702 nfsm_srvpostop_attr(1, NULL
);
705 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
708 if (uio_bufp
!= &uio_buf
[0]) {
709 FREE(uio_bufp
, M_TEMP
);
710 uio_bufp
= &uio_buf
[0];
712 nfsm_reply(2 * NFSX_UNSIGNED
);
713 nfsm_srvpostop_attr(1, NULL
);
716 if (vnode_vtype(vp
) != VLNK
) {
724 context
.vc_proc
= procp
;
725 context
.vc_ucred
= nfsd
->nd_cr
;
727 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
, nxo
, 0)))
729 error
= VNOP_READLINK(vp
, uiop
, &context
);
733 nfsm_srv_vattr_init(&attr
, v3
);
734 getret
= vnode_getattr(vp
, &attr
, &context
);
742 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_UNSIGNED
);
744 nfsm_srvpostop_attr(getret
, &attr
);
746 if (uio_bufp
!= &uio_buf
[0])
747 FREE(uio_bufp
, M_TEMP
);
752 if (uiop
&& (uio_resid(uiop
) > 0)) {
753 // LP64todo - fix this
754 len
-= uio_resid(uiop
);
755 tlen
= nfsm_rndup(len
);
756 nfsm_adj(mp3
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
758 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
759 *tl
= txdr_unsigned(len
);
760 mbuf_setnext(mb
, mp3
);
763 if (uio_bufp
!= &uio_buf
[0])
764 FREE(uio_bufp
, M_TEMP
);
772 nfsrv_read(nfsd
, slp
, procp
, mrq
)
773 struct nfsrv_descript
*nfsd
;
774 struct nfssvc_sock
*slp
;
778 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
779 mbuf_t nam
= nfsd
->nd_nam
;
780 caddr_t dpos
= nfsd
->nd_dpos
;
782 struct nfs_fattr
*fp
;
787 int error
= 0, count
, len
, left
, siz
, tlen
, getret
;
788 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), reqlen
, maxlen
;
790 mbuf_t mb
, mb2
, mreq
;
793 struct nfs_filehandle nfh
;
794 struct nfs_export
*nx
;
795 struct nfs_export_options
*nxo
;
797 char *uio_bufp
= NULL
;
798 struct vnode_attr va
, *vap
= &va
;
800 char uio_buf
[ UIO_SIZEOF(0) ];
801 struct vfs_context context
;
805 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
806 fxdr_hyper(tl
, &off
);
808 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
809 off
= (off_t
)fxdr_unsigned(u_long
, *tl
);
811 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
812 reqlen
= fxdr_unsigned(u_long
, *tl
);
813 maxlen
= NFS_SRVMAXDATA(nfsd
);
817 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
818 nfsm_reply(2 * NFSX_UNSIGNED
);
819 nfsm_srvpostop_attr(1, NULL
);
822 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
824 nfsm_reply(2 * NFSX_UNSIGNED
);
825 nfsm_srvpostop_attr(1, NULL
);
828 if (vnode_vtype(vp
) != VREG
) {
832 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
835 context
.vc_proc
= procp
;
836 context
.vc_ucred
= nfsd
->nd_cr
;
839 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
, nxo
, 1)))
840 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, &context
, nxo
, 1);
842 nfsm_srv_vattr_init(vap
, v3
);
843 getret
= vnode_getattr(vp
, vap
, &context
);
848 nfsm_reply(NFSX_POSTOPATTR(v3
));
849 nfsm_srvpostop_attr(getret
, vap
);
852 if ((u_quad_t
)off
>= vap
->va_data_size
)
854 else if (((u_quad_t
)off
+ reqlen
) > vap
->va_data_size
)
855 count
= nfsm_rndup(vap
->va_data_size
- off
);
858 nfsm_reply(NFSX_POSTOPORFATTR(v3
) + 3 * NFSX_UNSIGNED
+nfsm_rndup(count
));
860 nfsm_build(tl
, u_long
*, NFSX_V3FATTR
+ 4 * NFSX_UNSIGNED
);
862 fp
= (struct nfs_fattr
*)tl
;
863 tl
+= (NFSX_V3FATTR
/ sizeof (u_long
));
865 nfsm_build(tl
, u_long
*, NFSX_V2FATTR
+ NFSX_UNSIGNED
);
866 fp
= (struct nfs_fattr
*)tl
;
867 tl
+= (NFSX_V2FATTR
/ sizeof (u_long
));
872 * Generate the mbuf list with the uio_iov ref. to it.
877 siz
= min(mbuf_trailingspace(m
), left
);
884 if ((error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &m
)))
890 MALLOC(uio_bufp
, char *, UIO_SIZEOF(i
), M_TEMP
, M_WAITOK
);
895 uiop
= uio_createwithbuffer(i
, off
, UIO_SYSSPACE
, UIO_READ
,
896 uio_bufp
, UIO_SIZEOF(i
));
906 panic("nfsrv_read iov");
907 siz
= min(mbuf_trailingspace(m
), left
);
910 uio_addiov(uiop
, CAST_USER_ADDR_T((char *)mbuf_data(m
) + tlen
), siz
);
911 mbuf_setlen(m
, tlen
+ siz
);
917 error
= VNOP_READ(vp
, uiop
, IO_NODELOCKED
, &context
);
918 off
= uio_offset(uiop
);
921 * This may seem a little weird that we drop the whole
922 * successful read if we get an error on the getattr.
923 * The reason is because we've already set up the reply
924 * to have postop attrs and omitting these optional bits
925 * would require shifting all the data in the reply.
927 * It would be more correct if we would simply drop the
928 * postop attrs if the getattr fails. We might be able to
929 * do that easier if we allocated separate mbufs for the data.
931 nfsm_srv_vattr_init(vap
, v3
);
932 if (error
|| (getret
= vnode_getattr(vp
, vap
, &context
))) {
937 nfsm_reply(NFSX_POSTOPATTR(v3
));
938 nfsm_srvpostop_attr(getret
, vap
);
939 if (uio_bufp
!= NULL
) {
940 FREE(uio_bufp
, M_TEMP
);
945 uiop
= uio_createwithbuffer(0, 0, UIO_SYSSPACE
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
952 nfsm_srvfillattr(vap
, fp
);
953 // LP64todo - fix this
954 len
-= uio_resid(uiop
);
955 tlen
= nfsm_rndup(len
);
956 if (count
!= tlen
|| tlen
!= len
)
957 nfsm_adj(mb
, count
- tlen
, tlen
- len
);
959 *tl
++ = txdr_unsigned(len
);
965 *tl
= txdr_unsigned(len
);
967 if (uio_bufp
!= NULL
) {
968 FREE(uio_bufp
, M_TEMP
);
977 nfsrv_write(nfsd
, slp
, procp
, mrq
)
978 struct nfsrv_descript
*nfsd
;
979 struct nfssvc_sock
*slp
;
983 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
984 mbuf_t nam
= nfsd
->nd_nam
;
985 caddr_t dpos
= nfsd
->nd_dpos
;
988 struct nfs_fattr
*fp
;
989 struct vnode_attr va
, forat
;
990 struct vnode_attr
*vap
= &va
;
994 int error
= 0, len
, forat_ret
= 1;
995 int ioflags
, aftat_ret
= 1, retlen
, zeroing
, adjust
, tlen
;
996 int stable
= NFSV3WRITE_FILESYNC
;
997 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
999 mbuf_t mb
, mb2
, mreq
;
1001 struct nfs_filehandle nfh
;
1002 struct nfs_export
*nx
;
1003 struct nfs_export_options
*nxo
;
1006 char *uio_bufp
= NULL
;
1007 struct vfs_context context
;
1013 nfsm_srvmtofh(&nfh
);
1015 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1016 fxdr_hyper(tl
, &off
);
1018 stable
= fxdr_unsigned(int, *tl
++);
1020 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1021 off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
1024 stable
= NFSV3WRITE_UNSTABLE
;
1026 retlen
= len
= fxdr_unsigned(long, *tl
);
1030 * For NFS Version 2, it is not obvious what a write of zero length
1031 * should do, but I might as well be consistent with Version 3,
1032 * which is to return ok so long as there are no permission problems.
1040 tpos
= mbuf_data(mp
);
1041 tlen
= mbuf_len(mp
);
1042 adjust
= dpos
- tpos
;
1044 mbuf_setlen(mp
, tlen
);
1045 if (tlen
> 0 && adjust
> 0) {
1047 if ((error
= mbuf_setdata(mp
, tpos
, tlen
))) {
1048 nfsm_reply(2 * NFSX_UNSIGNED
);
1049 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1056 else if ((tlen
= mbuf_len(mp
)) > 0) {
1059 mbuf_setlen(mp
, tlen
- (i
- len
));
1062 if (mbuf_len(mp
) > 0)
1068 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1070 nfsm_reply(2 * NFSX_UNSIGNED
);
1071 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1074 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
1075 nfsm_reply(2 * NFSX_UNSIGNED
);
1076 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1079 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
1081 nfsm_reply(2 * NFSX_UNSIGNED
);
1082 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1085 context
.vc_proc
= procp
;
1086 context
.vc_ucred
= nfsd
->nd_cr
;
1089 nfsm_srv_pre_vattr_init(&forat
, v3
);
1090 forat_ret
= vnode_getattr(vp
, &forat
, &context
);
1092 if (vnode_vtype(vp
) != VREG
) {
1096 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1099 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, &context
, nxo
, 1);
1103 nfsm_reply(NFSX_WCCDATA(v3
));
1104 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1109 MALLOC(uio_bufp
, char *, UIO_SIZEOF(count
), M_TEMP
, M_WAITOK
);
1113 nfsm_reply(NFSX_WCCDATA(v3
));
1114 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1117 uiop
= uio_createwithbuffer(count
, off
, UIO_SYSSPACE
, UIO_WRITE
, uio_bufp
, UIO_SIZEOF(count
));
1121 nfsm_reply(NFSX_WCCDATA(v3
));
1122 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1123 if (uio_bufp
!= NULL
) {
1124 FREE(uio_bufp
, M_TEMP
);
1130 if ((tlen
= mbuf_len(mp
)) > 0)
1131 uio_addiov(uiop
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), tlen
);
1137 * The IO_METASYNC flag indicates that all metadata (and not just
1138 * enough to ensure data integrity) mus be written to stable storage
1140 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1142 if (stable
== NFSV3WRITE_UNSTABLE
)
1143 ioflags
= IO_NODELOCKED
;
1144 else if (stable
== NFSV3WRITE_DATASYNC
)
1145 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1147 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1149 error
= VNOP_WRITE(vp
, uiop
, ioflags
, &context
);
1150 OSAddAtomic(1, (SInt32
*)(SInt32
*)&nfsstats
.srvvop_writes
);
1152 nfsm_srv_vattr_init(vap
, v3
);
1153 aftat_ret
= vnode_getattr(vp
, vap
, &context
);
1157 nfsm_reply(NFSX_PREOPATTR(v3
) + NFSX_POSTOPORFATTR(v3
) +
1158 2 * NFSX_UNSIGNED
+ NFSX_WRITEVERF(v3
));
1160 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1162 if (uio_bufp
!= NULL
) {
1163 FREE(uio_bufp
, M_TEMP
);
1167 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1168 *tl
++ = txdr_unsigned(retlen
);
1170 * If nfs_async is set, then pretend the write was FILESYNC.
1172 if (stable
== NFSV3WRITE_UNSTABLE
&& !nfs_async
)
1173 *tl
++ = txdr_unsigned(stable
);
1175 *tl
++ = txdr_unsigned(NFSV3WRITE_FILESYNC
);
1177 * Actually, there is no need to txdr these fields,
1178 * but it may make the values more human readable,
1179 * for debugging purposes.
1181 *tl
++ = txdr_unsigned(boottime_sec());
1182 *tl
= txdr_unsigned(0);
1184 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1185 nfsm_srvfillattr(vap
, fp
);
1188 if (uio_bufp
!= NULL
) {
1189 FREE(uio_bufp
, M_TEMP
);
1195 * NFS write service with write gathering support. Called when
1196 * nfsrvw_procrastinate > 0.
1197 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1198 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1202 nfsrv_writegather(ndp
, slp
, procp
, mrq
)
1203 struct nfsrv_descript
**ndp
;
1204 struct nfssvc_sock
*slp
;
1209 struct nfsrv_descript
*wp
, *nfsd
, *owp
, *swp
;
1210 struct nfs_export
*nx
;
1211 struct nfs_export_options
*nxo
;
1212 struct nfs_fattr
*fp
;
1214 struct nfsrvw_delayhash
*wpp
;
1216 struct vnode_attr va
, forat
;
1219 caddr_t bpos
, dpos
, tpos
;
1220 int error
= 0, len
, forat_ret
= 1;
1221 int ioflags
, aftat_ret
= 1, adjust
, v3
, zeroing
, tlen
;
1223 mbuf_t mb
, mb2
, mreq
, mrep
, md
;
1226 char *uio_bufp
= NULL
;
1229 struct vfs_context context
;
1231 context
.vc_proc
= procp
;
1242 mrep
= nfsd
->nd_mrep
;
1244 dpos
= nfsd
->nd_dpos
;
1246 context
.vc_ucred
= cred
;
1247 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1248 LIST_INIT(&nfsd
->nd_coalesce
);
1249 nfsd
->nd_mreq
= NULL
;
1250 nfsd
->nd_stable
= NFSV3WRITE_FILESYNC
;
1252 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1253 nfsd
->nd_time
= cur_usec
+
1254 (v3
? nfsrvw_procrastinate_v3
: nfsrvw_procrastinate
);
1257 * Now, get the write header..
1259 nfsm_srvmtofh(&nfsd
->nd_fh
);
1260 /* XXX shouldn't we be checking for invalid FHs before doing any more work? */
1262 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1263 fxdr_hyper(tl
, &nfsd
->nd_off
);
1265 nfsd
->nd_stable
= fxdr_unsigned(int, *tl
++);
1267 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1268 nfsd
->nd_off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
1271 nfsd
->nd_stable
= NFSV3WRITE_UNSTABLE
;
1273 len
= fxdr_unsigned(long, *tl
);
1275 nfsd
->nd_eoff
= nfsd
->nd_off
+ len
;
1278 * Trim the header out of the mbuf list and trim off any trailing
1279 * junk so that the mbuf list has only the write data.
1287 tpos
= mbuf_data(mp
);
1288 tlen
= mbuf_len(mp
);
1289 adjust
= dpos
- tpos
;
1291 mbuf_setlen(mp
, tlen
);
1292 if (tlen
> 0 && adjust
> 0) {
1294 if ((error
= mbuf_setdata(mp
, tpos
, tlen
)))
1301 tlen
= mbuf_len(mp
);
1304 mbuf_setlen(mp
, tlen
- (i
- len
));
1310 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1315 nfsm_writereply(2 * NFSX_UNSIGNED
, v3
);
1317 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1318 nfsd
->nd_mreq
= mreq
;
1319 nfsd
->nd_mrep
= NULL
;
1324 * Add this entry to the hash and time queues.
1326 lck_mtx_lock(&slp
->ns_wgmutex
);
1328 wp
= slp
->ns_tq
.lh_first
;
1329 while (wp
&& wp
->nd_time
< nfsd
->nd_time
) {
1331 wp
= wp
->nd_tq
.le_next
;
1334 LIST_INSERT_AFTER(owp
, nfsd
, nd_tq
);
1336 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1338 if (nfsd
->nd_mrep
) {
1339 wpp
= NWDELAYHASH(slp
, nfsd
->nd_fh
.nfh_fid
);
1342 while (wp
&& !nfsrv_fhmatch(&nfsd
->nd_fh
, &wp
->nd_fh
)) {
1344 wp
= wp
->nd_hash
.le_next
;
1346 while (wp
&& (wp
->nd_off
< nfsd
->nd_off
) &&
1347 nfsrv_fhmatch(&nfsd
->nd_fh
, &wp
->nd_fh
)) {
1349 wp
= wp
->nd_hash
.le_next
;
1352 LIST_INSERT_AFTER(owp
, nfsd
, nd_hash
);
1355 * Search the hash list for overlapping entries and
1358 for(; nfsd
&& NFSW_CONTIG(owp
, nfsd
); nfsd
= wp
) {
1359 wp
= nfsd
->nd_hash
.le_next
;
1360 if (NFSW_SAMECRED(owp
, nfsd
))
1361 nfsrvw_coalesce(owp
, nfsd
);
1364 LIST_INSERT_HEAD(wpp
, nfsd
, nd_hash
);
1368 lck_mtx_lock(&slp
->ns_wgmutex
);
1372 * Now, do VNOP_WRITE()s for any one(s) that need to be done now
1373 * and generate the associated reply mbuf list(s).
1377 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1378 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= owp
) {
1379 owp
= nfsd
->nd_tq
.le_next
;
1380 if (nfsd
->nd_time
> cur_usec
)
1384 LIST_REMOVE(nfsd
, nd_tq
);
1385 LIST_REMOVE(nfsd
, nd_hash
);
1386 mrep
= nfsd
->nd_mrep
;
1387 nfsd
->nd_mrep
= NULL
;
1388 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1389 forat_ret
= aftat_ret
= 1;
1390 error
= nfsrv_fhtovp(&nfsd
->nd_fh
, nfsd
->nd_nam
, TRUE
, &vp
, &nx
, &nxo
);
1392 error
= nfsrv_credcheck(nfsd
, nx
, nxo
);
1397 context
.vc_ucred
= cred
;
1400 nfsm_srv_pre_vattr_init(&forat
, v3
);
1401 forat_ret
= vnode_getattr(vp
, &forat
, &context
);
1403 if (vnode_vtype(vp
) != VREG
) {
1407 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1412 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, &context
, nxo
, 1);
1415 if (nfsd
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1416 ioflags
= IO_NODELOCKED
;
1417 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
)
1418 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1420 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1422 if (!error
&& ((nfsd
->nd_eoff
- nfsd
->nd_off
) > 0)) {
1426 if (mbuf_len(mp
) > 0)
1431 MALLOC(uio_bufp
, char *, UIO_SIZEOF(i
), M_TEMP
, M_WAITOK
);
1433 uiop
= uio_createwithbuffer(i
, nfsd
->nd_off
, UIO_SYSSPACE
,
1434 UIO_WRITE
, uio_bufp
, UIO_SIZEOF(i
));
1435 if (!uio_bufp
|| !uiop
)
1440 if ((tlen
= mbuf_len(mp
)) > 0)
1441 uio_addiov(uiop
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), tlen
);
1444 error
= VNOP_WRITE(vp
, uiop
, ioflags
, &context
);
1445 OSAddAtomic(1, (SInt32
*)&nfsstats
.srvvop_writes
);
1448 FREE(uio_bufp
, M_TEMP
);
1455 nfsm_srv_pre_vattr_init(&va
, v3
);
1456 aftat_ret
= vnode_getattr(vp
, &va
, &context
);
1461 * Loop around generating replies for all write rpcs that have
1462 * now been completed.
1467 nfsm_writereply(NFSX_WCCDATA(v3
), v3
);
1469 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1472 nfsm_writereply(NFSX_PREOPATTR(v3
) +
1473 NFSX_POSTOPORFATTR(v3
) + 2 * NFSX_UNSIGNED
+
1474 NFSX_WRITEVERF(v3
), v3
);
1476 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1477 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1478 *tl
++ = txdr_unsigned(nfsd
->nd_len
);
1479 *tl
++ = txdr_unsigned(swp
->nd_stable
);
1481 * Actually, there is no need to txdr these fields,
1482 * but it may make the values more human readable,
1483 * for debugging purposes.
1485 *tl
++ = txdr_unsigned(boottime_sec());
1486 *tl
= txdr_unsigned(0);
1488 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1489 nfsm_srvfillattr(&va
, fp
);
1492 nfsd
->nd_mreq
= mreq
;
1494 panic("nfsrv_write: nd_mrep not free");
1497 * Done. Put it at the head of the timer queue so that
1498 * the final phase can return the reply.
1502 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1504 nfsd
= swp
->nd_coalesce
.lh_first
;
1506 LIST_REMOVE(nfsd
, nd_tq
);
1510 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1515 * Search for a reply to return.
1517 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= nfsd
->nd_tq
.le_next
)
1518 if (nfsd
->nd_mreq
) {
1519 LIST_REMOVE(nfsd
, nd_tq
);
1520 *mrq
= nfsd
->nd_mreq
;
1524 slp
->ns_wgtime
= slp
->ns_tq
.lh_first
? slp
->ns_tq
.lh_first
->nd_time
: 0;
1525 lck_mtx_unlock(&slp
->ns_wgmutex
);
1530 * Coalesce the write request nfsd into owp. To do this we must:
1531 * - remove nfsd from the queues
1532 * - merge nfsd->nd_mrep into owp->nd_mrep
1533 * - update the nd_eoff and nd_stable for owp
1534 * - put nfsd on owp's nd_coalesce list
1538 struct nfsrv_descript
*owp
,
1539 struct nfsrv_descript
*nfsd
)
1543 struct nfsrv_descript
*p
;
1545 LIST_REMOVE(nfsd
, nd_hash
);
1546 LIST_REMOVE(nfsd
, nd_tq
);
1547 if (owp
->nd_eoff
< nfsd
->nd_eoff
) {
1548 overlap
= owp
->nd_eoff
- nfsd
->nd_off
;
1550 panic("nfsrv_coalesce: bad off");
1552 mbuf_adj(nfsd
->nd_mrep
, overlap
);
1554 while ((mpnext
= mbuf_next(mp
)))
1556 error
= mbuf_setnext(mp
, nfsd
->nd_mrep
);
1558 panic("nfsrvw_coalesce: mbuf_setnext failed: %d", error
);
1559 owp
->nd_eoff
= nfsd
->nd_eoff
;
1561 mbuf_freem(nfsd
->nd_mrep
);
1563 nfsd
->nd_mrep
= NULL
;
1564 if (nfsd
->nd_stable
== NFSV3WRITE_FILESYNC
)
1565 owp
->nd_stable
= NFSV3WRITE_FILESYNC
;
1566 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
&&
1567 owp
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1568 owp
->nd_stable
= NFSV3WRITE_DATASYNC
;
1569 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nfsd
, nd_tq
);
1572 * If nfsd had anything else coalesced into it, transfer them
1573 * to owp, otherwise their replies will never get sent.
1575 for (p
= nfsd
->nd_coalesce
.lh_first
; p
;
1576 p
= nfsd
->nd_coalesce
.lh_first
) {
1577 LIST_REMOVE(p
, nd_tq
);
1578 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1583 * Sort the group list in increasing numerical order.
1584 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1585 * that used to be here.)
1590 nfsrvw_sort(list
, num
)
1597 /* Insertion sort. */
1598 for (i
= 1; i
< num
; i
++) {
1600 /* find correct slot for value v, moving others up */
1601 for (j
= i
; --j
>= 0 && v
< list
[j
];)
1602 list
[j
+ 1] = list
[j
];
1608 * copy credentials making sure that the result can be compared with bcmp().
1613 nfsrv_setcred(kauth_cred_t incred
, kauth_cred_t outcred
)
1617 bzero((caddr_t
)outcred
, sizeof (*outcred
));
1618 outcred
->cr_ref
= 1;
1619 outcred
->cr_uid
= kauth_cred_getuid(incred
);
1620 outcred
->cr_ngroups
= incred
->cr_ngroups
;
1621 for (i
= 0; i
< incred
->cr_ngroups
; i
++)
1622 outcred
->cr_groups
[i
] = incred
->cr_groups
[i
];
1623 nfsrvw_sort(outcred
->cr_groups
, outcred
->cr_ngroups
);
1627 * nfs create service
1628 * now does a truncate to 0 length via. setattr if it already exists
1631 nfsrv_create(nfsd
, slp
, procp
, mrq
)
1632 struct nfsrv_descript
*nfsd
;
1633 struct nfssvc_sock
*slp
;
1637 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
1638 mbuf_t nam
= nfsd
->nd_nam
;
1639 caddr_t dpos
= nfsd
->nd_dpos
;
1640 struct nfs_fattr
*fp
;
1641 struct vnode_attr dirfor
, diraft
, postat
;
1642 struct vnode_attr va
;
1643 struct vnode_attr
*vap
= &va
;
1644 struct nfsv2_sattr
*sp
;
1646 struct nameidata nd
;
1650 int error
= 0, rdev
, len
, tsize
, dirfor_ret
= 1, diraft_ret
= 1;
1651 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), how
, exclusive_flag
= 0;
1653 mbuf_t mb
, mb2
, mreq
;
1654 vnode_t vp
, dvp
, dirp
= NULL
;
1655 struct nfs_filehandle nfh
;
1656 struct nfs_export
*nx
;
1657 struct nfs_export_options
*nxo
;
1659 u_char cverf
[NFSX_V3CREATEVERF
];
1660 struct vfs_context context
;
1663 context
.vc_proc
= procp
;
1664 context
.vc_ucred
= nfsd
->nd_cr
;
1667 * Save the original credential UID in case they are
1668 * mapped and we need to map the IDs in the attributes.
1670 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
1675 nd
.ni_cnd
.cn_nameiop
= 0;
1677 nfsm_srvmtofh(&nfh
);
1678 nfsm_srvnamesiz(len
, v3
);
1680 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1681 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1682 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
1684 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
1687 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
1688 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
1695 nd
.ni_cnd
.cn_nameiop
= 0;
1696 nfsm_reply(NFSX_WCCDATA(v3
));
1697 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1708 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
1709 how
= fxdr_unsigned(int, *tl
);
1711 case NFSV3CREATE_GUARDED
:
1716 case NFSV3CREATE_UNCHECKED
:
1719 case NFSV3CREATE_EXCLUSIVE
:
1720 nfsm_dissect(cp
, caddr_t
, NFSX_V3CREATEVERF
);
1721 bcopy(cp
, cverf
, NFSX_V3CREATEVERF
);
1724 VATTR_SET(vap
, va_mode
, 0);
1727 VATTR_SET(vap
, va_type
, VREG
);
1731 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1732 v_type
= IFTOVT(fxdr_unsigned(u_long
, sp
->sa_mode
));
1735 VATTR_SET(vap
, va_type
, v_type
);
1736 VATTR_SET(vap
, va_mode
, nfstov_mode(sp
->sa_mode
));
1740 tsize
= fxdr_unsigned(long, sp
->sa_size
);
1742 VATTR_SET(vap
, va_data_size
, (u_quad_t
)tsize
);
1747 rdev
= fxdr_unsigned(long, sp
->sa_size
);
1755 * If it doesn't exist, create it
1756 * otherwise just truncate to 0 length
1757 * should I set the mode too ??
1760 kauth_acl_t xacl
= NULL
;
1763 * If the credentials were mapped, we should
1764 * map the same values in the attributes.
1766 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
1768 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
1769 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
1770 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
1773 /* authorize before creating */
1774 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
1776 /* construct ACL and handle inheritance */
1778 error
= kauth_acl_inherit(dvp
,
1784 if (!error
&& xacl
!= NULL
)
1785 VATTR_SET(vap
, va_acl
, xacl
);
1787 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
1788 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
1790 /* validate new-file security information */
1792 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
1793 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
1795 * Most NFS servers just ignore the UID/GID attributes, so we
1796 * try ignoring them if that'll help the request succeed.
1798 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
1799 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
1800 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
1804 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1807 error
= VNOP_CREATE(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
1809 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
1811 * If some of the requested attributes weren't handled by the VNOP,
1812 * use our fallback code.
1814 error
= vnode_setattr_fallback(vp
, vap
, &context
);
1817 kauth_acl_free(xacl
);
1820 if (exclusive_flag
) {
1823 bcopy(cverf
, (caddr_t
)&vap
->va_access_time
,
1825 VATTR_SET_ACTIVE(vap
, va_access_time
);
1826 // skip authorization, as this is an
1827 // NFS internal implementation detail.
1828 error
= vnode_setattr(vp
, vap
, &context
);
1832 } else if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
||
1833 vap
->va_type
== VFIFO
) {
1834 if (vap
->va_type
== VCHR
&& rdev
== (int)0xffffffff)
1835 VATTR_SET(vap
, va_type
, VFIFO
);
1836 if (vap
->va_type
!= VFIFO
&&
1837 (error
= suser(nfsd
->nd_cr
, (u_short
*)0))) {
1840 VATTR_SET(vap
, va_rdev
, (dev_t
)rdev
);
1842 error
= VNOP_MKNOD(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
1845 kauth_acl_free(xacl
);
1855 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1856 nd
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
1857 nd
.ni_cnd
.cn_context
= &context
;
1858 nd
.ni_startdir
= dvp
;
1860 error
= lookup(&nd
);
1862 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
)
1872 * nameidone has to happen before we vnode_put(dvp)
1873 * since it may need to release the fs_nodelock on the dvp
1876 nd
.ni_cnd
.cn_nameiop
= 0;
1881 * nameidone has to happen before we vnode_put(dvp)
1882 * since it may need to release the fs_nodelock on the dvp
1885 nd
.ni_cnd
.cn_nameiop
= 0;
1889 if (!error
&& VATTR_IS_ACTIVE(vap
, va_data_size
)) {
1890 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
,
1893 tempsize
= vap
->va_data_size
;
1895 VATTR_SET(vap
, va_data_size
, tempsize
);
1896 error
= vnode_setattr(vp
, vap
, &context
);
1901 error
= nfsrv_vptofh(nx
, !v3
, NULL
, vp
, &context
, &nfh
);
1903 nfsm_srv_vattr_init(&postat
, v3
);
1904 error
= vnode_getattr(vp
, &postat
, &context
);
1911 if (exclusive_flag
&& !error
&&
1912 bcmp(cverf
, (caddr_t
)&postat
.va_access_time
, NFSX_V3CREATEVERF
))
1914 nfsm_srv_vattr_init(&diraft
, v3
);
1915 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
1919 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_FATTR(v3
) + NFSX_WCCDATA(v3
));
1923 nfsm_srvpostop_fh(&nfh
);
1924 nfsm_srvpostop_attr(0, &postat
);
1926 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1928 nfsm_srvfhtom(&nfh
, v3
);
1929 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1930 nfsm_srvfillattr(&postat
, fp
);
1934 if (nd
.ni_cnd
.cn_nameiop
) {
1936 * nameidone has to happen before we vnode_put(dvp)
1937 * since it may need to release the fs_nodelock on the dvp
1951 * nfs v3 mknod service
1954 nfsrv_mknod(nfsd
, slp
, procp
, mrq
)
1955 struct nfsrv_descript
*nfsd
;
1956 struct nfssvc_sock
*slp
;
1960 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
1961 mbuf_t nam
= nfsd
->nd_nam
;
1962 caddr_t dpos
= nfsd
->nd_dpos
;
1963 struct vnode_attr dirfor
, diraft
, postat
;
1964 struct vnode_attr va
;
1965 struct vnode_attr
*vap
= &va
;
1967 struct nameidata nd
;
1970 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
1971 u_long major
, minor
;
1974 mbuf_t mb
, mb2
, mreq
;
1975 vnode_t vp
, dvp
, dirp
= NULL
;
1976 struct nfs_filehandle nfh
;
1977 struct nfs_export
*nx
;
1978 struct nfs_export_options
*nxo
;
1979 struct vfs_context hacked_context
; /* XXX should we have this? */
1980 struct vfs_context context
;
1982 kauth_acl_t xacl
= NULL
;
1984 context
.vc_proc
= procp
;
1985 context
.vc_ucred
= nfsd
->nd_cr
;
1986 hacked_context
.vc_proc
= procp
;
1987 hacked_context
.vc_ucred
= proc_ucred(procp
);
1990 * Save the original credential UID in case they are
1991 * mapped and we need to map the IDs in the attributes.
1993 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
1996 nd
.ni_cnd
.cn_nameiop
= 0;
1997 nfsm_srvmtofh(&nfh
);
1998 nfsm_srvnamesiz(len
, 1);
2000 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2001 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2002 error
= nfsm_path_mbuftond(&md
, &dpos
, 1, FALSE
, &len
, &nd
);
2004 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2006 nfsm_srv_pre_vattr_init(&dirfor
, 1);
2007 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2010 nd
.ni_cnd
.cn_nameiop
= 0;
2011 nfsm_reply(NFSX_WCCDATA(1));
2012 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2020 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
2021 vtyp
= nfsv3tov_type(*tl
);
2022 if (vtyp
!= VCHR
&& vtyp
!= VBLK
&& vtyp
!= VSOCK
&& vtyp
!= VFIFO
) {
2023 error
= NFSERR_BADTYPE
;
2029 if (vtyp
== VCHR
|| vtyp
== VBLK
) {
2030 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2031 major
= fxdr_unsigned(u_long
, *tl
++);
2032 minor
= fxdr_unsigned(u_long
, *tl
);
2033 VATTR_SET(vap
, va_rdev
, makedev(major
, minor
));
2037 * If it doesn't exist, create it.
2043 VATTR_SET(vap
, va_type
, vtyp
);
2046 * If the credentials were mapped, we should
2047 * map the same values in the attributes.
2049 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
2051 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
2052 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
2053 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
2056 /* authorize before creating */
2057 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
2059 /* construct ACL and handle inheritance */
2061 error
= kauth_acl_inherit(dvp
,
2067 if (!error
&& xacl
!= NULL
)
2068 VATTR_SET(vap
, va_acl
, xacl
);
2070 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
2071 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
2073 /* validate new-file security information */
2075 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
2076 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
2078 * Most NFS servers just ignore the UID/GID attributes, so we
2079 * try ignoring them if that'll help the request succeed.
2081 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
2082 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
2083 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
2087 if (vtyp
== VSOCK
) {
2088 error
= VNOP_CREATE(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
2090 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
2092 * If some of the requested attributes weren't handled by the VNOP,
2093 * use our fallback code.
2095 error
= vnode_setattr_fallback(vp
, vap
, &context
);
2097 if (vtyp
!= VFIFO
&& (error
= suser(nfsd
->nd_cr
, (u_short
*)0))) {
2100 if ((error
= VNOP_MKNOD(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
))) {
2108 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2109 nd
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
2110 nd
.ni_cnd
.cn_context
= &hacked_context
;
2111 nd
.ni_startdir
= dvp
;
2113 error
= lookup(&nd
);
2116 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
)
2122 kauth_acl_free(xacl
);
2125 * nameidone has to happen before we vnode_put(dvp)
2126 * since it may need to release the fs_nodelock on the dvp
2129 nd
.ni_cnd
.cn_nameiop
= 0;
2134 error
= nfsrv_vptofh(nx
, 0, NULL
, vp
, &context
, &nfh
);
2136 nfsm_srv_vattr_init(&postat
, 1);
2137 error
= vnode_getattr(vp
, &postat
, &context
);
2143 nfsm_srv_vattr_init(&diraft
, 1);
2144 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
2148 nfsm_reply(NFSX_SRVFH(1, &nfh
) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
2150 nfsm_srvpostop_fh(&nfh
);
2151 nfsm_srvpostop_attr(0, &postat
);
2153 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2156 if (nd
.ni_cnd
.cn_nameiop
) {
2158 * nameidone has to happen before we vnode_put(dvp)
2159 * since it may need to release the fs_nodelock on the dvp
2173 * nfs remove service
2176 nfsrv_remove(nfsd
, slp
, procp
, mrq
)
2177 struct nfsrv_descript
*nfsd
;
2178 struct nfssvc_sock
*slp
;
2182 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2183 mbuf_t nam
= nfsd
->nd_nam
;
2184 caddr_t dpos
= nfsd
->nd_dpos
;
2185 struct nameidata nd
;
2189 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2190 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2193 vnode_t vp
, dvp
, dirp
= NULL
;
2194 struct vnode_attr dirfor
, diraft
;
2195 struct nfs_filehandle nfh
;
2196 struct nfs_export
*nx
;
2197 struct nfs_export_options
*nxo
;
2198 struct vfs_context context
;
2200 context
.vc_proc
= procp
;
2201 context
.vc_ucred
= nfsd
->nd_cr
;
2204 nfsm_srvmtofh(&nfh
);
2205 nfsm_srvnamesiz(len
, v3
);
2207 nd
.ni_cnd
.cn_nameiop
= DELETE
;
2208 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2209 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
2211 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2214 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
2215 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2225 if (vnode_vtype(vp
) == VDIR
)
2226 error
= EPERM
; /* POSIX */
2227 else if (vnode_isvroot(vp
))
2229 * The root of a mounted filesystem cannot be deleted.
2233 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, &context
, nxo
, 0);
2236 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, 0, &context
);
2239 * nameidone has to happen before we vnode_put(dvp)
2240 * since it may need to release the fs_nodelock on the dvp
2248 nfsm_srv_vattr_init(&diraft
, v3
);
2249 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
2252 nfsm_reply(NFSX_WCCDATA(v3
));
2254 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2262 * nfs rename service
2265 nfsrv_rename(nfsd
, slp
, procp
, mrq
)
2266 struct nfsrv_descript
*nfsd
;
2267 struct nfssvc_sock
*slp
;
2271 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2272 mbuf_t nam
= nfsd
->nd_nam
;
2273 caddr_t dpos
= nfsd
->nd_dpos
;
2274 kauth_cred_t saved_cred
= NULL
;
2278 int error
= 0, fromlen
, tolen
;
2279 int fdirfor_ret
= 1, fdiraft_ret
= 1;
2280 int tdirfor_ret
= 1, tdiraft_ret
= 1;
2281 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2282 char *cp2
, *frompath
= NULL
, *topath
= NULL
;
2284 struct nameidata fromnd
, tond
;
2285 vnode_t fvp
, tvp
, tdvp
, fdvp
, fdirp
= NULL
;
2286 vnode_t tdirp
= NULL
;
2287 struct vnode_attr fdirfor
, fdiraft
, tdirfor
, tdiraft
;
2288 struct nfs_filehandle fnfh
, tnfh
;
2289 struct nfs_export
*fnx
, *tnx
;
2290 struct nfs_export_options
*fnxo
, *tnxo
;
2291 enum vtype fvtype
, tvtype
;
2292 int holding_mntlock
;
2294 struct vfs_context context
;
2296 context
.vc_proc
= procp
;
2297 context
.vc_ucred
= nfsd
->nd_cr
;
2304 * these need to be set before
2305 * calling any nfsm_xxxx macros
2306 * since they may take us out
2307 * through the error path
2309 holding_mntlock
= 0;
2314 nfsm_srvmtofh(&fnfh
);
2315 nfsm_srvnamesiz(fromlen
, v3
);
2316 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &fromlen
, &fromnd
);
2321 frompath
= fromnd
.ni_cnd
.cn_pnbuf
;
2322 nfsm_srvmtofh(&tnfh
);
2323 nfsm_strsiz(tolen
, NFS_MAXNAMLEN
, v3
);
2324 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &tolen
, &tond
);
2327 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
2330 topath
= tond
.ni_cnd
.cn_pnbuf
;
2333 * Remember our original uid so that we can reset cr_uid before
2334 * the second nfs_namei() call, in case it is remapped.
2336 saved_cred
= nfsd
->nd_cr
;
2337 kauth_cred_ref(saved_cred
);
2339 fromnd
.ni_cnd
.cn_nameiop
= DELETE
;
2340 fromnd
.ni_cnd
.cn_flags
= WANTPARENT
;
2342 fromnd
.ni_cnd
.cn_pnbuf
= frompath
;
2344 fromnd
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2345 fromnd
.ni_cnd
.cn_flags
|= HASBUF
;
2347 error
= nfs_namei(nfsd
, &context
, &fromnd
, &fnfh
, nam
, FALSE
, &fdirp
, &fnx
, &fnxo
);
2350 fdvp
= fromnd
.ni_dvp
;
2355 nfsm_srv_pre_vattr_init(&fdirfor
, v3
);
2356 fdirfor_ret
= vnode_getattr(fdirp
, &fdirfor
, &context
);
2362 fvtype
= vnode_vtype(fvp
);
2364 /* reset credential if it was remapped */
2365 if (nfsd
->nd_cr
!= saved_cred
) {
2366 kauth_cred_rele(nfsd
->nd_cr
);
2367 nfsd
->nd_cr
= saved_cred
;
2368 kauth_cred_ref(nfsd
->nd_cr
);
2371 tond
.ni_cnd
.cn_nameiop
= RENAME
;
2372 tond
.ni_cnd
.cn_flags
= WANTPARENT
;
2374 tond
.ni_cnd
.cn_pnbuf
= topath
;
2376 tond
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2377 tond
.ni_cnd
.cn_flags
|= HASBUF
;
2380 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2382 error
= nfs_namei(nfsd
, &context
, &tond
, &tnfh
, nam
, FALSE
, &tdirp
, &tnx
, &tnxo
);
2385 * Translate error code for rename("dir1", "dir2/.").
2387 if (error
== EISDIR
&& fvtype
== VDIR
) {
2400 nfsm_srv_pre_vattr_init(&tdirfor
, v3
);
2401 tdirfor_ret
= vnode_getattr(tdirp
, &tdirfor
, &context
);
2409 tvtype
= vnode_vtype(tvp
);
2411 if (fvtype
== VDIR
&& tvtype
!= VDIR
) {
2417 } else if (fvtype
!= VDIR
&& tvtype
== VDIR
) {
2424 if (tvtype
== VDIR
&& vnode_mountedhere(tvp
)) {
2443 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
2444 * the node is moving between directories and we need rights to remove from the
2445 * old and add to the new.
2447 * If tvp already exists and is not a directory, we need to be allowed to delete it.
2449 * Note that we do not inherit when renaming. XXX this needs to be revisited to
2450 * implement the deferred-inherit bit.
2456 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
2459 } else if (tdvp
!= fdvp
) {
2463 /* moving out of fdvp, must have delete rights */
2464 if ((error
= nfsrv_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
, fnxo
, 0)) != 0)
2466 /* moving into tdvp or tvp, must have rights to add */
2467 if ((error
= nfsrv_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
2469 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2470 &context
, tnxo
, 0)) != 0)
2473 /* node staying in same directory, must be allowed to add new name */
2474 if ((error
= nfsrv_authorize(fdvp
, NULL
,
2475 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2476 &context
, fnxo
, 0)) != 0)
2479 /* overwriting tvp */
2480 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
2481 ((error
= nfsrv_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
, tnxo
, 0)) != 0))
2484 /* XXX more checks? */
2487 /* authorization denied */
2492 if ((vnode_mount(fvp
) != vnode_mount(tdvp
)) ||
2493 (tvp
&& (vnode_mount(fvp
) != vnode_mount(tvp
)))) {
2501 * The following edge case is caught here:
2502 * (to cannot be a descendent of from)
2515 if (tdvp
->v_parent
== fvp
) {
2522 if (fvtype
== VDIR
&& vnode_mountedhere(fvp
)) {
2530 * If source is the same as the destination (that is the
2531 * same vnode) then there is nothing to do...
2532 * EXCEPT if the underlying file system supports case
2533 * insensitivity and is case preserving. In this case
2534 * the file system needs to handle the special case of
2535 * getting the same vnode as target (fvp) and source (tvp).
2537 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2538 * and _PC_CASE_PRESERVING can have this exception, and they need to
2539 * handle the special case of getting the same vnode as target and
2540 * source. NOTE: Then the target is unlocked going into vnop_rename,
2541 * so not to cause locking problems. There is a single reference on tvp.
2543 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2544 * that correct behaviour then is just to remove the source (link)
2546 if ((fvp
== tvp
) && (fdvp
== tdvp
)) {
2547 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
2548 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
2549 fromnd
.ni_cnd
.cn_namelen
)) {
2554 if (holding_mntlock
&& vnode_mount(fvp
) != locked_mp
) {
2556 * we're holding a reference and lock
2557 * on locked_mp, but it no longer matches
2558 * what we want to do... so drop our hold
2560 mount_unlock_renames(locked_mp
);
2561 mount_drop(locked_mp
, 0);
2562 holding_mntlock
= 0;
2564 if (tdvp
!= fdvp
&& fvtype
== VDIR
) {
2566 * serialize renames that re-shape
2567 * the tree... if holding_mntlock is
2568 * set, then we're ready to go...
2570 * first need to drop the iocounts
2571 * we picked up, second take the
2572 * lock to serialize the access,
2573 * then finally start the lookup
2574 * process over with the lock held
2576 if (!holding_mntlock
) {
2578 * need to grab a reference on
2579 * the mount point before we
2580 * drop all the iocounts... once
2581 * the iocounts are gone, the mount
2584 locked_mp
= vnode_mount(fvp
);
2585 mount_ref(locked_mp
, 0);
2587 /* make a copy of to path to pass to nfs_namei() again */
2588 MALLOC_ZONE(topath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2590 bcopy(tond
.ni_cnd
.cn_pnbuf
, topath
, tolen
+ 1);
2593 * nameidone has to happen before we vnode_put(tdvp)
2594 * since it may need to release the fs_nodelock on the tdvp
2602 /* make a copy of from path to pass to nfs_namei() again */
2603 MALLOC_ZONE(frompath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2605 bcopy(fromnd
.ni_cnd
.cn_pnbuf
, frompath
, fromlen
+ 1);
2608 * nameidone has to happen before we vnode_put(fdvp)
2609 * since it may need to release the fs_nodelock on the fdvp
2624 mount_lock_renames(locked_mp
);
2625 holding_mntlock
= 1;
2630 fdirfor_ret
= tdirfor_ret
= 1;
2632 if (!topath
|| !frompath
) {
2633 /* we couldn't allocate a path, so bail */
2642 * when we dropped the iocounts to take
2643 * the lock, we allowed the identity of
2644 * the various vnodes to change... if they did,
2645 * we may no longer be dealing with a rename
2646 * that reshapes the tree... once we're holding
2647 * the iocounts, the vnodes can't change type
2648 * so we're free to drop the lock at this point
2651 if (holding_mntlock
) {
2652 mount_unlock_renames(locked_mp
);
2653 mount_drop(locked_mp
, 0);
2654 holding_mntlock
= 0;
2658 // save these off so we can later verify that fvp is the same
2661 oname
= fvp
->v_name
;
2662 oparent
= fvp
->v_parent
;
2664 error
= VNOP_RENAME(fromnd
.ni_dvp
, fromnd
.ni_vp
, &fromnd
.ni_cnd
,
2665 tond
.ni_dvp
, tond
.ni_vp
, &tond
.ni_cnd
, &context
);
2667 * fix up name & parent pointers. note that we first
2668 * check that fvp has the same name/parent pointers it
2669 * had before the rename call... this is a 'weak' check
2672 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
2674 update_flags
= VNODE_UPDATE_NAME
;
2676 update_flags
|= VNODE_UPDATE_PARENT
;
2677 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
2680 if (holding_mntlock
) {
2681 mount_unlock_renames(locked_mp
);
2682 mount_drop(locked_mp
, 0);
2683 holding_mntlock
= 0;
2687 * nameidone has to happen before we vnode_put(tdvp)
2688 * since it may need to release the fs_nodelock on the tdvp
2699 * nameidone has to happen before we vnode_put(fdvp)
2700 * since it may need to release the fs_nodelock on the fdvp
2711 nfsm_srv_vattr_init(&fdiraft
, v3
);
2712 fdiraft_ret
= vnode_getattr(fdirp
, &fdiraft
, &context
);
2717 nfsm_srv_vattr_init(&tdiraft
, v3
);
2718 tdiraft_ret
= vnode_getattr(tdirp
, &tdiraft
, &context
);
2722 nfsm_reply(2 * NFSX_WCCDATA(v3
));
2724 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
2725 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
2728 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
2730 FREE_ZONE(topath
, MAXPATHLEN
, M_NAMEI
);
2732 kauth_cred_rele(saved_cred
);
2736 if (holding_mntlock
) {
2737 mount_unlock_renames(locked_mp
);
2738 mount_drop(locked_mp
, 0);
2742 * nameidone has to happen before we vnode_put(tdvp)
2743 * since it may need to release the fs_nodelock on the tdvp
2753 * nameidone has to happen before we vnode_put(fdvp)
2754 * since it may need to release the fs_nodelock on the fdvp
2767 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
2769 FREE_ZONE(topath
, MAXPATHLEN
, M_NAMEI
);
2771 kauth_cred_rele(saved_cred
);
2779 nfsrv_link(nfsd
, slp
, procp
, mrq
)
2780 struct nfsrv_descript
*nfsd
;
2781 struct nfssvc_sock
*slp
;
2785 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2786 mbuf_t nam
= nfsd
->nd_nam
;
2787 caddr_t dpos
= nfsd
->nd_dpos
;
2788 struct nameidata nd
;
2792 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2793 int getret
= 1, v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2796 vnode_t vp
, xp
, dvp
, dirp
= NULL
;
2797 struct vnode_attr dirfor
, diraft
, at
;
2798 struct nfs_filehandle nfh
, dnfh
;
2799 struct nfs_export
*nx
;
2800 struct nfs_export_options
*nxo
;
2801 struct vfs_context context
;
2803 vp
= xp
= dvp
= NULL
;
2804 nfsm_srvmtofh(&nfh
);
2805 nfsm_srvmtofh(&dnfh
);
2806 nfsm_srvnamesiz(len
, v3
);
2807 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
2808 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2809 nfsm_srvpostop_attr(getret
, &at
);
2810 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2813 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
2815 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2816 nfsm_srvpostop_attr(getret
, &at
);
2817 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2821 /* we're not allowed to link to directories... */
2822 if (vnode_vtype(vp
) == VDIR
) {
2823 error
= EPERM
; /* POSIX */
2827 context
.vc_proc
= procp
;
2828 context
.vc_ucred
= nfsd
->nd_cr
;
2830 /* ...or to anything that kauth doesn't want us to (eg. immutable items) */
2831 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
, nxo
, 0)) != 0)
2834 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2835 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2836 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
2838 error
= nfs_namei(nfsd
, &context
, &nd
, &dnfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2841 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
2842 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2855 else if (vnode_mount(vp
) != vnode_mount(dvp
))
2858 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
2861 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
2864 * nameidone has to happen before we vnode_put(dvp)
2865 * since it may need to release the fs_nodelock on the dvp
2874 nfsm_srv_vattr_init(&at
, v3
);
2875 getret
= vnode_getattr(vp
, &at
, &context
);
2878 nfsm_srv_vattr_init(&diraft
, v3
);
2879 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
2884 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2886 nfsm_srvpostop_attr(getret
, &at
);
2887 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2895 * nfs symbolic link service
2898 nfsrv_symlink(nfsd
, slp
, procp
, mrq
)
2899 struct nfsrv_descript
*nfsd
;
2900 struct nfssvc_sock
*slp
;
2904 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2905 mbuf_t nam
= nfsd
->nd_nam
;
2906 caddr_t dpos
= nfsd
->nd_dpos
;
2907 struct vnode_attr dirfor
, diraft
, postat
;
2908 struct nameidata nd
;
2909 struct vnode_attr va
;
2910 struct vnode_attr
*vap
= &va
;
2913 struct nfsv2_sattr
*sp
;
2914 char *bpos
, *linkdata
= NULL
, *cp2
;
2915 int error
= 0, len
, linkdatalen
;
2916 int dirfor_ret
= 1, diraft_ret
= 1;
2917 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2918 mbuf_t mb
, mreq
, mb2
;
2919 vnode_t vp
, dvp
, dirp
= NULL
;
2920 struct nfs_filehandle nfh
;
2921 struct nfs_export
*nx
;
2922 struct nfs_export_options
*nxo
;
2924 char uio_buf
[ UIO_SIZEOF(1) ];
2925 struct vfs_context context
;
2928 context
.vc_proc
= procp
;
2929 context
.vc_ucred
= nfsd
->nd_cr
;
2932 * Save the original credential UID in case they are
2933 * mapped and we need to map the IDs in the attributes.
2935 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
2937 nd
.ni_cnd
.cn_nameiop
= 0;
2939 nfsm_srvmtofh(&nfh
);
2940 nfsm_srvnamesiz(len
, v3
);
2942 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2943 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2944 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
2946 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2949 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
2950 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2957 nd
.ni_cnd
.cn_nameiop
= 0;
2966 nfsm_strsiz(linkdatalen
, NFS_MAXPATHLEN
, v3
);
2967 MALLOC(linkdata
, caddr_t
, linkdatalen
+ 1, M_TEMP
, M_WAITOK
);
2970 nd
.ni_cnd
.cn_nameiop
= 0;
2971 vnode_put(nd
.ni_dvp
);
2972 vnode_put(nd
.ni_vp
);
2976 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
2977 &uio_buf
[0], sizeof(uio_buf
));
2980 nd
.ni_cnd
.cn_nameiop
= 0;
2981 vnode_put(nd
.ni_dvp
);
2982 vnode_put(nd
.ni_vp
);
2986 uio_addiov(auio
, CAST_USER_ADDR_T(linkdata
), linkdatalen
);
2987 nfsm_mtouio(auio
, linkdatalen
);
2989 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2990 VATTR_SET(vap
, va_mode
, fxdr_unsigned(u_short
, sp
->sa_mode
));
2992 *(linkdata
+ linkdatalen
) = '\0';
2999 * If the credentials were mapped, we should
3000 * map the same values in the attributes.
3002 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
3004 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
3005 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
3006 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
3008 VATTR_SET(vap
, va_type
, VLNK
);
3009 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3010 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3012 /* authorize before creating */
3013 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
3015 /* validate given attributes */
3017 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3018 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
3020 * Most NFS servers just ignore the UID/GID attributes, so we
3021 * try ignoring them if that'll help the request succeed.
3023 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3024 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3025 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3029 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, vap
, linkdata
, &context
);
3033 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
3034 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| FOLLOW
);
3035 nd
.ni_cnd
.cn_flags
|= (NOFOLLOW
| LOCKLEAF
);
3036 nd
.ni_cnd
.cn_context
= &context
;
3037 nd
.ni_startdir
= dvp
;
3039 error
= lookup(&nd
);
3044 error
= nfsrv_vptofh(nx
, !v3
, NULL
, vp
, &context
, &nfh
);
3046 nfsm_srv_vattr_init(&postat
, v3
);
3047 error
= vnode_getattr(vp
, &postat
, &context
);
3053 * nameidone has to happen before we vnode_put(dvp)
3054 * since it may need to release the fs_nodelock on the dvp
3057 nd
.ni_cnd
.cn_nameiop
= 0;
3064 FREE(linkdata
, M_TEMP
);
3066 nfsm_srv_vattr_init(&diraft
, v3
);
3067 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
3070 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
3073 nfsm_srvpostop_fh(&nfh
);
3074 nfsm_srvpostop_attr(0, &postat
);
3076 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3080 if (nd
.ni_cnd
.cn_nameiop
) {
3082 * nameidone has to happen before we vnode_put(dvp)
3083 * since it may need to release the fs_nodelock on the dvp
3094 FREE(linkdata
, M_TEMP
);
3102 nfsrv_mkdir(nfsd
, slp
, procp
, mrq
)
3103 struct nfsrv_descript
*nfsd
;
3104 struct nfssvc_sock
*slp
;
3108 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3109 mbuf_t nam
= nfsd
->nd_nam
;
3110 caddr_t dpos
= nfsd
->nd_dpos
;
3111 struct vnode_attr dirfor
, diraft
, postat
;
3112 struct vnode_attr va
;
3113 struct vnode_attr
*vap
= &va
;
3114 struct nfs_fattr
*fp
;
3115 struct nameidata nd
;
3121 int dirfor_ret
= 1, diraft_ret
= 1;
3122 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3124 mbuf_t mb
, mb2
, mreq
;
3125 vnode_t vp
, dvp
, dirp
= NULL
;
3126 struct nfs_filehandle nfh
;
3127 struct nfs_export
*nx
;
3128 struct nfs_export_options
*nxo
;
3129 struct vfs_context context
;
3131 kauth_acl_t xacl
= NULL
;
3133 context
.vc_proc
= procp
;
3134 context
.vc_ucred
= nfsd
->nd_cr
;
3137 * Save the original credential UID in case they are
3138 * mapped and we need to map the IDs in the attributes.
3140 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
3142 nd
.ni_cnd
.cn_nameiop
= 0;
3144 nfsm_srvmtofh(&nfh
);
3145 nfsm_srvnamesiz(len
, v3
);
3147 nd
.ni_cnd
.cn_nameiop
= CREATE
;
3148 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
3149 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
3151 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
3154 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
3155 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
3162 nd
.ni_cnd
.cn_nameiop
= 0;
3163 nfsm_reply(NFSX_WCCDATA(v3
));
3164 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3176 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
3177 VATTR_SET(vap
, va_mode
, nfstov_mode(*tl
++));
3179 VATTR_SET(vap
, va_type
, VDIR
);
3183 * nameidone has to happen before we vnode_put(dvp)
3184 * since it may need to release the fs_nodelock on the dvp
3195 * If the credentials were mapped, we should
3196 * map the same values in the attributes.
3198 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
3200 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
3201 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
3202 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
3205 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, &context
, nxo
, 0);
3207 /* construct ACL and handle inheritance */
3209 error
= kauth_acl_inherit(dvp
,
3215 if (!error
&& xacl
!= NULL
)
3216 VATTR_SET(vap
, va_acl
, xacl
);
3218 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3219 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3221 /* validate new-file security information */
3223 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3224 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
3226 * Most NFS servers just ignore the UID/GID attributes, so we
3227 * try ignoring them if that'll help the request succeed.
3229 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3230 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3231 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3236 error
= VNOP_MKDIR(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
3238 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
3240 * If some of the requested attributes weren't handled by the VNOP,
3241 * use our fallback code.
3243 error
= vnode_setattr_fallback(vp
, vap
, &context
);
3246 kauth_acl_free(xacl
);
3249 error
= nfsrv_vptofh(nx
, !v3
, NULL
, vp
, &context
, &nfh
);
3251 nfsm_srv_vattr_init(&postat
, v3
);
3252 error
= vnode_getattr(vp
, &postat
, &context
);
3258 * nameidone has to happen before we vnode_put(dvp)
3259 * since it may need to release the fs_nodelock on the dvp
3265 nd
.ni_cnd
.cn_nameiop
= 0;
3268 nfsm_srv_vattr_init(&diraft
, v3
);
3269 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
3272 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
3275 nfsm_srvpostop_fh(&nfh
);
3276 nfsm_srvpostop_attr(0, &postat
);
3278 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3280 nfsm_srvfhtom(&nfh
, v3
);
3281 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
3282 nfsm_srvfillattr(&postat
, fp
);
3286 if (nd
.ni_cnd
.cn_nameiop
) {
3288 * nameidone has to happen before we vnode_put(dvp)
3289 * since it may need to release the fs_nodelock on the dvp
3305 nfsrv_rmdir(nfsd
, slp
, procp
, mrq
)
3306 struct nfsrv_descript
*nfsd
;
3307 struct nfssvc_sock
*slp
;
3311 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3312 mbuf_t nam
= nfsd
->nd_nam
;
3313 caddr_t dpos
= nfsd
->nd_dpos
;
3318 int dirfor_ret
= 1, diraft_ret
= 1;
3319 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3322 vnode_t vp
, dvp
, dirp
= NULL
;
3323 struct vnode_attr dirfor
, diraft
;
3324 struct nfs_filehandle nfh
;
3325 struct nfs_export
*nx
;
3326 struct nfs_export_options
*nxo
;
3327 struct nameidata nd
;
3328 struct vfs_context context
;
3330 context
.vc_proc
= procp
;
3331 context
.vc_ucred
= nfsd
->nd_cr
;
3334 nfsm_srvmtofh(&nfh
);
3335 nfsm_srvnamesiz(len
, v3
);
3337 nd
.ni_cnd
.cn_nameiop
= DELETE
;
3338 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
3339 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
3341 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
3344 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
3345 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
3352 nfsm_reply(NFSX_WCCDATA(v3
));
3353 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3361 if (vnode_vtype(vp
) != VDIR
) {
3366 * No rmdir "." please.
3373 * The root of a mounted filesystem cannot be deleted.
3375 if (vnode_isvroot(vp
))
3378 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, &context
, nxo
, 0);
3380 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
3383 * nameidone has to happen before we vnode_put(dvp)
3384 * since it may need to release the fs_nodelock on the dvp
3392 nfsm_srv_vattr_init(&diraft
, v3
);
3393 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
3396 nfsm_reply(NFSX_WCCDATA(v3
));
3398 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3406 * nfs readdir service
3407 * - mallocs what it thinks is enough to read
3408 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
3409 * - calls VNOP_READDIR()
3410 * - loops around building the reply
3411 * if the output generated exceeds count break out of loop
3412 * The nfsm_clget macro is used here so that the reply will be packed
3413 * tightly in mbuf clusters.
3414 * - it only knows that it has encountered eof when the VNOP_READDIR()
3416 * - as such one readdir rpc will return eof false although you are there
3417 * and then the next will return eof
3418 * - it trims out records with d_fileno == 0
3419 * this doesn't matter for Unix clients, but they might confuse clients
3421 * NB: It is tempting to set eof to true if the VNOP_READDIR() reads less
3422 * than requested, but this may not apply to all filesystems. For
3423 * example, client NFS does not { although it is never remote mounted
3425 * The alternate call nfsrv_readdirplus() does lookups as well.
3426 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
3427 * are supposed to cover. For readdir, the count is the total number of
3428 * bytes included in everything from the directory's postopattr through
3429 * the EOF flag. For readdirplus, the maxcount is the same, and the
3430 * dircount includes all that except for the entry attributes and handles.
3434 nfsrv_readdir(nfsd
, slp
, procp
, mrq
)
3435 struct nfsrv_descript
*nfsd
;
3436 struct nfssvc_sock
*slp
;
3440 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3441 mbuf_t nam
= nfsd
->nd_nam
;
3442 caddr_t dpos
= nfsd
->nd_dpos
;
3445 struct direntry
*dp
;
3450 mbuf_t mb
, mb2
, mreq
, mp2
;
3451 char *cpos
, *cend
, *cp2
, *rbuf
;
3453 struct vnode_attr at
;
3454 struct nfs_filehandle nfh
;
3455 struct nfs_export
*nx
;
3456 struct nfs_export_options
*nxo
;
3458 char uio_buf
[ UIO_SIZEOF(1) ];
3459 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
3460 int siz
, count
, fullsiz
, eofflag
, nentries
= 0;
3461 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3462 u_quad_t off
, toff
, verf
;
3465 struct vfs_context context
;
3467 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
3469 nfsm_srvmtofh(&nfh
);
3471 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
3472 fxdr_hyper(tl
, &toff
);
3474 fxdr_hyper(tl
, &verf
);
3477 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3478 toff
= fxdr_unsigned(u_quad_t
, *tl
++);
3481 count
= fxdr_unsigned(int, *tl
);
3482 siz
= ((count
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
3483 xfer
= NFS_SRVMAXDATA(nfsd
);
3487 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
3488 nfsm_reply(NFSX_UNSIGNED
);
3489 nfsm_srvpostop_attr(getret
, &at
);
3492 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
3494 nfsm_reply(NFSX_UNSIGNED
);
3495 nfsm_srvpostop_attr(getret
, &at
);
3498 context
.vc_proc
= procp
;
3499 context
.vc_ucred
= nfsd
->nd_cr
;
3500 if (!v3
|| (nxo
->nxo_flags
& NX_32BITCLIENTS
))
3501 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
3503 nfsm_srv_vattr_init(&at
, v3
);
3504 error
= getret
= vnode_getattr(vp
, &at
, &context
);
3505 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
3506 error
= NFSERR_BAD_COOKIE
;
3509 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, &context
, nxo
, 0);
3512 nfsm_reply(NFSX_POSTOPATTR(v3
));
3513 nfsm_srvpostop_attr(getret
, &at
);
3516 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
3520 nfsm_reply(NFSX_POSTOPATTR(v3
));
3521 nfsm_srvpostop_attr(getret
, &at
);
3524 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3525 &uio_buf
[0], sizeof(uio_buf
));
3530 nfsm_reply(NFSX_POSTOPATTR(v3
));
3531 nfsm_srvpostop_attr(getret
, &at
);
3535 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
3536 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
3539 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, &context
);
3540 off
= uio_offset(auio
);
3543 nfsm_srv_vattr_init(&at
, v3
);
3544 getret
= vnode_getattr(vp
, &at
, &context
);
3551 nfsm_reply(NFSX_POSTOPATTR(v3
));
3552 nfsm_srvpostop_attr(getret
, &at
);
3555 if (uio_resid(auio
) != 0) {
3556 // LP64todo - fix this
3557 siz
-= uio_resid(auio
);
3560 * If nothing read, return eof
3565 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) +
3568 nfsm_srvpostop_attr(getret
, &at
);
3569 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
3570 txdr_hyper(&at
.va_filerev
, tl
);
3573 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3582 * Check for degenerate cases of nothing useful read.
3583 * If so go try again
3587 dp
= (struct direntry
*)cpos
;
3588 while (dp
->d_fileno
== 0 && cpos
< cend
&& nentries
> 0) {
3589 cpos
+= dp
->d_reclen
;
3590 dp
= (struct direntry
*)cpos
;
3593 if (cpos
>= cend
|| nentries
== 0) {
3600 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) + siz
);
3602 len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3603 nfsm_srvpostop_attr(getret
, &at
);
3604 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3605 txdr_hyper(&at
.va_filerev
, tl
);
3607 len
= 2 * NFSX_UNSIGNED
;
3610 be
= bp
+ mbuf_trailingspace(mp
);
3612 /* Loop through the records and build reply */
3613 while (cpos
< cend
&& nentries
> 0) {
3614 if (dp
->d_fileno
!= 0) {
3615 nlen
= dp
->d_namlen
;
3616 if (!v3
&& (nlen
> NFS_MAXNAMLEN
))
3617 nlen
= NFS_MAXNAMLEN
;
3618 rem
= nfsm_rndup(nlen
)-nlen
;
3619 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
3621 len
+= 2 * NFSX_UNSIGNED
;
3627 * Build the directory record xdr from
3628 * the direntry entry.
3632 bp
+= NFSX_UNSIGNED
;
3635 txdr_hyper(&dp
->d_fileno
, &tquad
);
3636 *tl
= tquad
.nfsuquad
[0];
3637 bp
+= NFSX_UNSIGNED
;
3639 *tl
= tquad
.nfsuquad
[1];
3640 bp
+= NFSX_UNSIGNED
;
3642 *tl
= txdr_unsigned(dp
->d_fileno
);
3643 bp
+= NFSX_UNSIGNED
;
3646 *tl
= txdr_unsigned(nlen
);
3647 bp
+= NFSX_UNSIGNED
;
3649 /* And loop around copying the name */
3658 bcopy(cp
, bp
, tsiz
);
3664 /* And null pad to a long boundary */
3665 for (i
= 0; i
< rem
; i
++)
3668 /* Finish off the record with the cookie */
3671 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
3672 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
3673 txdr_hyper(&dp
->d_seekoff
, &tquad
);
3674 *tl
= tquad
.nfsuquad
[0];
3675 bp
+= NFSX_UNSIGNED
;
3677 *tl
= tquad
.nfsuquad
[1];
3678 bp
+= NFSX_UNSIGNED
;
3680 *tl
= txdr_unsigned(dp
->d_seekoff
);
3681 bp
+= NFSX_UNSIGNED
;
3684 cpos
+= dp
->d_reclen
;
3685 dp
= (struct direntry
*)cpos
;
3690 bp
+= NFSX_UNSIGNED
;
3696 bp
+= NFSX_UNSIGNED
;
3699 mbuf_setlen(mp
, bp
- (char*)mbuf_data(mp
));
3701 mbuf_setlen(mp
, mbuf_len(mp
) + (bp
- bpos
));
3710 u_long fl_fattr
[NFSX_V3FATTR
/ sizeof (u_long
)];
3713 u_long fl_nfh
[NFSX_V3FHMAX
/ sizeof (u_long
)];
3717 nfsrv_readdirplus(nfsd
, slp
, procp
, mrq
)
3718 struct nfsrv_descript
*nfsd
;
3719 struct nfssvc_sock
*slp
;
3723 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3724 mbuf_t nam
= nfsd
->nd_nam
;
3725 caddr_t dpos
= nfsd
->nd_dpos
;
3728 struct direntry
*dp
;
3733 mbuf_t mb
, mb2
, mreq
, mp2
;
3734 char *cpos
, *cend
, *cp2
, *rbuf
;
3737 struct nfs_filehandle dnfh
, *nfhp
= (struct nfs_filehandle
*)&fl
.fl_fhsize
;
3738 struct nfs_export
*nx
;
3739 struct nfs_export_options
*nxo
;
3741 char uio_buf
[ UIO_SIZEOF(1) ];
3742 struct vnode_attr va
, at
, *vap
= &va
;
3743 struct nfs_fattr
*fp
;
3744 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
3745 int siz
, count
, fullsiz
, eofflag
, dirlen
, nentries
= 0, isdotdot
;
3746 u_quad_t off
, toff
, verf
;
3749 struct vfs_context context
;
3751 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
3753 nfsm_srvmtofh(&dnfh
);
3754 nfsm_dissect(tl
, u_long
*, 6 * NFSX_UNSIGNED
);
3755 fxdr_hyper(tl
, &toff
);
3757 fxdr_hyper(tl
, &verf
);
3759 siz
= fxdr_unsigned(int, *tl
++);
3760 count
= fxdr_unsigned(int, *tl
);
3762 siz
= ((siz
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
3763 xfer
= NFS_SRVMAXDATA(nfsd
);
3767 if ((error
= nfsrv_fhtovp(&dnfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
3768 nfsm_reply(NFSX_UNSIGNED
);
3769 nfsm_srvpostop_attr(getret
, &at
);
3772 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
3774 nfsm_reply(NFSX_UNSIGNED
);
3775 nfsm_srvpostop_attr(getret
, &at
);
3778 context
.vc_proc
= procp
;
3779 context
.vc_ucred
= nfsd
->nd_cr
;
3780 if (nxo
->nxo_flags
& NX_32BITCLIENTS
)
3781 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
3782 nfsm_srv_vattr_init(&at
, 1);
3783 error
= getret
= vnode_getattr(vp
, &at
, &context
);
3784 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
3785 error
= NFSERR_BAD_COOKIE
;
3787 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, &context
, nxo
, 0);
3791 nfsm_reply(NFSX_V3POSTOPATTR
);
3792 nfsm_srvpostop_attr(getret
, &at
);
3795 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
3800 nfsm_reply(NFSX_V3POSTOPATTR
);
3801 nfsm_srvpostop_attr(getret
, &at
);
3804 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3805 &uio_buf
[0], sizeof(uio_buf
));
3811 nfsm_reply(NFSX_V3POSTOPATTR
);
3812 nfsm_srvpostop_attr(getret
, &at
);
3816 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
3817 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
3819 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, &context
);
3820 off
= uio_offset(auio
);
3821 nfsm_srv_vattr_init(&at
, 1);
3822 getret
= vnode_getattr(vp
, &at
, &context
);
3830 nfsm_reply(NFSX_V3POSTOPATTR
);
3831 nfsm_srvpostop_attr(getret
, &at
);
3834 if (uio_resid(auio
) != 0) {
3835 // LP64todo - fix this
3836 siz
-= uio_resid(auio
);
3839 * If nothing read, return eof
3845 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+
3847 nfsm_srvpostop_attr(getret
, &at
);
3848 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
3849 txdr_hyper(&at
.va_filerev
, tl
);
3859 * Check for degenerate cases of nothing useful read.
3860 * If so go try again
3864 dp
= (struct direntry
*)cpos
;
3865 while (dp
->d_fileno
== 0 && cpos
< cend
&& nentries
> 0) {
3866 cpos
+= dp
->d_reclen
;
3867 dp
= (struct direntry
*)cpos
;
3870 if (cpos
>= cend
|| nentries
== 0) {
3877 * Probe one of the directory entries to see if the filesystem
3880 if ((error
= VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, &context
))) {
3881 if (error
== ENOTSUP
) /* let others get passed back */
3882 error
= NFSERR_NOTSUPP
;
3886 nfsm_reply(NFSX_V3POSTOPATTR
);
3887 nfsm_srvpostop_attr(getret
, &at
);
3892 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3894 nfsm_srvpostop_attr(getret
, &at
);
3895 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3896 txdr_hyper(&at
.va_filerev
, tl
);
3899 be
= bp
+ mbuf_trailingspace(mp
);
3901 /* Loop through the records and build reply */
3902 while (cpos
< cend
&& nentries
> 0) {
3903 if (dp
->d_fileno
!= 0) {
3904 nlen
= dp
->d_namlen
;
3905 rem
= nfsm_rndup(nlen
)-nlen
;
3908 * Got to get the vnode for lookup per entry.
3910 if (VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, &context
))
3912 isdotdot
= ((dp
->d_namlen
== 2) &&
3913 (dp
->d_name
[0] == '.') && (dp
->d_name
[1] == '.'));
3914 if (nfsrv_vptofh(nx
, 0, (isdotdot
? &dnfh
: NULL
), nvp
, &context
, nfhp
)) {
3915 // XXX file handle is optional, so we should be able to
3916 // XXX return this entry without the file handle
3920 nfsm_srv_vattr_init(vap
, 1);
3921 if (vnode_getattr(nvp
, vap
, &context
)) {
3922 // XXX attributes are optional, so we should be able to
3923 // XXX return this entry without the attributes
3930 * If either the dircount or maxcount will be
3931 * exceeded, get out now. Both of these lengths
3932 * are calculated conservatively, including all
3935 len
+= (8 * NFSX_UNSIGNED
+ nlen
+ rem
+ nfhp
->nfh_len
+
3937 dirlen
+= (6 * NFSX_UNSIGNED
+ nlen
+ rem
);
3938 if (len
> count
|| dirlen
> fullsiz
) {
3944 * Build the directory record xdr from
3945 * the direntry entry.
3947 fp
= (struct nfs_fattr
*)&fl
.fl_fattr
;
3948 nfsm_srvfillattr(vap
, fp
);
3949 fl
.fl_fhsize
= txdr_unsigned(nfhp
->nfh_len
);
3950 fl
.fl_fhok
= nfs_true
;
3951 fl
.fl_postopok
= nfs_true
;
3952 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
3953 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
3954 txdr_hyper(&dp
->d_seekoff
, &fl
.fl_off
);
3958 bp
+= NFSX_UNSIGNED
;
3961 txdr_hyper(&dp
->d_fileno
, &tquad
);
3962 *tl
= tquad
.nfsuquad
[0];
3963 bp
+= NFSX_UNSIGNED
;
3965 *tl
= tquad
.nfsuquad
[1];
3966 bp
+= NFSX_UNSIGNED
;
3969 *tl
= txdr_unsigned(nlen
);
3970 bp
+= NFSX_UNSIGNED
;
3972 /* And loop around copying the name */
3977 if ((bp
+ xfer
) > be
)
3981 bcopy(cp
, bp
, tsiz
);
3987 /* And null pad to a long boundary */
3988 for (i
= 0; i
< rem
; i
++)
3992 * Now copy the flrep structure out.
3994 xfer
= sizeof(struct flrep
) - sizeof(fl
.fl_nfh
) + fl
.fl_fhsize
;
3998 if ((bp
+ xfer
) > be
)
4002 bcopy(cp
, bp
, tsiz
);
4010 cpos
+= dp
->d_reclen
;
4011 dp
= (struct direntry
*)cpos
;
4018 bp
+= NFSX_UNSIGNED
;
4024 bp
+= NFSX_UNSIGNED
;
4027 mbuf_setlen(mp
, bp
- (char*)mbuf_data(mp
));
4029 mbuf_setlen(mp
, mbuf_len(mp
) + (bp
- bpos
));
4038 * nfs commit service
4041 nfsrv_commit(nfsd
, slp
, procp
, mrq
)
4042 struct nfsrv_descript
*nfsd
;
4043 struct nfssvc_sock
*slp
;
4047 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4048 mbuf_t nam
= nfsd
->nd_nam
;
4049 caddr_t dpos
= nfsd
->nd_dpos
;
4050 struct vnode_attr bfor
, aft
;
4052 struct nfs_filehandle nfh
;
4053 struct nfs_export
*nx
;
4054 struct nfs_export_options
*nxo
;
4058 int error
= 0, for_ret
= 1, aft_ret
= 1, count
;
4060 mbuf_t mb
, mb2
, mreq
;
4062 struct vfs_context context
;
4064 nfsm_srvmtofh(&nfh
);
4065 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
4068 * XXX At this time VNOP_FSYNC() does not accept offset and byte
4069 * count parameters, so these arguments are useless (someday maybe).
4071 fxdr_hyper(tl
, &off
);
4073 count
= fxdr_unsigned(int, *tl
);
4074 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4075 nfsm_reply(2 * NFSX_UNSIGNED
);
4076 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
4079 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4081 nfsm_reply(2 * NFSX_UNSIGNED
);
4082 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
4085 context
.vc_proc
= procp
;
4086 context
.vc_ucred
= nfsd
->nd_cr
;
4088 nfsm_srv_pre_vattr_init(&bfor
, 1);
4089 for_ret
= vnode_getattr(vp
, &bfor
, &context
);
4090 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
4091 nfsm_srv_vattr_init(&aft
, 1);
4092 aft_ret
= vnode_getattr(vp
, &aft
, &context
);
4094 nfsm_reply(NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
4095 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
4097 nfsm_build(tl
, u_long
*, NFSX_V3WRITEVERF
);
4098 *tl
++ = txdr_unsigned(boottime_sec());
4099 *tl
= txdr_unsigned(0);
4107 * nfs statfs service
4110 nfsrv_statfs(nfsd
, slp
, procp
, mrq
)
4111 struct nfsrv_descript
*nfsd
;
4112 struct nfssvc_sock
*slp
;
4116 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4117 mbuf_t nam
= nfsd
->nd_nam
;
4118 caddr_t dpos
= nfsd
->nd_dpos
;
4120 struct nfs_statfs
*sfp
;
4124 int error
= 0, getret
= 1;
4125 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
4127 mbuf_t mb
, mb2
, mreq
;
4129 struct vnode_attr at
;
4130 struct nfs_filehandle nfh
;
4131 struct nfs_export
*nx
;
4132 struct nfs_export_options
*nxo
;
4135 struct vfs_context context
;
4137 nfsm_srvmtofh(&nfh
);
4138 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4139 nfsm_reply(NFSX_UNSIGNED
);
4140 nfsm_srvpostop_attr(getret
, &at
);
4143 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4145 nfsm_reply(NFSX_UNSIGNED
);
4146 nfsm_srvpostop_attr(getret
, &at
);
4149 context
.vc_proc
= procp
;
4150 context
.vc_ucred
= nfsd
->nd_cr
;
4153 VFSATTR_WANTED(&va
, f_blocks
);
4154 VFSATTR_WANTED(&va
, f_bavail
);
4155 VFSATTR_WANTED(&va
, f_files
);
4156 VFSATTR_WANTED(&va
, f_ffree
);
4157 error
= vfs_getattr(vnode_mount(vp
), &va
, &context
);
4158 blksize
= vnode_mount(vp
)->mnt_vfsstat
.f_bsize
;
4159 nfsm_srv_vattr_init(&at
, v3
);
4160 getret
= vnode_getattr(vp
, &at
, &context
);
4162 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_STATFS(v3
));
4164 nfsm_srvpostop_attr(getret
, &at
);
4167 nfsm_build(sfp
, struct nfs_statfs
*, NFSX_STATFS(v3
));
4169 tval
= (u_quad_t
)(va
.f_blocks
* blksize
);
4170 txdr_hyper(&tval
, &sfp
->sf_tbytes
);
4171 tval
= (u_quad_t
)(va
.f_bfree
* blksize
);
4172 txdr_hyper(&tval
, &sfp
->sf_fbytes
);
4173 tval
= (u_quad_t
)(va
.f_bavail
* blksize
);
4174 txdr_hyper(&tval
, &sfp
->sf_abytes
);
4175 txdr_hyper(&va
.f_files
, &sfp
->sf_tfiles
);
4176 txdr_hyper(&va
.f_ffree
, &sfp
->sf_ffiles
);
4177 txdr_hyper(&va
.f_ffree
, &sfp
->sf_afiles
);
4178 sfp
->sf_invarsec
= 0;
4180 sfp
->sf_tsize
= txdr_unsigned(NFS_V2MAXDATA
);
4181 sfp
->sf_bsize
= txdr_unsigned((unsigned)blksize
);
4182 sfp
->sf_blocks
= txdr_unsigned((unsigned)va
.f_blocks
);
4183 sfp
->sf_bfree
= txdr_unsigned((unsigned)va
.f_bfree
);
4184 sfp
->sf_bavail
= txdr_unsigned((unsigned)va
.f_bavail
);
4191 * nfs fsinfo service
4194 nfsrv_fsinfo(nfsd
, slp
, procp
, mrq
)
4195 struct nfsrv_descript
*nfsd
;
4196 struct nfssvc_sock
*slp
;
4200 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4201 mbuf_t nam
= nfsd
->nd_nam
;
4202 caddr_t dpos
= nfsd
->nd_dpos
;
4204 struct nfsv3_fsinfo
*sip
;
4207 int error
= 0, getret
= 1, prefsize
, maxsize
;
4209 mbuf_t mb
, mb2
, mreq
;
4211 struct vnode_attr at
;
4212 struct nfs_filehandle nfh
;
4213 struct nfs_export
*nx
;
4214 struct nfs_export_options
*nxo
;
4215 struct vfs_context context
;
4217 nfsm_srvmtofh(&nfh
);
4218 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4219 nfsm_reply(NFSX_UNSIGNED
);
4220 nfsm_srvpostop_attr(getret
, &at
);
4223 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4225 nfsm_reply(NFSX_UNSIGNED
);
4226 nfsm_srvpostop_attr(getret
, &at
);
4229 context
.vc_proc
= procp
;
4230 context
.vc_ucred
= nfsd
->nd_cr
;
4232 nfsm_srv_vattr_init(&at
, 1);
4233 getret
= vnode_getattr(vp
, &at
, &context
);
4235 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
4236 nfsm_srvpostop_attr(getret
, &at
);
4237 nfsm_build(sip
, struct nfsv3_fsinfo
*, NFSX_V3FSINFO
);
4241 * There should be file system VFS OP(s) to get this information.
4242 * For now, assume our usual NFS defaults.
4244 if (slp
->ns_sotype
== SOCK_DGRAM
) {
4245 maxsize
= NFS_MAXDGRAMDATA
;
4246 prefsize
= NFS_PREFDGRAMDATA
;
4248 maxsize
= prefsize
= NFS_MAXDATA
;
4249 sip
->fs_rtmax
= txdr_unsigned(maxsize
);
4250 sip
->fs_rtpref
= txdr_unsigned(prefsize
);
4251 sip
->fs_rtmult
= txdr_unsigned(NFS_FABLKSIZE
);
4252 sip
->fs_wtmax
= txdr_unsigned(maxsize
);
4253 sip
->fs_wtpref
= txdr_unsigned(prefsize
);
4254 sip
->fs_wtmult
= txdr_unsigned(NFS_FABLKSIZE
);
4255 sip
->fs_dtpref
= txdr_unsigned(prefsize
);
4256 sip
->fs_maxfilesize
.nfsuquad
[0] = 0xffffffff;
4257 sip
->fs_maxfilesize
.nfsuquad
[1] = 0xffffffff;
4258 sip
->fs_timedelta
.nfsv3_sec
= 0;
4259 sip
->fs_timedelta
.nfsv3_nsec
= txdr_unsigned(1);
4260 sip
->fs_properties
= txdr_unsigned(NFSV3FSINFO_LINK
|
4261 NFSV3FSINFO_SYMLINK
| NFSV3FSINFO_HOMOGENEOUS
|
4262 NFSV3FSINFO_CANSETTIME
);
4268 * nfs pathconf service
4271 nfsrv_pathconf(nfsd
, slp
, procp
, mrq
)
4272 struct nfsrv_descript
*nfsd
;
4273 struct nfssvc_sock
*slp
;
4277 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4278 mbuf_t nam
= nfsd
->nd_nam
;
4279 caddr_t dpos
= nfsd
->nd_dpos
;
4281 struct nfsv3_pathconf
*pc
;
4284 int error
= 0, getret
= 1, linkmax
, namemax
;
4285 int chownres
, notrunc
, case_sensitive
, case_preserving
;
4287 mbuf_t mb
, mb2
, mreq
;
4289 struct vnode_attr at
;
4290 struct nfs_filehandle nfh
;
4291 struct nfs_export
*nx
;
4292 struct nfs_export_options
*nxo
;
4293 struct vfs_context context
;
4295 nfsm_srvmtofh(&nfh
);
4296 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4297 nfsm_reply(NFSX_UNSIGNED
);
4298 nfsm_srvpostop_attr(getret
, &at
);
4301 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4303 nfsm_reply(NFSX_UNSIGNED
);
4304 nfsm_srvpostop_attr(getret
, &at
);
4307 context
.vc_proc
= procp
;
4308 context
.vc_ucred
= nfsd
->nd_cr
;
4310 error
= VNOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
, &context
);
4312 error
= VNOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
, &context
);
4314 error
= VNOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
, &context
);
4316 error
= VNOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
, &context
);
4318 error
= VNOP_PATHCONF(vp
, _PC_CASE_SENSITIVE
, &case_sensitive
, &context
);
4320 error
= VNOP_PATHCONF(vp
, _PC_CASE_PRESERVING
, &case_preserving
, &context
);
4321 nfsm_srv_vattr_init(&at
, 1);
4322 getret
= vnode_getattr(vp
, &at
, &context
);
4324 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
4325 nfsm_srvpostop_attr(getret
, &at
);
4328 nfsm_build(pc
, struct nfsv3_pathconf
*, NFSX_V3PATHCONF
);
4330 pc
->pc_linkmax
= txdr_unsigned(linkmax
);
4331 pc
->pc_namemax
= txdr_unsigned(namemax
);
4332 pc
->pc_notrunc
= txdr_unsigned(notrunc
);
4333 pc
->pc_chownrestricted
= txdr_unsigned(chownres
);
4334 pc
->pc_caseinsensitive
= txdr_unsigned(!case_sensitive
);
4335 pc
->pc_casepreserving
= txdr_unsigned(case_preserving
);
4342 * Null operation, used by clients to ping server
4347 struct nfsrv_descript
*nfsd
,
4348 struct nfssvc_sock
*slp
,
4349 __unused proc_t procp
,
4352 mbuf_t mrep
= nfsd
->nd_mrep
;
4354 int error
= NFSERR_RETVOID
;
4363 * No operation, used for obsolete procedures
4368 struct nfsrv_descript
*nfsd
,
4369 struct nfssvc_sock
*slp
,
4370 __unused proc_t procp
,
4373 mbuf_t mrep
= nfsd
->nd_mrep
;
4378 if (nfsd
->nd_repstat
)
4379 error
= nfsd
->nd_repstat
;
4381 error
= EPROCUNAVAIL
;
4388 * Perform access checking for vnodes obtained from file handles that would
4389 * refer to files already opened by a Unix client. You cannot just use
4390 * vnode_authorize() for two reasons.
4391 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4392 * 2 - The owner is to be given access irrespective of mode bits so that
4393 * processes that chmod after opening a file don't break. I don't like
4394 * this because it opens a security hole, but since the nfs server opens
4395 * a security hole the size of a barn door anyhow, what the heck.
4397 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, vnode_authorize()
4398 * will return EPERM instead of EACCESS. EPERM is always an error.
4405 kauth_action_t action
,
4406 vfs_context_t context
,
4407 struct nfs_export_options
*nxo
,
4410 struct vnode_attr vattr
;
4413 if (action
& KAUTH_VNODE_WRITE_RIGHTS
) {
4415 * Disallow write attempts on read-only exports;
4416 * unless the file is a socket or a block or character
4417 * device resident on the file system.
4419 if (nxo
->nxo_flags
& NX_READONLY
) {
4420 switch (vnode_vtype(vp
)) {
4421 case VREG
: case VDIR
: case VLNK
: case VCPLX
:
4428 error
= vnode_authorize(vp
, dvp
, action
, context
);
4430 * Allow certain operations for the owner (reads and writes
4431 * on files that are already open). Picking up from FreeBSD.
4433 if (override
&& (error
== EACCES
)) {
4435 VATTR_WANTED(&vattr
, va_uid
);
4436 if ((vnode_getattr(vp
, &vattr
, context
) == 0) &&
4437 (kauth_cred_getuid(vfs_context_ucred(context
)) == vattr
.va_uid
))
4442 #endif /* NFS_NOSERVER */