2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
27 * This code is derived from software contributed to Berkeley by
28 * Rick Macklem at The University of Guelph.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * @(#)nfs_serv.c 8.7 (Berkeley) 5/14/95
59 * FreeBSD-Id: nfs_serv.c,v 1.52 1997/10/28 15:59:05 bde Exp $
63 * nfs version 2 and 3 server calls to vnode ops
64 * - these routines generally have 3 phases
65 * 1 - break down and validate rpc request in mbuf list
66 * 2 - do the vnode ops for the request
67 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
68 * 3 - build the rpc reply in an mbuf list
70 * - do not mix the phases, since the nfsm_?? macros can return failures
71 * on a bad rpc or similar and do not do any vnode_rele()s or vnode_put()s
73 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
74 * error number iff error != 0 whereas
75 * returning an error from the server function implies a fatal error
76 * such as a badly constructed rpc request that should be dropped without
78 * For Version 3, nfsm_reply() does not return for the error case, since
79 * most version 3 rpcs return more than the status for error cases.
82 #include <sys/param.h>
83 #include <sys/systm.h>
85 #include <sys/kauth.h>
86 #include <sys/unistd.h>
87 #include <sys/malloc.h>
88 #include <sys/vnode.h>
89 #include <sys/mount_internal.h>
90 #include <sys/socket.h>
91 #include <sys/socketvar.h>
92 #include <sys/kpi_mbuf.h>
93 #include <sys/dirent.h>
95 #include <sys/kernel.h>
96 #include <sys/sysctl.h>
98 #include <sys/vnode_internal.h>
99 #include <sys/uio_internal.h>
100 #include <libkern/OSAtomic.h>
103 #include <sys/vmparam.h>
105 #include <nfs/nfsproto.h>
106 #include <nfs/rpcv2.h>
108 #include <nfs/xdr_subs.h>
109 #include <nfs/nfsm_subs.h>
111 nfstype nfsv3_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFSOCK
,
114 nfstype nfsv2_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFNON
,
117 extern u_long nfs_xdrneg1
;
118 extern u_long nfs_false
, nfs_true
;
119 extern enum vtype nv3tov_type
[8];
120 extern struct nfsstats nfsstats
;
122 int nfsrvw_procrastinate
= NFS_GATHERDELAY
* 1000;
123 int nfsrvw_procrastinate_v3
= 0;
127 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
128 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, async
, CTLFLAG_RW
, &nfs_async
, 0, "");
131 static int nfsrv_authorize(vnode_t
,vnode_t
,kauth_action_t
,vfs_context_t
,struct nfs_export_options
*,int);
132 static void nfsrvw_coalesce(struct nfsrv_descript
*, struct nfsrv_descript
*);
134 #define THREAD_SAFE_FS(VP) \
135 ((VP)->v_mount ? (VP)->v_mount->mnt_vtable->vfc_threadsafe : 0)
138 * nfs v3 access service
141 nfsrv3_access(nfsd
, slp
, procp
, mrq
)
142 struct nfsrv_descript
*nfsd
;
143 struct nfssvc_sock
*slp
;
147 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
148 mbuf_t nam
= nfsd
->nd_nam
;
149 caddr_t dpos
= nfsd
->nd_dpos
;
151 struct nfs_filehandle nfh
;
155 int error
= 0, getret
;
157 mbuf_t mb
, mreq
, mb2
;
158 struct vnode_attr vattr
, *vap
= &vattr
;
160 kauth_action_t testaction
;
161 struct vfs_context context
;
162 struct nfs_export
*nx
;
163 struct nfs_export_options
*nxo
;
166 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
167 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
168 nfsm_reply(NFSX_UNSIGNED
);
169 nfsm_srvpostop_attr(1, NULL
);
172 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
174 nfsm_reply(NFSX_UNSIGNED
);
175 nfsm_srvpostop_attr(1, NULL
);
178 nfsmode
= fxdr_unsigned(u_long
, *tl
);
180 context
.vc_proc
= procp
;
181 context
.vc_ucred
= nfsd
->nd_cr
;
184 * Each NFS mode bit is tested separately.
186 * XXX this code is nominally correct, but returns a pessimistic
187 * rather than optimistic result. It will be necessary to add
188 * an NFS-specific interface to the vnode_authorize code to
189 * obtain good performance in the optimistic mode.
191 if (nfsmode
& NFSV3ACCESS_READ
) {
192 if (vnode_isdir(vp
)) {
194 KAUTH_VNODE_LIST_DIRECTORY
|
195 KAUTH_VNODE_READ_EXTATTRIBUTES
;
198 KAUTH_VNODE_READ_DATA
|
199 KAUTH_VNODE_READ_EXTATTRIBUTES
;
201 if (nfsrv_authorize(vp
, NULL
, testaction
, &context
, nxo
, 0))
202 nfsmode
&= ~NFSV3ACCESS_READ
;
204 if ((nfsmode
& NFSV3ACCESS_LOOKUP
) &&
206 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_SEARCH
, &context
, nxo
, 0)))
207 nfsmode
&= ~NFSV3ACCESS_LOOKUP
;
208 if (nfsmode
& NFSV3ACCESS_MODIFY
) {
209 if (vnode_isdir(vp
)) {
211 KAUTH_VNODE_ADD_FILE
|
212 KAUTH_VNODE_ADD_SUBDIRECTORY
|
213 KAUTH_VNODE_DELETE_CHILD
;
216 KAUTH_VNODE_WRITE_DATA
;
218 if (nfsrv_authorize(vp
, NULL
, testaction
, &context
, nxo
, 0))
219 nfsmode
&= ~NFSV3ACCESS_MODIFY
;
221 if (nfsmode
& NFSV3ACCESS_EXTEND
) {
222 if (vnode_isdir(vp
)) {
224 KAUTH_VNODE_ADD_FILE
|
225 KAUTH_VNODE_ADD_SUBDIRECTORY
;
228 KAUTH_VNODE_WRITE_DATA
|
229 KAUTH_VNODE_APPEND_DATA
;
231 if (nfsrv_authorize(vp
, NULL
, testaction
, &context
, nxo
, 0))
232 nfsmode
&= ~NFSV3ACCESS_EXTEND
;
236 * Note concerning NFSV3ACCESS_DELETE:
237 * For hard links, the answer may be wrong if the vnode
238 * has multiple parents with different permissions.
239 * Also, some clients (e.g. MacOSX 10.3) may incorrectly
240 * interpret the missing/cleared DELETE bit.
241 * So we'll just leave the DELETE bit alone. At worst,
242 * we're telling the client it might be able to do
243 * something it really can't.
246 if ((nfsmode
& NFSV3ACCESS_EXECUTE
) &&
248 nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, &context
, nxo
, 0)))
249 nfsmode
&= ~NFSV3ACCESS_EXECUTE
;
251 nfsm_srv_vattr_init(vap
, 1);
252 getret
= vnode_getattr(vp
, vap
, &context
);
254 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED
);
255 nfsm_srvpostop_attr(getret
, vap
);
256 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
257 *tl
= txdr_unsigned(nfsmode
);
263 * nfs getattr service
266 nfsrv_getattr(nfsd
, slp
, procp
, mrq
)
267 struct nfsrv_descript
*nfsd
;
268 struct nfssvc_sock
*slp
;
272 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
273 mbuf_t nam
= nfsd
->nd_nam
;
274 caddr_t dpos
= nfsd
->nd_dpos
;
275 struct nfs_fattr
*fp
;
276 struct vnode_attr va
;
277 struct vnode_attr
*vap
= &va
;
279 struct nfs_filehandle nfh
;
285 mbuf_t mb
, mb2
, mreq
;
286 struct vfs_context context
;
287 struct nfs_export
*nx
;
288 struct nfs_export_options
*nxo
;
289 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
292 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
296 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
301 context
.vc_proc
= procp
;
302 context
.vc_ucred
= nfsd
->nd_cr
;
304 nfsm_srv_vattr_init(vap
, v3
);
305 error
= vnode_getattr(vp
, vap
, &context
);
307 nfsm_reply(NFSX_FATTR(v3
));
310 nfsm_build(fp
, struct nfs_fattr
*, NFSX_FATTR(v3
));
311 nfsm_srvfillattr(vap
, fp
);
317 * nfs setattr service
320 nfsrv_setattr(nfsd
, slp
, procp
, mrq
)
321 struct nfsrv_descript
*nfsd
;
322 struct nfssvc_sock
*slp
;
326 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
327 mbuf_t nam
= nfsd
->nd_nam
;
328 caddr_t dpos
= nfsd
->nd_dpos
;
329 struct vnode_attr preat
;
330 struct vnode_attr postat
;
331 struct vnode_attr va
;
332 struct vnode_attr
*vap
= &va
;
333 struct nfsv2_sattr
*sp
;
334 struct nfs_fattr
*fp
;
336 struct nfs_filehandle nfh
;
337 struct nfs_export
*nx
;
338 struct nfs_export_options
*nxo
;
342 int error
= 0, preat_ret
= 1, postat_ret
= 1;
343 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), gcheck
= 0;
345 mbuf_t mb
, mb2
, mreq
;
346 struct timespec guard
;
347 struct vfs_context context
;
348 kauth_action_t action
;
355 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
356 gcheck
= fxdr_unsigned(int, *tl
);
358 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
359 fxdr_nfsv3time(tl
, &guard
);
362 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
364 * Nah nah nah nah na nah
365 * There is a bug in the Sun client that puts 0xffff in the mode
366 * field of sattr when it should put in 0xffffffff. The u_short
367 * doesn't sign extend.
368 * --> check the low order 2 bytes for 0xffff
370 if ((fxdr_unsigned(int, sp
->sa_mode
) & 0xffff) != 0xffff)
371 VATTR_SET(vap
, va_mode
, nfstov_mode(sp
->sa_mode
));
372 if (sp
->sa_uid
!= nfs_xdrneg1
)
373 VATTR_SET(vap
, va_uid
, fxdr_unsigned(uid_t
, sp
->sa_uid
));
374 if (sp
->sa_gid
!= nfs_xdrneg1
)
375 VATTR_SET(vap
, va_gid
, fxdr_unsigned(gid_t
, sp
->sa_gid
));
376 if (sp
->sa_size
!= nfs_xdrneg1
)
377 VATTR_SET(vap
, va_data_size
, fxdr_unsigned(u_quad_t
, sp
->sa_size
));
378 if (sp
->sa_atime
.nfsv2_sec
!= nfs_xdrneg1
) {
379 fxdr_nfsv2time(&sp
->sa_atime
, &vap
->va_access_time
);
380 VATTR_SET_ACTIVE(vap
, va_access_time
);
382 if (sp
->sa_mtime
.nfsv2_sec
!= nfs_xdrneg1
) {
383 fxdr_nfsv2time(&sp
->sa_mtime
, &vap
->va_modify_time
);
384 VATTR_SET_ACTIVE(vap
, va_modify_time
);
389 * Save the original credential UID in case they are
390 * mapped and we need to map the IDs in the attributes.
392 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
395 * Now that we have all the fields, lets do it.
397 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
398 nfsm_reply(2 * NFSX_UNSIGNED
);
399 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
402 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
404 nfsm_reply(2 * NFSX_UNSIGNED
);
405 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
409 context
.vc_proc
= procp
;
410 context
.vc_ucred
= nfsd
->nd_cr
;
413 nfsm_srv_pre_vattr_init(&preat
, v3
);
414 error
= preat_ret
= vnode_getattr(vp
, &preat
, &context
);
415 if (!error
&& gcheck
&& VATTR_IS_SUPPORTED(&preat
, va_change_time
) &&
416 (preat
.va_change_time
.tv_sec
!= guard
.tv_sec
||
417 preat
.va_change_time
.tv_nsec
!= guard
.tv_nsec
))
418 error
= NFSERR_NOT_SYNC
;
419 if (!preat_ret
&& !VATTR_ALL_SUPPORTED(&preat
))
423 nfsm_reply(NFSX_WCCDATA(v3
));
424 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
430 * If the credentials were mapped, we should
431 * map the same values in the attributes.
433 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
435 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
436 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
437 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
441 * Authorize the attribute changes.
443 if (((error
= vnode_authattr(vp
, vap
, &action
, &context
))) ||
444 ((error
= nfsrv_authorize(vp
, NULL
, action
, &context
, nxo
, 0))))
446 error
= vnode_setattr(vp
, vap
, &context
);
448 nfsm_srv_vattr_init(&postat
, v3
);
449 postat_ret
= vnode_getattr(vp
, &postat
, &context
);
454 nfsm_reply(NFSX_WCCORFATTR(v3
));
456 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &postat
);
459 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
460 nfsm_srvfillattr(&postat
, fp
);
470 nfsrv_lookup(nfsd
, slp
, procp
, mrq
)
471 struct nfsrv_descript
*nfsd
;
472 struct nfssvc_sock
*slp
;
476 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
477 mbuf_t nam
= nfsd
->nd_nam
;
478 caddr_t dpos
= nfsd
->nd_dpos
;
479 struct nfs_fattr
*fp
;
480 struct nameidata nd
, *ndp
= &nd
;
481 /* XXX Revisit when enabling WebNFS */
482 #ifdef WEBNFS_ENABLED
483 struct nameidata ind
;
485 vnode_t vp
, dirp
= NULL
;
486 struct nfs_filehandle dnfh
, nfh
;
487 struct nfs_export
*nx
;
488 struct nfs_export_options
*nxo
;
493 int error
= 0, len
, dirattr_ret
= 1, isdotdot
;
494 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), pubflag
;
496 mbuf_t mb
, mb2
, mreq
;
497 struct vnode_attr va
, dirattr
, *vap
= &va
;
498 struct vfs_context context
;
500 context
.vc_proc
= procp
;
501 context
.vc_ucred
= nfsd
->nd_cr
;
503 nfsm_srvmtofh(&dnfh
);
504 nfsm_srvnamesiz(len
, v3
);
506 pubflag
= nfs_ispublicfh(&dnfh
);
508 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
509 nd
.ni_cnd
.cn_flags
= LOCKLEAF
;
510 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, pubflag
, &len
, &nd
);
511 isdotdot
= ((len
== 2) && (nd
.ni_cnd
.cn_pnbuf
[0] == '.') && (nd
.ni_cnd
.cn_pnbuf
[1] == '.'));
513 error
= nfs_namei(nfsd
, &context
, &nd
, &dnfh
, nam
, pubflag
, &dirp
, &nx
, &nxo
);
515 /* XXX Revisit when enabling WebNFS */
516 #ifdef WEBNFS_ENABLED
517 if (!error
&& pubflag
) {
518 if (vnode_vtype(nd
.ni_vp
) == VDIR
&& nfs_pub
.np_index
!= NULL
) {
520 * Setup call to lookup() to see if we can find
521 * the index file. Arguably, this doesn't belong
525 ind
.ni_pathlen
= strlen(nfs_pub
.np_index
);
526 ind
.ni_cnd
.cn_nameptr
= ind
.ni_cnd
.cn_pnbuf
=
528 ind
.ni_startdir
= nd
.ni_vp
;
529 ind
.ni_usedvp
= nd
.ni_vp
;
531 if (!(error
= lookup(&ind
))) {
533 * Found an index file. Get rid of
534 * the old references.
539 vnode_put(nd
.ni_startdir
);
545 * If the public filehandle was used, check that this lookup
546 * didn't result in a filehandle outside the publicly exported
550 if (!error
&& vnode_mount(ndp
->ni_vp
) != nfs_pub
.np_mount
) {
560 nfsm_srv_vattr_init(&dirattr
, v3
);
561 dirattr_ret
= vnode_getattr(dirp
, &dirattr
, &context
);
567 nfsm_reply(NFSX_POSTOPATTR(v3
));
568 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
574 error
= nfsrv_vptofh(nx
, !v3
, (isdotdot
? &dnfh
: NULL
), vp
, &context
, &nfh
);
576 nfsm_srv_vattr_init(vap
, v3
);
577 error
= vnode_getattr(vp
, vap
, &context
);
580 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_POSTOPORFATTR(v3
) + NFSX_POSTOPATTR(v3
));
582 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
585 nfsm_srvfhtom(&nfh
, v3
);
587 nfsm_srvpostop_attr(0, vap
);
588 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
590 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
591 nfsm_srvfillattr(vap
, fp
);
598 * nfs readlink service
601 nfsrv_readlink(nfsd
, slp
, procp
, mrq
)
602 struct nfsrv_descript
*nfsd
;
603 struct nfssvc_sock
*slp
;
607 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
608 mbuf_t nam
= nfsd
->nd_nam
;
609 caddr_t dpos
= nfsd
->nd_dpos
;
614 int error
= 0, i
, tlen
, len
, getret
= 1;
615 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
617 mbuf_t mb
, mb2
, mp2
, mp3
, mreq
;
619 struct vnode_attr attr
;
620 struct nfs_filehandle nfh
;
621 struct nfs_export
*nx
;
622 struct nfs_export_options
*nxo
;
624 char uio_buf
[ UIO_SIZEOF(4) ];
625 char *uio_bufp
= &uio_buf
[0];
626 int uio_buflen
= UIO_SIZEOF(4);
628 struct vfs_context context
;
636 while (len
< NFS_MAXPATHLEN
) {
638 if ((error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &mp
)))
640 mblen
= mbuf_maxlen(mp
);
641 mbuf_setlen(mp
, mblen
);
645 if ((error
= mbuf_setnext(mp2
, mp
))) {
651 if ((len
+ mblen
) > NFS_MAXPATHLEN
) {
652 mbuf_setlen(mp
, NFS_MAXPATHLEN
- len
);
653 len
= NFS_MAXPATHLEN
;
659 uio_buflen
= UIO_SIZEOF(i
);
660 MALLOC(uio_bufp
, char*, uio_buflen
, M_TEMP
, M_WAITOK
);
664 nfsm_reply(2 * NFSX_UNSIGNED
);
665 nfsm_srvpostop_attr(1, NULL
);
669 uiop
= uio_createwithbuffer(i
, 0, UIO_SYSSPACE
, UIO_READ
, uio_bufp
, uio_buflen
);
673 if (uio_bufp
!= &uio_buf
[0]) {
674 FREE(uio_bufp
, M_TEMP
);
675 uio_bufp
= &uio_buf
[0];
677 nfsm_reply(2 * NFSX_UNSIGNED
);
678 nfsm_srvpostop_attr(1, NULL
);
683 uio_addiov(uiop
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), mbuf_len(mp
));
687 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
689 if (uio_bufp
!= &uio_buf
[0]) {
690 FREE(uio_bufp
, M_TEMP
);
691 uio_bufp
= &uio_buf
[0];
693 nfsm_reply(2 * NFSX_UNSIGNED
);
694 nfsm_srvpostop_attr(1, NULL
);
697 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
700 if (uio_bufp
!= &uio_buf
[0]) {
701 FREE(uio_bufp
, M_TEMP
);
702 uio_bufp
= &uio_buf
[0];
704 nfsm_reply(2 * NFSX_UNSIGNED
);
705 nfsm_srvpostop_attr(1, NULL
);
708 if (vnode_vtype(vp
) != VLNK
) {
716 context
.vc_proc
= procp
;
717 context
.vc_ucred
= nfsd
->nd_cr
;
719 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
, nxo
, 0)))
721 error
= VNOP_READLINK(vp
, uiop
, &context
);
725 nfsm_srv_vattr_init(&attr
, v3
);
726 getret
= vnode_getattr(vp
, &attr
, &context
);
734 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_UNSIGNED
);
736 nfsm_srvpostop_attr(getret
, &attr
);
738 if (uio_bufp
!= &uio_buf
[0])
739 FREE(uio_bufp
, M_TEMP
);
744 if (uiop
&& (uio_resid(uiop
) > 0)) {
745 // LP64todo - fix this
746 len
-= uio_resid(uiop
);
747 tlen
= nfsm_rndup(len
);
748 nfsm_adj(mp3
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
750 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
751 *tl
= txdr_unsigned(len
);
752 mbuf_setnext(mb
, mp3
);
755 if (uio_bufp
!= &uio_buf
[0])
756 FREE(uio_bufp
, M_TEMP
);
764 nfsrv_read(nfsd
, slp
, procp
, mrq
)
765 struct nfsrv_descript
*nfsd
;
766 struct nfssvc_sock
*slp
;
770 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
771 mbuf_t nam
= nfsd
->nd_nam
;
772 caddr_t dpos
= nfsd
->nd_dpos
;
774 struct nfs_fattr
*fp
;
779 int error
= 0, count
, len
, left
, siz
, tlen
, getret
;
780 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), reqlen
, maxlen
;
782 mbuf_t mb
, mb2
, mreq
;
785 struct nfs_filehandle nfh
;
786 struct nfs_export
*nx
;
787 struct nfs_export_options
*nxo
;
789 char *uio_bufp
= NULL
;
790 struct vnode_attr va
, *vap
= &va
;
792 char uio_buf
[ UIO_SIZEOF(0) ];
793 struct vfs_context context
;
797 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
798 fxdr_hyper(tl
, &off
);
800 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
801 off
= (off_t
)fxdr_unsigned(u_long
, *tl
);
803 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
804 reqlen
= fxdr_unsigned(u_long
, *tl
);
805 maxlen
= NFS_SRVMAXDATA(nfsd
);
809 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
810 nfsm_reply(2 * NFSX_UNSIGNED
);
811 nfsm_srvpostop_attr(1, NULL
);
814 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
816 nfsm_reply(2 * NFSX_UNSIGNED
);
817 nfsm_srvpostop_attr(1, NULL
);
820 if (vnode_vtype(vp
) != VREG
) {
824 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
827 context
.vc_proc
= procp
;
828 context
.vc_ucred
= nfsd
->nd_cr
;
831 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_READ_DATA
, &context
, nxo
, 1)))
832 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_EXECUTE
, &context
, nxo
, 1);
834 nfsm_srv_vattr_init(vap
, v3
);
835 getret
= vnode_getattr(vp
, vap
, &context
);
840 nfsm_reply(NFSX_POSTOPATTR(v3
));
841 nfsm_srvpostop_attr(getret
, vap
);
844 if ((u_quad_t
)off
>= vap
->va_data_size
)
846 else if (((u_quad_t
)off
+ reqlen
) > vap
->va_data_size
)
847 count
= nfsm_rndup(vap
->va_data_size
- off
);
850 nfsm_reply(NFSX_POSTOPORFATTR(v3
) + 3 * NFSX_UNSIGNED
+nfsm_rndup(count
));
852 nfsm_build(tl
, u_long
*, NFSX_V3FATTR
+ 4 * NFSX_UNSIGNED
);
854 fp
= (struct nfs_fattr
*)tl
;
855 tl
+= (NFSX_V3FATTR
/ sizeof (u_long
));
857 nfsm_build(tl
, u_long
*, NFSX_V2FATTR
+ NFSX_UNSIGNED
);
858 fp
= (struct nfs_fattr
*)tl
;
859 tl
+= (NFSX_V2FATTR
/ sizeof (u_long
));
864 * Generate the mbuf list with the uio_iov ref. to it.
869 siz
= min(mbuf_trailingspace(m
), left
);
876 if ((error
= mbuf_mclget(MBUF_WAITOK
, MBUF_TYPE_DATA
, &m
)))
882 MALLOC(uio_bufp
, char *, UIO_SIZEOF(i
), M_TEMP
, M_WAITOK
);
887 uiop
= uio_createwithbuffer(i
, off
, UIO_SYSSPACE
, UIO_READ
,
888 uio_bufp
, UIO_SIZEOF(i
));
898 panic("nfsrv_read iov");
899 siz
= min(mbuf_trailingspace(m
), left
);
902 uio_addiov(uiop
, CAST_USER_ADDR_T((char *)mbuf_data(m
) + tlen
), siz
);
903 mbuf_setlen(m
, tlen
+ siz
);
909 error
= VNOP_READ(vp
, uiop
, IO_NODELOCKED
, &context
);
910 off
= uio_offset(uiop
);
913 * This may seem a little weird that we drop the whole
914 * successful read if we get an error on the getattr.
915 * The reason is because we've already set up the reply
916 * to have postop attrs and omitting these optional bits
917 * would require shifting all the data in the reply.
919 * It would be more correct if we would simply drop the
920 * postop attrs if the getattr fails. We might be able to
921 * do that easier if we allocated separate mbufs for the data.
923 nfsm_srv_vattr_init(vap
, v3
);
924 if (error
|| (getret
= vnode_getattr(vp
, vap
, &context
))) {
929 nfsm_reply(NFSX_POSTOPATTR(v3
));
930 nfsm_srvpostop_attr(getret
, vap
);
931 if (uio_bufp
!= NULL
) {
932 FREE(uio_bufp
, M_TEMP
);
937 uiop
= uio_createwithbuffer(0, 0, UIO_SYSSPACE
, UIO_READ
, &uio_buf
[0], sizeof(uio_buf
));
944 nfsm_srvfillattr(vap
, fp
);
945 // LP64todo - fix this
946 len
-= uio_resid(uiop
);
947 tlen
= nfsm_rndup(len
);
948 if (count
!= tlen
|| tlen
!= len
)
949 nfsm_adj(mb
, count
- tlen
, tlen
- len
);
951 *tl
++ = txdr_unsigned(len
);
957 *tl
= txdr_unsigned(len
);
959 if (uio_bufp
!= NULL
) {
960 FREE(uio_bufp
, M_TEMP
);
969 nfsrv_write(nfsd
, slp
, procp
, mrq
)
970 struct nfsrv_descript
*nfsd
;
971 struct nfssvc_sock
*slp
;
975 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
976 mbuf_t nam
= nfsd
->nd_nam
;
977 caddr_t dpos
= nfsd
->nd_dpos
;
980 struct nfs_fattr
*fp
;
981 struct vnode_attr va
, forat
;
982 struct vnode_attr
*vap
= &va
;
986 int error
= 0, len
, forat_ret
= 1;
987 int ioflags
, aftat_ret
= 1, retlen
, zeroing
, adjust
, tlen
;
988 int stable
= NFSV3WRITE_FILESYNC
;
989 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
991 mbuf_t mb
, mb2
, mreq
;
993 struct nfs_filehandle nfh
;
994 struct nfs_export
*nx
;
995 struct nfs_export_options
*nxo
;
998 char *uio_bufp
= NULL
;
999 struct vfs_context context
;
1005 nfsm_srvmtofh(&nfh
);
1007 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1008 fxdr_hyper(tl
, &off
);
1010 stable
= fxdr_unsigned(int, *tl
++);
1012 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1013 off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
1016 stable
= NFSV3WRITE_UNSTABLE
;
1018 retlen
= len
= fxdr_unsigned(long, *tl
);
1022 * For NFS Version 2, it is not obvious what a write of zero length
1023 * should do, but I might as well be consistent with Version 3,
1024 * which is to return ok so long as there are no permission problems.
1032 tpos
= mbuf_data(mp
);
1033 tlen
= mbuf_len(mp
);
1034 adjust
= dpos
- tpos
;
1036 mbuf_setlen(mp
, tlen
);
1037 if (tlen
> 0 && adjust
> 0) {
1039 if ((error
= mbuf_setdata(mp
, tpos
, tlen
))) {
1040 nfsm_reply(2 * NFSX_UNSIGNED
);
1041 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1048 else if ((tlen
= mbuf_len(mp
)) > 0) {
1051 mbuf_setlen(mp
, tlen
- (i
- len
));
1054 if (mbuf_len(mp
) > 0)
1060 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1062 nfsm_reply(2 * NFSX_UNSIGNED
);
1063 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1066 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
1067 nfsm_reply(2 * NFSX_UNSIGNED
);
1068 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1071 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
1073 nfsm_reply(2 * NFSX_UNSIGNED
);
1074 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1077 context
.vc_proc
= procp
;
1078 context
.vc_ucred
= nfsd
->nd_cr
;
1081 nfsm_srv_pre_vattr_init(&forat
, v3
);
1082 forat_ret
= vnode_getattr(vp
, &forat
, &context
);
1084 if (vnode_vtype(vp
) != VREG
) {
1088 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1091 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, &context
, nxo
, 1);
1095 nfsm_reply(NFSX_WCCDATA(v3
));
1096 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1101 MALLOC(uio_bufp
, char *, UIO_SIZEOF(count
), M_TEMP
, M_WAITOK
);
1105 nfsm_reply(NFSX_WCCDATA(v3
));
1106 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1109 uiop
= uio_createwithbuffer(count
, off
, UIO_SYSSPACE
, UIO_WRITE
, uio_bufp
, UIO_SIZEOF(count
));
1113 nfsm_reply(NFSX_WCCDATA(v3
));
1114 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1115 if (uio_bufp
!= NULL
) {
1116 FREE(uio_bufp
, M_TEMP
);
1122 if ((tlen
= mbuf_len(mp
)) > 0)
1123 uio_addiov(uiop
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), tlen
);
1129 * The IO_METASYNC flag indicates that all metadata (and not just
1130 * enough to ensure data integrity) mus be written to stable storage
1132 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1134 if (stable
== NFSV3WRITE_UNSTABLE
)
1135 ioflags
= IO_NODELOCKED
;
1136 else if (stable
== NFSV3WRITE_DATASYNC
)
1137 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1139 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1141 error
= VNOP_WRITE(vp
, uiop
, ioflags
, &context
);
1142 OSAddAtomic(1, (SInt32
*)(SInt32
*)&nfsstats
.srvvop_writes
);
1144 nfsm_srv_vattr_init(vap
, v3
);
1145 aftat_ret
= vnode_getattr(vp
, vap
, &context
);
1149 nfsm_reply(NFSX_PREOPATTR(v3
) + NFSX_POSTOPORFATTR(v3
) +
1150 2 * NFSX_UNSIGNED
+ NFSX_WRITEVERF(v3
));
1152 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1154 if (uio_bufp
!= NULL
) {
1155 FREE(uio_bufp
, M_TEMP
);
1159 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1160 *tl
++ = txdr_unsigned(retlen
);
1162 * If nfs_async is set, then pretend the write was FILESYNC.
1164 if (stable
== NFSV3WRITE_UNSTABLE
&& !nfs_async
)
1165 *tl
++ = txdr_unsigned(stable
);
1167 *tl
++ = txdr_unsigned(NFSV3WRITE_FILESYNC
);
1168 /* write verifier */
1169 *tl
++ = txdr_unsigned(boottime_sec());
1170 *tl
= txdr_unsigned(0);
1172 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1173 nfsm_srvfillattr(vap
, fp
);
1176 if (uio_bufp
!= NULL
) {
1177 FREE(uio_bufp
, M_TEMP
);
1183 * NFS write service with write gathering support. Called when
1184 * nfsrvw_procrastinate > 0.
1185 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1186 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1190 nfsrv_writegather(ndp
, slp
, procp
, mrq
)
1191 struct nfsrv_descript
**ndp
;
1192 struct nfssvc_sock
*slp
;
1197 struct nfsrv_descript
*wp
, *nfsd
, *owp
, *swp
;
1198 struct nfs_export
*nx
;
1199 struct nfs_export_options
*nxo
;
1200 struct nfs_fattr
*fp
;
1202 struct nfsrvw_delayhash
*wpp
;
1204 struct vnode_attr va
, forat
;
1207 caddr_t bpos
, dpos
, tpos
;
1208 int error
= 0, len
, forat_ret
= 1;
1209 int ioflags
, aftat_ret
= 1, adjust
, v3
, zeroing
, tlen
;
1211 mbuf_t mb
, mb2
, mreq
, mrep
, md
;
1214 char *uio_bufp
= NULL
;
1217 struct vfs_context context
;
1219 context
.vc_proc
= procp
;
1230 mrep
= nfsd
->nd_mrep
;
1232 dpos
= nfsd
->nd_dpos
;
1234 context
.vc_ucred
= cred
;
1235 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1236 LIST_INIT(&nfsd
->nd_coalesce
);
1237 nfsd
->nd_mreq
= NULL
;
1238 nfsd
->nd_stable
= NFSV3WRITE_FILESYNC
;
1240 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1241 nfsd
->nd_time
= cur_usec
+
1242 (v3
? nfsrvw_procrastinate_v3
: nfsrvw_procrastinate
);
1245 * Now, get the write header..
1247 nfsm_srvmtofh(&nfsd
->nd_fh
);
1248 /* XXX shouldn't we be checking for invalid FHs before doing any more work? */
1250 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1251 fxdr_hyper(tl
, &nfsd
->nd_off
);
1253 nfsd
->nd_stable
= fxdr_unsigned(int, *tl
++);
1255 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1256 nfsd
->nd_off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
1259 nfsd
->nd_stable
= NFSV3WRITE_UNSTABLE
;
1261 len
= fxdr_unsigned(long, *tl
);
1263 nfsd
->nd_eoff
= nfsd
->nd_off
+ len
;
1266 * Trim the header out of the mbuf list and trim off any trailing
1267 * junk so that the mbuf list has only the write data.
1275 tpos
= mbuf_data(mp
);
1276 tlen
= mbuf_len(mp
);
1277 adjust
= dpos
- tpos
;
1279 mbuf_setlen(mp
, tlen
);
1280 if (tlen
> 0 && adjust
> 0) {
1282 if ((error
= mbuf_setdata(mp
, tpos
, tlen
)))
1289 tlen
= mbuf_len(mp
);
1292 mbuf_setlen(mp
, tlen
- (i
- len
));
1298 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1303 nfsm_writereply(2 * NFSX_UNSIGNED
, v3
);
1305 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1306 nfsd
->nd_mreq
= mreq
;
1307 nfsd
->nd_mrep
= NULL
;
1312 * Add this entry to the hash and time queues.
1314 lck_mtx_lock(&slp
->ns_wgmutex
);
1316 wp
= slp
->ns_tq
.lh_first
;
1317 while (wp
&& wp
->nd_time
< nfsd
->nd_time
) {
1319 wp
= wp
->nd_tq
.le_next
;
1322 LIST_INSERT_AFTER(owp
, nfsd
, nd_tq
);
1324 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1326 if (nfsd
->nd_mrep
) {
1327 wpp
= NWDELAYHASH(slp
, nfsd
->nd_fh
.nfh_fid
);
1330 while (wp
&& !nfsrv_fhmatch(&nfsd
->nd_fh
, &wp
->nd_fh
)) {
1332 wp
= wp
->nd_hash
.le_next
;
1334 while (wp
&& (wp
->nd_off
< nfsd
->nd_off
) &&
1335 nfsrv_fhmatch(&nfsd
->nd_fh
, &wp
->nd_fh
)) {
1337 wp
= wp
->nd_hash
.le_next
;
1340 LIST_INSERT_AFTER(owp
, nfsd
, nd_hash
);
1343 * Search the hash list for overlapping entries and
1346 for(; nfsd
&& NFSW_CONTIG(owp
, nfsd
); nfsd
= wp
) {
1347 wp
= nfsd
->nd_hash
.le_next
;
1348 if (NFSW_SAMECRED(owp
, nfsd
))
1349 nfsrvw_coalesce(owp
, nfsd
);
1352 LIST_INSERT_HEAD(wpp
, nfsd
, nd_hash
);
1356 lck_mtx_lock(&slp
->ns_wgmutex
);
1360 * Now, do VNOP_WRITE()s for any one(s) that need to be done now
1361 * and generate the associated reply mbuf list(s).
1365 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1366 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= owp
) {
1367 owp
= nfsd
->nd_tq
.le_next
;
1368 if (nfsd
->nd_time
> cur_usec
)
1372 LIST_REMOVE(nfsd
, nd_tq
);
1373 LIST_REMOVE(nfsd
, nd_hash
);
1374 mrep
= nfsd
->nd_mrep
;
1375 nfsd
->nd_mrep
= NULL
;
1376 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1377 forat_ret
= aftat_ret
= 1;
1378 error
= nfsrv_fhtovp(&nfsd
->nd_fh
, nfsd
->nd_nam
, TRUE
, &vp
, &nx
, &nxo
);
1380 error
= nfsrv_credcheck(nfsd
, nx
, nxo
);
1385 context
.vc_ucred
= cred
;
1388 nfsm_srv_pre_vattr_init(&forat
, v3
);
1389 forat_ret
= vnode_getattr(vp
, &forat
, &context
);
1391 if (vnode_vtype(vp
) != VREG
) {
1395 error
= (vnode_vtype(vp
) == VDIR
) ? EISDIR
: EACCES
;
1400 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
, &context
, nxo
, 1);
1403 if (nfsd
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1404 ioflags
= IO_NODELOCKED
;
1405 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
)
1406 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1408 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1410 if (!error
&& ((nfsd
->nd_eoff
- nfsd
->nd_off
) > 0)) {
1414 if (mbuf_len(mp
) > 0)
1419 MALLOC(uio_bufp
, char *, UIO_SIZEOF(i
), M_TEMP
, M_WAITOK
);
1421 uiop
= uio_createwithbuffer(i
, nfsd
->nd_off
, UIO_SYSSPACE
,
1422 UIO_WRITE
, uio_bufp
, UIO_SIZEOF(i
));
1423 if (!uio_bufp
|| !uiop
)
1428 if ((tlen
= mbuf_len(mp
)) > 0)
1429 uio_addiov(uiop
, CAST_USER_ADDR_T((caddr_t
)mbuf_data(mp
)), tlen
);
1432 error
= VNOP_WRITE(vp
, uiop
, ioflags
, &context
);
1433 OSAddAtomic(1, (SInt32
*)&nfsstats
.srvvop_writes
);
1436 FREE(uio_bufp
, M_TEMP
);
1443 nfsm_srv_pre_vattr_init(&va
, v3
);
1444 aftat_ret
= vnode_getattr(vp
, &va
, &context
);
1449 * Loop around generating replies for all write rpcs that have
1450 * now been completed.
1455 nfsm_writereply(NFSX_WCCDATA(v3
), v3
);
1457 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1460 nfsm_writereply(NFSX_PREOPATTR(v3
) +
1461 NFSX_POSTOPORFATTR(v3
) + 2 * NFSX_UNSIGNED
+
1462 NFSX_WRITEVERF(v3
), v3
);
1464 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1465 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1466 *tl
++ = txdr_unsigned(nfsd
->nd_len
);
1467 *tl
++ = txdr_unsigned(swp
->nd_stable
);
1468 /* write verifier */
1469 *tl
++ = txdr_unsigned(boottime_sec());
1470 *tl
= txdr_unsigned(0);
1472 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1473 nfsm_srvfillattr(&va
, fp
);
1476 nfsd
->nd_mreq
= mreq
;
1478 panic("nfsrv_write: nd_mrep not free");
1481 * Done. Put it at the head of the timer queue so that
1482 * the final phase can return the reply.
1486 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1488 nfsd
= swp
->nd_coalesce
.lh_first
;
1490 LIST_REMOVE(nfsd
, nd_tq
);
1494 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1499 * Search for a reply to return.
1501 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= nfsd
->nd_tq
.le_next
)
1502 if (nfsd
->nd_mreq
) {
1503 LIST_REMOVE(nfsd
, nd_tq
);
1504 *mrq
= nfsd
->nd_mreq
;
1508 slp
->ns_wgtime
= slp
->ns_tq
.lh_first
? slp
->ns_tq
.lh_first
->nd_time
: 0;
1509 lck_mtx_unlock(&slp
->ns_wgmutex
);
1514 * Coalesce the write request nfsd into owp. To do this we must:
1515 * - remove nfsd from the queues
1516 * - merge nfsd->nd_mrep into owp->nd_mrep
1517 * - update the nd_eoff and nd_stable for owp
1518 * - put nfsd on owp's nd_coalesce list
1522 struct nfsrv_descript
*owp
,
1523 struct nfsrv_descript
*nfsd
)
1527 struct nfsrv_descript
*p
;
1529 LIST_REMOVE(nfsd
, nd_hash
);
1530 LIST_REMOVE(nfsd
, nd_tq
);
1531 if (owp
->nd_eoff
< nfsd
->nd_eoff
) {
1532 overlap
= owp
->nd_eoff
- nfsd
->nd_off
;
1534 panic("nfsrv_coalesce: bad off");
1536 mbuf_adj(nfsd
->nd_mrep
, overlap
);
1538 while ((mpnext
= mbuf_next(mp
)))
1540 error
= mbuf_setnext(mp
, nfsd
->nd_mrep
);
1542 panic("nfsrvw_coalesce: mbuf_setnext failed: %d", error
);
1543 owp
->nd_eoff
= nfsd
->nd_eoff
;
1545 mbuf_freem(nfsd
->nd_mrep
);
1547 nfsd
->nd_mrep
= NULL
;
1548 if (nfsd
->nd_stable
== NFSV3WRITE_FILESYNC
)
1549 owp
->nd_stable
= NFSV3WRITE_FILESYNC
;
1550 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
&&
1551 owp
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1552 owp
->nd_stable
= NFSV3WRITE_DATASYNC
;
1553 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nfsd
, nd_tq
);
1556 * If nfsd had anything else coalesced into it, transfer them
1557 * to owp, otherwise their replies will never get sent.
1559 for (p
= nfsd
->nd_coalesce
.lh_first
; p
;
1560 p
= nfsd
->nd_coalesce
.lh_first
) {
1561 LIST_REMOVE(p
, nd_tq
);
1562 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1567 * Sort the group list in increasing numerical order.
1568 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1569 * that used to be here.)
1574 nfsrvw_sort(list
, num
)
1581 /* Insertion sort. */
1582 for (i
= 1; i
< num
; i
++) {
1584 /* find correct slot for value v, moving others up */
1585 for (j
= i
; --j
>= 0 && v
< list
[j
];)
1586 list
[j
+ 1] = list
[j
];
1592 * copy credentials making sure that the result can be compared with bcmp().
1597 nfsrv_setcred(kauth_cred_t incred
, kauth_cred_t outcred
)
1601 bzero((caddr_t
)outcred
, sizeof (*outcred
));
1602 outcred
->cr_ref
= 1;
1603 outcred
->cr_uid
= kauth_cred_getuid(incred
);
1604 outcred
->cr_ngroups
= incred
->cr_ngroups
;
1605 for (i
= 0; i
< incred
->cr_ngroups
; i
++)
1606 outcred
->cr_groups
[i
] = incred
->cr_groups
[i
];
1607 nfsrvw_sort(outcred
->cr_groups
, outcred
->cr_ngroups
);
1611 * nfs create service
1612 * now does a truncate to 0 length via. setattr if it already exists
1615 nfsrv_create(nfsd
, slp
, procp
, mrq
)
1616 struct nfsrv_descript
*nfsd
;
1617 struct nfssvc_sock
*slp
;
1621 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
1622 mbuf_t nam
= nfsd
->nd_nam
;
1623 caddr_t dpos
= nfsd
->nd_dpos
;
1624 struct nfs_fattr
*fp
;
1625 struct vnode_attr dirfor
, diraft
, postat
;
1626 struct vnode_attr va
;
1627 struct vnode_attr
*vap
= &va
;
1628 struct nfsv2_sattr
*sp
;
1630 struct nameidata nd
;
1634 int error
= 0, rdev
, len
, tsize
, dirfor_ret
= 1, diraft_ret
= 1;
1635 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), how
, exclusive_flag
= 0;
1637 mbuf_t mb
, mb2
, mreq
;
1638 vnode_t vp
, dvp
, dirp
= NULL
;
1639 struct nfs_filehandle nfh
;
1640 struct nfs_export
*nx
;
1641 struct nfs_export_options
*nxo
;
1643 u_char cverf
[NFSX_V3CREATEVERF
];
1644 struct vfs_context context
;
1647 context
.vc_proc
= procp
;
1648 context
.vc_ucred
= nfsd
->nd_cr
;
1651 * Save the original credential UID in case they are
1652 * mapped and we need to map the IDs in the attributes.
1654 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
1659 nd
.ni_cnd
.cn_nameiop
= 0;
1661 nfsm_srvmtofh(&nfh
);
1662 nfsm_srvnamesiz(len
, v3
);
1664 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1665 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1666 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
1668 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
1671 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
1672 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
1679 nd
.ni_cnd
.cn_nameiop
= 0;
1680 nfsm_reply(NFSX_WCCDATA(v3
));
1681 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1692 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
1693 how
= fxdr_unsigned(int, *tl
);
1695 case NFSV3CREATE_GUARDED
:
1700 case NFSV3CREATE_UNCHECKED
:
1703 case NFSV3CREATE_EXCLUSIVE
:
1704 nfsm_dissect(cp
, caddr_t
, NFSX_V3CREATEVERF
);
1705 bcopy(cp
, cverf
, NFSX_V3CREATEVERF
);
1708 VATTR_SET(vap
, va_mode
, 0);
1711 VATTR_SET(vap
, va_type
, VREG
);
1715 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1716 v_type
= IFTOVT(fxdr_unsigned(u_long
, sp
->sa_mode
));
1719 VATTR_SET(vap
, va_type
, v_type
);
1720 VATTR_SET(vap
, va_mode
, nfstov_mode(sp
->sa_mode
));
1724 tsize
= fxdr_unsigned(long, sp
->sa_size
);
1726 VATTR_SET(vap
, va_data_size
, (u_quad_t
)tsize
);
1731 rdev
= fxdr_unsigned(long, sp
->sa_size
);
1739 * If it doesn't exist, create it
1740 * otherwise just truncate to 0 length
1741 * should I set the mode too ??
1744 kauth_acl_t xacl
= NULL
;
1747 * If the credentials were mapped, we should
1748 * map the same values in the attributes.
1750 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
1752 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
1753 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
1754 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
1757 /* authorize before creating */
1758 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
1760 /* construct ACL and handle inheritance */
1762 error
= kauth_acl_inherit(dvp
,
1768 if (!error
&& xacl
!= NULL
)
1769 VATTR_SET(vap
, va_acl
, xacl
);
1771 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
1772 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
1774 /* validate new-file security information */
1776 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
1777 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
1779 * Most NFS servers just ignore the UID/GID attributes, so we
1780 * try ignoring them if that'll help the request succeed.
1782 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
1783 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
1784 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
1788 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1791 error
= VNOP_CREATE(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
1793 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
1795 * If some of the requested attributes weren't handled by the VNOP,
1796 * use our fallback code.
1798 error
= vnode_setattr_fallback(vp
, vap
, &context
);
1801 kauth_acl_free(xacl
);
1804 if (exclusive_flag
) {
1807 bcopy(cverf
, (caddr_t
)&vap
->va_access_time
,
1809 VATTR_SET_ACTIVE(vap
, va_access_time
);
1810 // skip authorization, as this is an
1811 // NFS internal implementation detail.
1812 error
= vnode_setattr(vp
, vap
, &context
);
1816 } else if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
||
1817 vap
->va_type
== VFIFO
) {
1818 if (vap
->va_type
== VCHR
&& rdev
== (int)0xffffffff)
1819 VATTR_SET(vap
, va_type
, VFIFO
);
1820 if (vap
->va_type
!= VFIFO
&&
1821 (error
= suser(nfsd
->nd_cr
, (u_short
*)0))) {
1824 VATTR_SET(vap
, va_rdev
, (dev_t
)rdev
);
1826 error
= VNOP_MKNOD(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
1829 kauth_acl_free(xacl
);
1839 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1840 nd
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
1841 nd
.ni_cnd
.cn_context
= &context
;
1842 nd
.ni_startdir
= dvp
;
1844 error
= lookup(&nd
);
1846 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
)
1856 * nameidone has to happen before we vnode_put(dvp)
1857 * since it may need to release the fs_nodelock on the dvp
1860 nd
.ni_cnd
.cn_nameiop
= 0;
1865 * nameidone has to happen before we vnode_put(dvp)
1866 * since it may need to release the fs_nodelock on the dvp
1869 nd
.ni_cnd
.cn_nameiop
= 0;
1873 if (!error
&& VATTR_IS_ACTIVE(vap
, va_data_size
)) {
1874 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_WRITE_DATA
,
1877 tempsize
= vap
->va_data_size
;
1879 VATTR_SET(vap
, va_data_size
, tempsize
);
1880 error
= vnode_setattr(vp
, vap
, &context
);
1885 error
= nfsrv_vptofh(nx
, !v3
, NULL
, vp
, &context
, &nfh
);
1887 nfsm_srv_vattr_init(&postat
, v3
);
1888 error
= vnode_getattr(vp
, &postat
, &context
);
1895 if (exclusive_flag
&& !error
&&
1896 bcmp(cverf
, (caddr_t
)&postat
.va_access_time
, NFSX_V3CREATEVERF
))
1898 nfsm_srv_vattr_init(&diraft
, v3
);
1899 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
1903 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_FATTR(v3
) + NFSX_WCCDATA(v3
));
1907 nfsm_srvpostop_fh(&nfh
);
1908 nfsm_srvpostop_attr(0, &postat
);
1910 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1912 nfsm_srvfhtom(&nfh
, v3
);
1913 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1914 nfsm_srvfillattr(&postat
, fp
);
1918 if (nd
.ni_cnd
.cn_nameiop
) {
1920 * nameidone has to happen before we vnode_put(dvp)
1921 * since it may need to release the fs_nodelock on the dvp
1935 * nfs v3 mknod service
1938 nfsrv_mknod(nfsd
, slp
, procp
, mrq
)
1939 struct nfsrv_descript
*nfsd
;
1940 struct nfssvc_sock
*slp
;
1944 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
1945 mbuf_t nam
= nfsd
->nd_nam
;
1946 caddr_t dpos
= nfsd
->nd_dpos
;
1947 struct vnode_attr dirfor
, diraft
, postat
;
1948 struct vnode_attr va
;
1949 struct vnode_attr
*vap
= &va
;
1951 struct nameidata nd
;
1954 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
1955 u_long major
, minor
;
1958 mbuf_t mb
, mb2
, mreq
;
1959 vnode_t vp
, dvp
, dirp
= NULL
;
1960 struct nfs_filehandle nfh
;
1961 struct nfs_export
*nx
;
1962 struct nfs_export_options
*nxo
;
1963 struct vfs_context hacked_context
; /* XXX should we have this? */
1964 struct vfs_context context
;
1966 kauth_acl_t xacl
= NULL
;
1968 context
.vc_proc
= procp
;
1969 context
.vc_ucred
= nfsd
->nd_cr
;
1970 hacked_context
.vc_proc
= procp
;
1971 hacked_context
.vc_ucred
= proc_ucred(procp
);
1974 * Save the original credential UID in case they are
1975 * mapped and we need to map the IDs in the attributes.
1977 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
1980 nd
.ni_cnd
.cn_nameiop
= 0;
1981 nfsm_srvmtofh(&nfh
);
1982 nfsm_srvnamesiz(len
, 1);
1984 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1985 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1986 error
= nfsm_path_mbuftond(&md
, &dpos
, 1, FALSE
, &len
, &nd
);
1988 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
1990 nfsm_srv_pre_vattr_init(&dirfor
, 1);
1991 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
1994 nd
.ni_cnd
.cn_nameiop
= 0;
1995 nfsm_reply(NFSX_WCCDATA(1));
1996 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2004 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
2005 vtyp
= nfsv3tov_type(*tl
);
2006 if (vtyp
!= VCHR
&& vtyp
!= VBLK
&& vtyp
!= VSOCK
&& vtyp
!= VFIFO
) {
2007 error
= NFSERR_BADTYPE
;
2013 if (vtyp
== VCHR
|| vtyp
== VBLK
) {
2014 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2015 major
= fxdr_unsigned(u_long
, *tl
++);
2016 minor
= fxdr_unsigned(u_long
, *tl
);
2017 VATTR_SET(vap
, va_rdev
, makedev(major
, minor
));
2021 * If it doesn't exist, create it.
2027 VATTR_SET(vap
, va_type
, vtyp
);
2030 * If the credentials were mapped, we should
2031 * map the same values in the attributes.
2033 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
2035 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
2036 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
2037 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
2040 /* authorize before creating */
2041 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
2043 /* construct ACL and handle inheritance */
2045 error
= kauth_acl_inherit(dvp
,
2051 if (!error
&& xacl
!= NULL
)
2052 VATTR_SET(vap
, va_acl
, xacl
);
2054 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
2055 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
2057 /* validate new-file security information */
2059 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
2060 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
2062 * Most NFS servers just ignore the UID/GID attributes, so we
2063 * try ignoring them if that'll help the request succeed.
2065 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
2066 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
2067 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
2071 if (vtyp
== VSOCK
) {
2072 error
= VNOP_CREATE(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
2074 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
2076 * If some of the requested attributes weren't handled by the VNOP,
2077 * use our fallback code.
2079 error
= vnode_setattr_fallback(vp
, vap
, &context
);
2081 if (vtyp
!= VFIFO
&& (error
= suser(nfsd
->nd_cr
, (u_short
*)0))) {
2084 if ((error
= VNOP_MKNOD(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
))) {
2092 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2093 nd
.ni_cnd
.cn_flags
&= ~LOCKPARENT
;
2094 nd
.ni_cnd
.cn_context
= &hacked_context
;
2095 nd
.ni_startdir
= dvp
;
2097 error
= lookup(&nd
);
2100 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
)
2106 kauth_acl_free(xacl
);
2109 * nameidone has to happen before we vnode_put(dvp)
2110 * since it may need to release the fs_nodelock on the dvp
2113 nd
.ni_cnd
.cn_nameiop
= 0;
2118 error
= nfsrv_vptofh(nx
, 0, NULL
, vp
, &context
, &nfh
);
2120 nfsm_srv_vattr_init(&postat
, 1);
2121 error
= vnode_getattr(vp
, &postat
, &context
);
2127 nfsm_srv_vattr_init(&diraft
, 1);
2128 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
2132 nfsm_reply(NFSX_SRVFH(1, &nfh
) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
2134 nfsm_srvpostop_fh(&nfh
);
2135 nfsm_srvpostop_attr(0, &postat
);
2137 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2140 if (nd
.ni_cnd
.cn_nameiop
) {
2142 * nameidone has to happen before we vnode_put(dvp)
2143 * since it may need to release the fs_nodelock on the dvp
2157 * nfs remove service
2160 nfsrv_remove(nfsd
, slp
, procp
, mrq
)
2161 struct nfsrv_descript
*nfsd
;
2162 struct nfssvc_sock
*slp
;
2166 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2167 mbuf_t nam
= nfsd
->nd_nam
;
2168 caddr_t dpos
= nfsd
->nd_dpos
;
2169 struct nameidata nd
;
2173 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2174 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2177 vnode_t vp
, dvp
, dirp
= NULL
;
2178 struct vnode_attr dirfor
, diraft
;
2179 struct nfs_filehandle nfh
;
2180 struct nfs_export
*nx
;
2181 struct nfs_export_options
*nxo
;
2182 struct vfs_context context
;
2184 context
.vc_proc
= procp
;
2185 context
.vc_ucred
= nfsd
->nd_cr
;
2188 nfsm_srvmtofh(&nfh
);
2189 nfsm_srvnamesiz(len
, v3
);
2191 nd
.ni_cnd
.cn_nameiop
= DELETE
;
2192 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2193 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
2195 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2198 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
2199 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2209 if (vnode_vtype(vp
) == VDIR
)
2210 error
= EPERM
; /* POSIX */
2211 else if (vnode_isvroot(vp
))
2213 * The root of a mounted filesystem cannot be deleted.
2217 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, &context
, nxo
, 0);
2220 error
= VNOP_REMOVE(dvp
, vp
, &nd
.ni_cnd
, 0, &context
);
2223 * nameidone has to happen before we vnode_put(dvp)
2224 * since it may need to release the fs_nodelock on the dvp
2232 nfsm_srv_vattr_init(&diraft
, v3
);
2233 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
2236 nfsm_reply(NFSX_WCCDATA(v3
));
2238 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2246 * nfs rename service
2249 nfsrv_rename(nfsd
, slp
, procp
, mrq
)
2250 struct nfsrv_descript
*nfsd
;
2251 struct nfssvc_sock
*slp
;
2255 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2256 mbuf_t nam
= nfsd
->nd_nam
;
2257 caddr_t dpos
= nfsd
->nd_dpos
;
2258 kauth_cred_t saved_cred
= NULL
;
2262 int error
= 0, fromlen
, tolen
;
2263 int fdirfor_ret
= 1, fdiraft_ret
= 1;
2264 int tdirfor_ret
= 1, tdiraft_ret
= 1;
2265 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2266 char *cp2
, *frompath
= NULL
, *topath
= NULL
;
2268 struct nameidata fromnd
, tond
;
2269 vnode_t fvp
, tvp
, tdvp
, fdvp
, fdirp
= NULL
;
2270 vnode_t tdirp
= NULL
;
2271 struct vnode_attr fdirfor
, fdiraft
, tdirfor
, tdiraft
;
2272 struct nfs_filehandle fnfh
, tnfh
;
2273 struct nfs_export
*fnx
, *tnx
;
2274 struct nfs_export_options
*fnxo
, *tnxo
;
2275 enum vtype fvtype
, tvtype
;
2276 int holding_mntlock
;
2278 struct vfs_context context
;
2280 context
.vc_proc
= procp
;
2281 context
.vc_ucred
= nfsd
->nd_cr
;
2288 * these need to be set before
2289 * calling any nfsm_xxxx macros
2290 * since they may take us out
2291 * through the error path
2293 holding_mntlock
= 0;
2298 nfsm_srvmtofh(&fnfh
);
2299 nfsm_srvnamesiz(fromlen
, v3
);
2300 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &fromlen
, &fromnd
);
2305 frompath
= fromnd
.ni_cnd
.cn_pnbuf
;
2306 nfsm_srvmtofh(&tnfh
);
2307 nfsm_strsiz(tolen
, NFS_MAXNAMLEN
, v3
);
2308 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &tolen
, &tond
);
2311 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
2314 topath
= tond
.ni_cnd
.cn_pnbuf
;
2317 * Remember our original uid so that we can reset cr_uid before
2318 * the second nfs_namei() call, in case it is remapped.
2320 saved_cred
= nfsd
->nd_cr
;
2321 kauth_cred_ref(saved_cred
);
2323 fromnd
.ni_cnd
.cn_nameiop
= DELETE
;
2324 fromnd
.ni_cnd
.cn_flags
= WANTPARENT
;
2326 fromnd
.ni_cnd
.cn_pnbuf
= frompath
;
2328 fromnd
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2329 fromnd
.ni_cnd
.cn_flags
|= HASBUF
;
2331 error
= nfs_namei(nfsd
, &context
, &fromnd
, &fnfh
, nam
, FALSE
, &fdirp
, &fnx
, &fnxo
);
2334 fdvp
= fromnd
.ni_dvp
;
2339 nfsm_srv_pre_vattr_init(&fdirfor
, v3
);
2340 fdirfor_ret
= vnode_getattr(fdirp
, &fdirfor
, &context
);
2346 fvtype
= vnode_vtype(fvp
);
2348 /* reset credential if it was remapped */
2349 if (nfsd
->nd_cr
!= saved_cred
) {
2350 kauth_cred_rele(nfsd
->nd_cr
);
2351 nfsd
->nd_cr
= saved_cred
;
2352 kauth_cred_ref(nfsd
->nd_cr
);
2355 tond
.ni_cnd
.cn_nameiop
= RENAME
;
2356 tond
.ni_cnd
.cn_flags
= WANTPARENT
;
2358 tond
.ni_cnd
.cn_pnbuf
= topath
;
2360 tond
.ni_cnd
.cn_pnlen
= MAXPATHLEN
;
2361 tond
.ni_cnd
.cn_flags
|= HASBUF
;
2364 tond
.ni_cnd
.cn_flags
|= WILLBEDIR
;
2366 error
= nfs_namei(nfsd
, &context
, &tond
, &tnfh
, nam
, FALSE
, &tdirp
, &tnx
, &tnxo
);
2369 * Translate error code for rename("dir1", "dir2/.").
2371 if (error
== EISDIR
&& fvtype
== VDIR
) {
2384 nfsm_srv_pre_vattr_init(&tdirfor
, v3
);
2385 tdirfor_ret
= vnode_getattr(tdirp
, &tdirfor
, &context
);
2393 tvtype
= vnode_vtype(tvp
);
2395 if (fvtype
== VDIR
&& tvtype
!= VDIR
) {
2401 } else if (fvtype
!= VDIR
&& tvtype
== VDIR
) {
2408 if (tvtype
== VDIR
&& vnode_mountedhere(tvp
)) {
2427 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
2428 * the node is moving between directories and we need rights to remove from the
2429 * old and add to the new.
2431 * If tvp already exists and is not a directory, we need to be allowed to delete it.
2433 * Note that we do not inherit when renaming. XXX this needs to be revisited to
2434 * implement the deferred-inherit bit.
2440 if ((tvp
!= NULL
) && vnode_isdir(tvp
)) {
2443 } else if (tdvp
!= fdvp
) {
2447 /* moving out of fdvp, must have delete rights */
2448 if ((error
= nfsrv_authorize(fvp
, fdvp
, KAUTH_VNODE_DELETE
, &context
, fnxo
, 0)) != 0)
2450 /* moving into tdvp or tvp, must have rights to add */
2451 if ((error
= nfsrv_authorize(((tvp
!= NULL
) && vnode_isdir(tvp
)) ? tvp
: tdvp
,
2453 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2454 &context
, tnxo
, 0)) != 0)
2457 /* node staying in same directory, must be allowed to add new name */
2458 if ((error
= nfsrv_authorize(fdvp
, NULL
,
2459 vnode_isdir(fvp
) ? KAUTH_VNODE_ADD_SUBDIRECTORY
: KAUTH_VNODE_ADD_FILE
,
2460 &context
, fnxo
, 0)) != 0)
2463 /* overwriting tvp */
2464 if ((tvp
!= NULL
) && !vnode_isdir(tvp
) &&
2465 ((error
= nfsrv_authorize(tvp
, tdvp
, KAUTH_VNODE_DELETE
, &context
, tnxo
, 0)) != 0))
2468 /* XXX more checks? */
2471 /* authorization denied */
2476 if ((vnode_mount(fvp
) != vnode_mount(tdvp
)) ||
2477 (tvp
&& (vnode_mount(fvp
) != vnode_mount(tvp
)))) {
2485 * The following edge case is caught here:
2486 * (to cannot be a descendent of from)
2499 if (tdvp
->v_parent
== fvp
) {
2506 if (fvtype
== VDIR
&& vnode_mountedhere(fvp
)) {
2514 * If source is the same as the destination (that is the
2515 * same vnode) then there is nothing to do...
2516 * EXCEPT if the underlying file system supports case
2517 * insensitivity and is case preserving. In this case
2518 * the file system needs to handle the special case of
2519 * getting the same vnode as target (fvp) and source (tvp).
2521 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2522 * and _PC_CASE_PRESERVING can have this exception, and they need to
2523 * handle the special case of getting the same vnode as target and
2524 * source. NOTE: Then the target is unlocked going into vnop_rename,
2525 * so not to cause locking problems. There is a single reference on tvp.
2527 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2528 * that correct behaviour then is just to remove the source (link)
2530 if ((fvp
== tvp
) && (fdvp
== tdvp
)) {
2531 if (fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
2532 !bcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
2533 fromnd
.ni_cnd
.cn_namelen
)) {
2538 if (holding_mntlock
&& vnode_mount(fvp
) != locked_mp
) {
2540 * we're holding a reference and lock
2541 * on locked_mp, but it no longer matches
2542 * what we want to do... so drop our hold
2544 mount_unlock_renames(locked_mp
);
2545 mount_drop(locked_mp
, 0);
2546 holding_mntlock
= 0;
2548 if (tdvp
!= fdvp
&& fvtype
== VDIR
) {
2550 * serialize renames that re-shape
2551 * the tree... if holding_mntlock is
2552 * set, then we're ready to go...
2554 * first need to drop the iocounts
2555 * we picked up, second take the
2556 * lock to serialize the access,
2557 * then finally start the lookup
2558 * process over with the lock held
2560 if (!holding_mntlock
) {
2562 * need to grab a reference on
2563 * the mount point before we
2564 * drop all the iocounts... once
2565 * the iocounts are gone, the mount
2568 locked_mp
= vnode_mount(fvp
);
2569 mount_ref(locked_mp
, 0);
2571 /* make a copy of to path to pass to nfs_namei() again */
2572 MALLOC_ZONE(topath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2574 bcopy(tond
.ni_cnd
.cn_pnbuf
, topath
, tolen
+ 1);
2577 * nameidone has to happen before we vnode_put(tdvp)
2578 * since it may need to release the fs_nodelock on the tdvp
2586 /* make a copy of from path to pass to nfs_namei() again */
2587 MALLOC_ZONE(frompath
, caddr_t
, MAXPATHLEN
, M_NAMEI
, M_WAITOK
);
2589 bcopy(fromnd
.ni_cnd
.cn_pnbuf
, frompath
, fromlen
+ 1);
2592 * nameidone has to happen before we vnode_put(fdvp)
2593 * since it may need to release the fs_nodelock on the fdvp
2608 mount_lock_renames(locked_mp
);
2609 holding_mntlock
= 1;
2614 fdirfor_ret
= tdirfor_ret
= 1;
2616 if (!topath
|| !frompath
) {
2617 /* we couldn't allocate a path, so bail */
2626 * when we dropped the iocounts to take
2627 * the lock, we allowed the identity of
2628 * the various vnodes to change... if they did,
2629 * we may no longer be dealing with a rename
2630 * that reshapes the tree... once we're holding
2631 * the iocounts, the vnodes can't change type
2632 * so we're free to drop the lock at this point
2635 if (holding_mntlock
) {
2636 mount_unlock_renames(locked_mp
);
2637 mount_drop(locked_mp
, 0);
2638 holding_mntlock
= 0;
2642 // save these off so we can later verify that fvp is the same
2645 oname
= fvp
->v_name
;
2646 oparent
= fvp
->v_parent
;
2648 error
= VNOP_RENAME(fromnd
.ni_dvp
, fromnd
.ni_vp
, &fromnd
.ni_cnd
,
2649 tond
.ni_dvp
, tond
.ni_vp
, &tond
.ni_cnd
, &context
);
2651 * fix up name & parent pointers. note that we first
2652 * check that fvp has the same name/parent pointers it
2653 * had before the rename call... this is a 'weak' check
2656 if (oname
== fvp
->v_name
&& oparent
== fvp
->v_parent
) {
2658 update_flags
= VNODE_UPDATE_NAME
;
2660 update_flags
|= VNODE_UPDATE_PARENT
;
2661 vnode_update_identity(fvp
, tdvp
, tond
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_namelen
, tond
.ni_cnd
.cn_hash
, update_flags
);
2664 if (holding_mntlock
) {
2665 mount_unlock_renames(locked_mp
);
2666 mount_drop(locked_mp
, 0);
2667 holding_mntlock
= 0;
2671 * nameidone has to happen before we vnode_put(tdvp)
2672 * since it may need to release the fs_nodelock on the tdvp
2683 * nameidone has to happen before we vnode_put(fdvp)
2684 * since it may need to release the fs_nodelock on the fdvp
2695 nfsm_srv_vattr_init(&fdiraft
, v3
);
2696 fdiraft_ret
= vnode_getattr(fdirp
, &fdiraft
, &context
);
2701 nfsm_srv_vattr_init(&tdiraft
, v3
);
2702 tdiraft_ret
= vnode_getattr(tdirp
, &tdiraft
, &context
);
2706 nfsm_reply(2 * NFSX_WCCDATA(v3
));
2708 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
2709 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
2712 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
2714 FREE_ZONE(topath
, MAXPATHLEN
, M_NAMEI
);
2716 kauth_cred_rele(saved_cred
);
2720 if (holding_mntlock
) {
2721 mount_unlock_renames(locked_mp
);
2722 mount_drop(locked_mp
, 0);
2726 * nameidone has to happen before we vnode_put(tdvp)
2727 * since it may need to release the fs_nodelock on the tdvp
2737 * nameidone has to happen before we vnode_put(fdvp)
2738 * since it may need to release the fs_nodelock on the fdvp
2751 FREE_ZONE(frompath
, MAXPATHLEN
, M_NAMEI
);
2753 FREE_ZONE(topath
, MAXPATHLEN
, M_NAMEI
);
2755 kauth_cred_rele(saved_cred
);
2763 nfsrv_link(nfsd
, slp
, procp
, mrq
)
2764 struct nfsrv_descript
*nfsd
;
2765 struct nfssvc_sock
*slp
;
2769 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2770 mbuf_t nam
= nfsd
->nd_nam
;
2771 caddr_t dpos
= nfsd
->nd_dpos
;
2772 struct nameidata nd
;
2776 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2777 int getret
= 1, v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2780 vnode_t vp
, xp
, dvp
, dirp
= NULL
;
2781 struct vnode_attr dirfor
, diraft
, at
;
2782 struct nfs_filehandle nfh
, dnfh
;
2783 struct nfs_export
*nx
;
2784 struct nfs_export_options
*nxo
;
2785 struct vfs_context context
;
2787 vp
= xp
= dvp
= NULL
;
2788 nfsm_srvmtofh(&nfh
);
2789 nfsm_srvmtofh(&dnfh
);
2790 nfsm_srvnamesiz(len
, v3
);
2791 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
2792 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2793 nfsm_srvpostop_attr(getret
, &at
);
2794 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2797 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
2799 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2800 nfsm_srvpostop_attr(getret
, &at
);
2801 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2805 /* we're not allowed to link to directories... */
2806 if (vnode_vtype(vp
) == VDIR
) {
2807 error
= EPERM
; /* POSIX */
2811 context
.vc_proc
= procp
;
2812 context
.vc_ucred
= nfsd
->nd_cr
;
2814 /* ...or to anything that kauth doesn't want us to (eg. immutable items) */
2815 if ((error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LINKTARGET
, &context
, nxo
, 0)) != 0)
2818 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2819 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2820 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
2822 error
= nfs_namei(nfsd
, &context
, &nd
, &dnfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2825 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
2826 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2839 else if (vnode_mount(vp
) != vnode_mount(dvp
))
2842 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
2845 error
= VNOP_LINK(vp
, dvp
, &nd
.ni_cnd
, &context
);
2848 * nameidone has to happen before we vnode_put(dvp)
2849 * since it may need to release the fs_nodelock on the dvp
2858 nfsm_srv_vattr_init(&at
, v3
);
2859 getret
= vnode_getattr(vp
, &at
, &context
);
2862 nfsm_srv_vattr_init(&diraft
, v3
);
2863 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
2868 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2870 nfsm_srvpostop_attr(getret
, &at
);
2871 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2879 * nfs symbolic link service
2882 nfsrv_symlink(nfsd
, slp
, procp
, mrq
)
2883 struct nfsrv_descript
*nfsd
;
2884 struct nfssvc_sock
*slp
;
2888 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
2889 mbuf_t nam
= nfsd
->nd_nam
;
2890 caddr_t dpos
= nfsd
->nd_dpos
;
2891 struct vnode_attr dirfor
, diraft
, postat
;
2892 struct nameidata nd
;
2893 struct vnode_attr va
;
2894 struct vnode_attr
*vap
= &va
;
2897 struct nfsv2_sattr
*sp
;
2898 char *bpos
, *linkdata
= NULL
, *cp2
;
2899 int error
= 0, len
, linkdatalen
;
2900 int dirfor_ret
= 1, diraft_ret
= 1;
2901 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2902 mbuf_t mb
, mreq
, mb2
;
2903 vnode_t vp
, dvp
, dirp
= NULL
;
2904 struct nfs_filehandle nfh
;
2905 struct nfs_export
*nx
;
2906 struct nfs_export_options
*nxo
;
2908 char uio_buf
[ UIO_SIZEOF(1) ];
2909 struct vfs_context context
;
2912 context
.vc_proc
= procp
;
2913 context
.vc_ucred
= nfsd
->nd_cr
;
2916 * Save the original credential UID in case they are
2917 * mapped and we need to map the IDs in the attributes.
2919 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
2921 nd
.ni_cnd
.cn_nameiop
= 0;
2923 nfsm_srvmtofh(&nfh
);
2924 nfsm_srvnamesiz(len
, v3
);
2926 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2927 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2928 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
2930 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
2933 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
2934 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
2941 nd
.ni_cnd
.cn_nameiop
= 0;
2950 nfsm_strsiz(linkdatalen
, NFS_MAXPATHLEN
, v3
);
2951 MALLOC(linkdata
, caddr_t
, linkdatalen
+ 1, M_TEMP
, M_WAITOK
);
2954 nd
.ni_cnd
.cn_nameiop
= 0;
2955 vnode_put(nd
.ni_dvp
);
2956 vnode_put(nd
.ni_vp
);
2960 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
2961 &uio_buf
[0], sizeof(uio_buf
));
2964 nd
.ni_cnd
.cn_nameiop
= 0;
2965 vnode_put(nd
.ni_dvp
);
2966 vnode_put(nd
.ni_vp
);
2970 uio_addiov(auio
, CAST_USER_ADDR_T(linkdata
), linkdatalen
);
2971 nfsm_mtouio(auio
, linkdatalen
);
2973 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2974 VATTR_SET(vap
, va_mode
, fxdr_unsigned(u_short
, sp
->sa_mode
));
2976 *(linkdata
+ linkdatalen
) = '\0';
2983 * If the credentials were mapped, we should
2984 * map the same values in the attributes.
2986 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
2988 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
2989 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
2990 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
2992 VATTR_SET(vap
, va_type
, VLNK
);
2993 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
2994 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
2996 /* authorize before creating */
2997 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_FILE
, &context
, nxo
, 0);
2999 /* validate given attributes */
3001 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3002 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
3004 * Most NFS servers just ignore the UID/GID attributes, so we
3005 * try ignoring them if that'll help the request succeed.
3007 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3008 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3009 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3013 error
= VNOP_SYMLINK(dvp
, &vp
, &nd
.ni_cnd
, vap
, linkdata
, &context
);
3017 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
3018 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| FOLLOW
);
3019 nd
.ni_cnd
.cn_flags
|= (NOFOLLOW
| LOCKLEAF
);
3020 nd
.ni_cnd
.cn_context
= &context
;
3021 nd
.ni_startdir
= dvp
;
3023 error
= lookup(&nd
);
3028 error
= nfsrv_vptofh(nx
, !v3
, NULL
, vp
, &context
, &nfh
);
3030 nfsm_srv_vattr_init(&postat
, v3
);
3031 error
= vnode_getattr(vp
, &postat
, &context
);
3037 * nameidone has to happen before we vnode_put(dvp)
3038 * since it may need to release the fs_nodelock on the dvp
3041 nd
.ni_cnd
.cn_nameiop
= 0;
3048 FREE(linkdata
, M_TEMP
);
3050 nfsm_srv_vattr_init(&diraft
, v3
);
3051 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
3054 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
3057 nfsm_srvpostop_fh(&nfh
);
3058 nfsm_srvpostop_attr(0, &postat
);
3060 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3064 if (nd
.ni_cnd
.cn_nameiop
) {
3066 * nameidone has to happen before we vnode_put(dvp)
3067 * since it may need to release the fs_nodelock on the dvp
3078 FREE(linkdata
, M_TEMP
);
3086 nfsrv_mkdir(nfsd
, slp
, procp
, mrq
)
3087 struct nfsrv_descript
*nfsd
;
3088 struct nfssvc_sock
*slp
;
3092 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3093 mbuf_t nam
= nfsd
->nd_nam
;
3094 caddr_t dpos
= nfsd
->nd_dpos
;
3095 struct vnode_attr dirfor
, diraft
, postat
;
3096 struct vnode_attr va
;
3097 struct vnode_attr
*vap
= &va
;
3098 struct nfs_fattr
*fp
;
3099 struct nameidata nd
;
3105 int dirfor_ret
= 1, diraft_ret
= 1;
3106 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3108 mbuf_t mb
, mb2
, mreq
;
3109 vnode_t vp
, dvp
, dirp
= NULL
;
3110 struct nfs_filehandle nfh
;
3111 struct nfs_export
*nx
;
3112 struct nfs_export_options
*nxo
;
3113 struct vfs_context context
;
3115 kauth_acl_t xacl
= NULL
;
3117 context
.vc_proc
= procp
;
3118 context
.vc_ucred
= nfsd
->nd_cr
;
3121 * Save the original credential UID in case they are
3122 * mapped and we need to map the IDs in the attributes.
3124 saved_uid
= kauth_cred_getuid(nfsd
->nd_cr
);
3126 nd
.ni_cnd
.cn_nameiop
= 0;
3128 nfsm_srvmtofh(&nfh
);
3129 nfsm_srvnamesiz(len
, v3
);
3131 nd
.ni_cnd
.cn_nameiop
= CREATE
;
3132 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
3133 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
3135 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
3138 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
3139 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
3146 nd
.ni_cnd
.cn_nameiop
= 0;
3147 nfsm_reply(NFSX_WCCDATA(v3
));
3148 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3160 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
3161 VATTR_SET(vap
, va_mode
, nfstov_mode(*tl
++));
3163 VATTR_SET(vap
, va_type
, VDIR
);
3167 * nameidone has to happen before we vnode_put(dvp)
3168 * since it may need to release the fs_nodelock on the dvp
3179 * If the credentials were mapped, we should
3180 * map the same values in the attributes.
3182 if ((vap
->va_uid
== saved_uid
) && (kauth_cred_getuid(nfsd
->nd_cr
) != saved_uid
)) {
3184 VATTR_SET(vap
, va_uid
, kauth_cred_getuid(nfsd
->nd_cr
));
3185 if (kauth_cred_ismember_gid(nfsd
->nd_cr
, vap
->va_gid
, &ismember
) || !ismember
)
3186 VATTR_SET(vap
, va_gid
, kauth_cred_getgid(nfsd
->nd_cr
));
3189 error
= nfsrv_authorize(dvp
, NULL
, KAUTH_VNODE_ADD_SUBDIRECTORY
, &context
, nxo
, 0);
3191 /* construct ACL and handle inheritance */
3193 error
= kauth_acl_inherit(dvp
,
3199 if (!error
&& xacl
!= NULL
)
3200 VATTR_SET(vap
, va_acl
, xacl
);
3202 VATTR_CLEAR_ACTIVE(vap
, va_data_size
);
3203 VATTR_CLEAR_ACTIVE(vap
, va_access_time
);
3205 /* validate new-file security information */
3207 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3208 if (error
&& (VATTR_IS_ACTIVE(vap
, va_uid
) || VATTR_IS_ACTIVE(vap
, va_gid
))) {
3210 * Most NFS servers just ignore the UID/GID attributes, so we
3211 * try ignoring them if that'll help the request succeed.
3213 VATTR_CLEAR_ACTIVE(vap
, va_uid
);
3214 VATTR_CLEAR_ACTIVE(vap
, va_gid
);
3215 error
= vnode_authattr_new(dvp
, vap
, 0, &context
);
3220 error
= VNOP_MKDIR(dvp
, &vp
, &nd
.ni_cnd
, vap
, &context
);
3222 if (!error
&& !VATTR_ALL_SUPPORTED(vap
))
3224 * If some of the requested attributes weren't handled by the VNOP,
3225 * use our fallback code.
3227 error
= vnode_setattr_fallback(vp
, vap
, &context
);
3230 kauth_acl_free(xacl
);
3233 error
= nfsrv_vptofh(nx
, !v3
, NULL
, vp
, &context
, &nfh
);
3235 nfsm_srv_vattr_init(&postat
, v3
);
3236 error
= vnode_getattr(vp
, &postat
, &context
);
3242 * nameidone has to happen before we vnode_put(dvp)
3243 * since it may need to release the fs_nodelock on the dvp
3249 nd
.ni_cnd
.cn_nameiop
= 0;
3252 nfsm_srv_vattr_init(&diraft
, v3
);
3253 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
3256 nfsm_reply(NFSX_SRVFH(v3
, &nfh
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
3259 nfsm_srvpostop_fh(&nfh
);
3260 nfsm_srvpostop_attr(0, &postat
);
3262 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3264 nfsm_srvfhtom(&nfh
, v3
);
3265 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
3266 nfsm_srvfillattr(&postat
, fp
);
3270 if (nd
.ni_cnd
.cn_nameiop
) {
3272 * nameidone has to happen before we vnode_put(dvp)
3273 * since it may need to release the fs_nodelock on the dvp
3289 nfsrv_rmdir(nfsd
, slp
, procp
, mrq
)
3290 struct nfsrv_descript
*nfsd
;
3291 struct nfssvc_sock
*slp
;
3295 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3296 mbuf_t nam
= nfsd
->nd_nam
;
3297 caddr_t dpos
= nfsd
->nd_dpos
;
3302 int dirfor_ret
= 1, diraft_ret
= 1;
3303 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3306 vnode_t vp
, dvp
, dirp
= NULL
;
3307 struct vnode_attr dirfor
, diraft
;
3308 struct nfs_filehandle nfh
;
3309 struct nfs_export
*nx
;
3310 struct nfs_export_options
*nxo
;
3311 struct nameidata nd
;
3312 struct vfs_context context
;
3314 context
.vc_proc
= procp
;
3315 context
.vc_ucred
= nfsd
->nd_cr
;
3318 nfsm_srvmtofh(&nfh
);
3319 nfsm_srvnamesiz(len
, v3
);
3321 nd
.ni_cnd
.cn_nameiop
= DELETE
;
3322 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
3323 error
= nfsm_path_mbuftond(&md
, &dpos
, v3
, FALSE
, &len
, &nd
);
3325 error
= nfs_namei(nfsd
, &context
, &nd
, &nfh
, nam
, FALSE
, &dirp
, &nx
, &nxo
);
3328 nfsm_srv_pre_vattr_init(&dirfor
, v3
);
3329 dirfor_ret
= vnode_getattr(dirp
, &dirfor
, &context
);
3336 nfsm_reply(NFSX_WCCDATA(v3
));
3337 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3345 if (vnode_vtype(vp
) != VDIR
) {
3350 * No rmdir "." please.
3357 * The root of a mounted filesystem cannot be deleted.
3359 if (vnode_isvroot(vp
))
3362 error
= nfsrv_authorize(vp
, dvp
, KAUTH_VNODE_DELETE
, &context
, nxo
, 0);
3364 error
= VNOP_RMDIR(dvp
, vp
, &nd
.ni_cnd
, &context
);
3367 * nameidone has to happen before we vnode_put(dvp)
3368 * since it may need to release the fs_nodelock on the dvp
3376 nfsm_srv_vattr_init(&diraft
, v3
);
3377 diraft_ret
= vnode_getattr(dirp
, &diraft
, &context
);
3380 nfsm_reply(NFSX_WCCDATA(v3
));
3382 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
3390 * nfs readdir service
3391 * - mallocs what it thinks is enough to read
3392 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
3393 * - calls VNOP_READDIR()
3394 * - loops around building the reply
3395 * if the output generated exceeds count break out of loop
3396 * The nfsm_clget macro is used here so that the reply will be packed
3397 * tightly in mbuf clusters.
3398 * - it only knows that it has encountered eof when the VNOP_READDIR()
3400 * - as such one readdir rpc will return eof false although you are there
3401 * and then the next will return eof
3402 * - it trims out records with d_fileno == 0
3403 * this doesn't matter for Unix clients, but they might confuse clients
3405 * NB: It is tempting to set eof to true if the VNOP_READDIR() reads less
3406 * than requested, but this may not apply to all filesystems. For
3407 * example, client NFS does not { although it is never remote mounted
3409 * The alternate call nfsrv_readdirplus() does lookups as well.
3410 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
3411 * are supposed to cover. For readdir, the count is the total number of
3412 * bytes included in everything from the directory's postopattr through
3413 * the EOF flag. For readdirplus, the maxcount is the same, and the
3414 * dircount includes all that except for the entry attributes and handles.
3418 nfsrv_readdir(nfsd
, slp
, procp
, mrq
)
3419 struct nfsrv_descript
*nfsd
;
3420 struct nfssvc_sock
*slp
;
3424 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3425 mbuf_t nam
= nfsd
->nd_nam
;
3426 caddr_t dpos
= nfsd
->nd_dpos
;
3429 struct direntry
*dp
;
3434 mbuf_t mb
, mb2
, mreq
, mp2
;
3435 char *cpos
, *cend
, *cp2
, *rbuf
;
3437 struct vnode_attr at
;
3438 struct nfs_filehandle nfh
;
3439 struct nfs_export
*nx
;
3440 struct nfs_export_options
*nxo
;
3442 char uio_buf
[ UIO_SIZEOF(1) ];
3443 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
3444 int siz
, count
, fullsiz
, eofflag
, nentries
= 0;
3445 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3446 u_quad_t off
, toff
, verf
;
3449 struct vfs_context context
;
3451 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
3453 nfsm_srvmtofh(&nfh
);
3455 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
3456 fxdr_hyper(tl
, &toff
);
3458 fxdr_hyper(tl
, &verf
);
3461 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3462 toff
= fxdr_unsigned(u_quad_t
, *tl
++);
3465 count
= fxdr_unsigned(int, *tl
);
3466 siz
= ((count
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
3467 xfer
= NFS_SRVMAXDATA(nfsd
);
3471 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
3472 nfsm_reply(NFSX_UNSIGNED
);
3473 nfsm_srvpostop_attr(getret
, &at
);
3476 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
3478 nfsm_reply(NFSX_UNSIGNED
);
3479 nfsm_srvpostop_attr(getret
, &at
);
3482 context
.vc_proc
= procp
;
3483 context
.vc_ucred
= nfsd
->nd_cr
;
3484 if (!v3
|| (nxo
->nxo_flags
& NX_32BITCLIENTS
))
3485 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
3487 nfsm_srv_vattr_init(&at
, v3
);
3488 error
= getret
= vnode_getattr(vp
, &at
, &context
);
3489 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
3490 error
= NFSERR_BAD_COOKIE
;
3493 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, &context
, nxo
, 0);
3496 nfsm_reply(NFSX_POSTOPATTR(v3
));
3497 nfsm_srvpostop_attr(getret
, &at
);
3500 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
3504 nfsm_reply(NFSX_POSTOPATTR(v3
));
3505 nfsm_srvpostop_attr(getret
, &at
);
3508 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3509 &uio_buf
[0], sizeof(uio_buf
));
3514 nfsm_reply(NFSX_POSTOPATTR(v3
));
3515 nfsm_srvpostop_attr(getret
, &at
);
3519 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
3520 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
3523 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, &context
);
3524 off
= uio_offset(auio
);
3527 nfsm_srv_vattr_init(&at
, v3
);
3528 getret
= vnode_getattr(vp
, &at
, &context
);
3535 nfsm_reply(NFSX_POSTOPATTR(v3
));
3536 nfsm_srvpostop_attr(getret
, &at
);
3539 if (uio_resid(auio
) != 0) {
3540 // LP64todo - fix this
3541 siz
-= uio_resid(auio
);
3544 * If nothing read, return eof
3549 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) +
3552 nfsm_srvpostop_attr(getret
, &at
);
3553 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
3554 txdr_hyper(&at
.va_filerev
, tl
);
3557 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3566 * Check for degenerate cases of nothing useful read.
3567 * If so go try again
3571 dp
= (struct direntry
*)cpos
;
3572 while (dp
->d_fileno
== 0 && cpos
< cend
&& nentries
> 0) {
3573 cpos
+= dp
->d_reclen
;
3574 dp
= (struct direntry
*)cpos
;
3577 if (cpos
>= cend
|| nentries
== 0) {
3584 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) + siz
);
3586 len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3587 nfsm_srvpostop_attr(getret
, &at
);
3588 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3589 txdr_hyper(&at
.va_filerev
, tl
);
3591 len
= 2 * NFSX_UNSIGNED
;
3594 be
= bp
+ mbuf_trailingspace(mp
);
3596 /* Loop through the records and build reply */
3597 while (cpos
< cend
&& nentries
> 0) {
3598 if (dp
->d_fileno
!= 0) {
3599 nlen
= dp
->d_namlen
;
3600 if (!v3
&& (nlen
> NFS_MAXNAMLEN
))
3601 nlen
= NFS_MAXNAMLEN
;
3602 rem
= nfsm_rndup(nlen
)-nlen
;
3603 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
3605 len
+= 2 * NFSX_UNSIGNED
;
3611 * Build the directory record xdr from
3612 * the direntry entry.
3616 bp
+= NFSX_UNSIGNED
;
3619 txdr_hyper(&dp
->d_fileno
, &tquad
);
3620 *tl
= tquad
.nfsuquad
[0];
3621 bp
+= NFSX_UNSIGNED
;
3623 *tl
= tquad
.nfsuquad
[1];
3624 bp
+= NFSX_UNSIGNED
;
3626 *tl
= txdr_unsigned(dp
->d_fileno
);
3627 bp
+= NFSX_UNSIGNED
;
3630 *tl
= txdr_unsigned(nlen
);
3631 bp
+= NFSX_UNSIGNED
;
3633 /* And loop around copying the name */
3642 bcopy(cp
, bp
, tsiz
);
3648 /* And null pad to a long boundary */
3649 for (i
= 0; i
< rem
; i
++)
3652 /* Finish off the record with the cookie */
3655 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
3656 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
3657 txdr_hyper(&dp
->d_seekoff
, &tquad
);
3658 *tl
= tquad
.nfsuquad
[0];
3659 bp
+= NFSX_UNSIGNED
;
3661 *tl
= tquad
.nfsuquad
[1];
3662 bp
+= NFSX_UNSIGNED
;
3664 *tl
= txdr_unsigned(dp
->d_seekoff
);
3665 bp
+= NFSX_UNSIGNED
;
3668 cpos
+= dp
->d_reclen
;
3669 dp
= (struct direntry
*)cpos
;
3674 bp
+= NFSX_UNSIGNED
;
3680 bp
+= NFSX_UNSIGNED
;
3683 mbuf_setlen(mp
, bp
- (char*)mbuf_data(mp
));
3685 mbuf_setlen(mp
, mbuf_len(mp
) + (bp
- bpos
));
3694 u_long fl_fattr
[NFSX_V3FATTR
/ sizeof (u_long
)];
3697 u_long fl_nfh
[NFSX_V3FHMAX
/ sizeof (u_long
)];
3701 nfsrv_readdirplus(nfsd
, slp
, procp
, mrq
)
3702 struct nfsrv_descript
*nfsd
;
3703 struct nfssvc_sock
*slp
;
3707 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
3708 mbuf_t nam
= nfsd
->nd_nam
;
3709 caddr_t dpos
= nfsd
->nd_dpos
;
3712 struct direntry
*dp
;
3717 mbuf_t mb
, mb2
, mreq
, mp2
;
3718 char *cpos
, *cend
, *cp2
, *rbuf
;
3721 struct nfs_filehandle dnfh
, *nfhp
= (struct nfs_filehandle
*)&fl
.fl_fhsize
;
3723 struct nfs_export
*nx
;
3724 struct nfs_export_options
*nxo
;
3726 char uio_buf
[ UIO_SIZEOF(1) ];
3727 struct vnode_attr va
, at
, *vap
= &va
;
3728 struct nfs_fattr
*fp
;
3729 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
3730 int siz
, count
, fullsiz
, eofflag
, dirlen
, nentries
= 0, isdotdot
;
3731 u_quad_t off
, toff
, verf
;
3734 struct vfs_context context
;
3736 vnopflag
= VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
;
3738 nfsm_srvmtofh(&dnfh
);
3739 nfsm_dissect(tl
, u_long
*, 6 * NFSX_UNSIGNED
);
3740 fxdr_hyper(tl
, &toff
);
3742 fxdr_hyper(tl
, &verf
);
3744 siz
= fxdr_unsigned(int, *tl
++);
3745 count
= fxdr_unsigned(int, *tl
);
3747 siz
= ((siz
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
3748 xfer
= NFS_SRVMAXDATA(nfsd
);
3752 if ((error
= nfsrv_fhtovp(&dnfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
3753 nfsm_reply(NFSX_UNSIGNED
);
3754 nfsm_srvpostop_attr(getret
, &at
);
3757 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
3759 nfsm_reply(NFSX_UNSIGNED
);
3760 nfsm_srvpostop_attr(getret
, &at
);
3763 context
.vc_proc
= procp
;
3764 context
.vc_ucred
= nfsd
->nd_cr
;
3765 if (nxo
->nxo_flags
& NX_32BITCLIENTS
)
3766 vnopflag
|= VNODE_READDIR_SEEKOFF32
;
3767 nfsm_srv_vattr_init(&at
, 1);
3768 error
= getret
= vnode_getattr(vp
, &at
, &context
);
3769 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
3770 error
= NFSERR_BAD_COOKIE
;
3772 error
= nfsrv_authorize(vp
, NULL
, KAUTH_VNODE_LIST_DIRECTORY
, &context
, nxo
, 0);
3776 nfsm_reply(NFSX_V3POSTOPATTR
);
3777 nfsm_srvpostop_attr(getret
, &at
);
3780 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
3785 nfsm_reply(NFSX_V3POSTOPATTR
);
3786 nfsm_srvpostop_attr(getret
, &at
);
3789 auio
= uio_createwithbuffer(1, 0, UIO_SYSSPACE
, UIO_READ
,
3790 &uio_buf
[0], sizeof(uio_buf
));
3796 nfsm_reply(NFSX_V3POSTOPATTR
);
3797 nfsm_srvpostop_attr(getret
, &at
);
3801 uio_reset(auio
, off
, UIO_SYSSPACE
, UIO_READ
);
3802 uio_addiov(auio
, CAST_USER_ADDR_T(rbuf
), fullsiz
);
3804 error
= VNOP_READDIR(vp
, auio
, vnopflag
, &eofflag
, &nentries
, &context
);
3805 off
= uio_offset(auio
);
3806 nfsm_srv_vattr_init(&at
, 1);
3807 getret
= vnode_getattr(vp
, &at
, &context
);
3815 nfsm_reply(NFSX_V3POSTOPATTR
);
3816 nfsm_srvpostop_attr(getret
, &at
);
3819 if (uio_resid(auio
) != 0) {
3820 // LP64todo - fix this
3821 siz
-= uio_resid(auio
);
3824 * If nothing read, return eof
3830 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+
3832 nfsm_srvpostop_attr(getret
, &at
);
3833 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
3834 txdr_hyper(&at
.va_filerev
, tl
);
3844 * Check for degenerate cases of nothing useful read.
3845 * If so go try again
3849 dp
= (struct direntry
*)cpos
;
3850 while (dp
->d_fileno
== 0 && cpos
< cend
&& nentries
> 0) {
3851 cpos
+= dp
->d_reclen
;
3852 dp
= (struct direntry
*)cpos
;
3855 if (cpos
>= cend
|| nentries
== 0) {
3862 * Probe one of the directory entries to see if the filesystem
3865 if ((error
= VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, &context
))) {
3866 if (error
== ENOTSUP
) /* let others get passed back */
3867 error
= NFSERR_NOTSUPP
;
3871 nfsm_reply(NFSX_V3POSTOPATTR
);
3872 nfsm_srvpostop_attr(getret
, &at
);
3877 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3879 nfsm_srvpostop_attr(getret
, &at
);
3880 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3881 txdr_hyper(&at
.va_filerev
, tl
);
3884 be
= bp
+ mbuf_trailingspace(mp
);
3886 /* Loop through the records and build reply */
3887 while (cpos
< cend
&& nentries
> 0) {
3888 if (dp
->d_fileno
!= 0) {
3889 nlen
= dp
->d_namlen
;
3890 rem
= nfsm_rndup(nlen
)-nlen
;
3893 * Got to get the vnode for lookup per entry.
3895 if (VFS_VGET(vnode_mount(vp
), (ino64_t
)dp
->d_fileno
, &nvp
, &context
))
3897 isdotdot
= ((dp
->d_namlen
== 2) &&
3898 (dp
->d_name
[0] == '.') && (dp
->d_name
[1] == '.'));
3899 if (nfsrv_vptofh(nx
, 0, (isdotdot
? &dnfh
: NULL
), nvp
, &context
, nfhp
)) {
3900 // XXX file handle is optional, so we should be able to
3901 // XXX return this entry without the file handle
3905 nfsm_srv_vattr_init(vap
, 1);
3906 if (vnode_getattr(nvp
, vap
, &context
)) {
3907 // XXX attributes are optional, so we should be able to
3908 // XXX return this entry without the attributes
3915 * If either the dircount or maxcount will be
3916 * exceeded, get out now. Both of these lengths
3917 * are calculated conservatively, including all
3920 len
+= (8 * NFSX_UNSIGNED
+ nlen
+ rem
+ nfhp
->nfh_len
+
3922 dirlen
+= (6 * NFSX_UNSIGNED
+ nlen
+ rem
);
3923 if (len
> count
|| dirlen
> fullsiz
) {
3929 * Build the directory record xdr from
3930 * the direntry entry.
3932 fp
= (struct nfs_fattr
*)&fl
.fl_fattr
;
3933 nfsm_srvfillattr(vap
, fp
);
3934 fhsize
= nfhp
->nfh_len
;
3935 fl
.fl_fhsize
= txdr_unsigned(fhsize
);
3936 fl
.fl_fhok
= nfs_true
;
3937 fl
.fl_postopok
= nfs_true
;
3938 if (vnopflag
& VNODE_READDIR_SEEKOFF32
)
3939 dp
->d_seekoff
&= 0x00000000ffffffffULL
;
3940 txdr_hyper(&dp
->d_seekoff
, &fl
.fl_off
);
3944 bp
+= NFSX_UNSIGNED
;
3947 txdr_hyper(&dp
->d_fileno
, &tquad
);
3948 *tl
= tquad
.nfsuquad
[0];
3949 bp
+= NFSX_UNSIGNED
;
3951 *tl
= tquad
.nfsuquad
[1];
3952 bp
+= NFSX_UNSIGNED
;
3955 *tl
= txdr_unsigned(nlen
);
3956 bp
+= NFSX_UNSIGNED
;
3958 /* And loop around copying the name */
3963 if ((bp
+ xfer
) > be
)
3967 bcopy(cp
, bp
, tsiz
);
3973 /* And null pad to a long boundary */
3974 for (i
= 0; i
< rem
; i
++)
3978 * Now copy the flrep structure out.
3980 xfer
= sizeof(struct flrep
) - sizeof(fl
.fl_nfh
) + fhsize
;
3984 if ((bp
+ xfer
) > be
)
3988 bcopy(cp
, bp
, tsiz
);
3996 cpos
+= dp
->d_reclen
;
3997 dp
= (struct direntry
*)cpos
;
4004 bp
+= NFSX_UNSIGNED
;
4010 bp
+= NFSX_UNSIGNED
;
4013 mbuf_setlen(mp
, bp
- (char*)mbuf_data(mp
));
4015 mbuf_setlen(mp
, mbuf_len(mp
) + (bp
- bpos
));
4024 * nfs commit service
4027 nfsrv_commit(nfsd
, slp
, procp
, mrq
)
4028 struct nfsrv_descript
*nfsd
;
4029 struct nfssvc_sock
*slp
;
4033 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4034 mbuf_t nam
= nfsd
->nd_nam
;
4035 caddr_t dpos
= nfsd
->nd_dpos
;
4036 struct vnode_attr bfor
, aft
;
4038 struct nfs_filehandle nfh
;
4039 struct nfs_export
*nx
;
4040 struct nfs_export_options
*nxo
;
4044 int error
= 0, for_ret
= 1, aft_ret
= 1, count
;
4046 mbuf_t mb
, mb2
, mreq
;
4048 struct vfs_context context
;
4050 nfsm_srvmtofh(&nfh
);
4051 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
4054 * XXX At this time VNOP_FSYNC() does not accept offset and byte
4055 * count parameters, so these arguments are useless (someday maybe).
4057 fxdr_hyper(tl
, &off
);
4059 count
= fxdr_unsigned(int, *tl
);
4060 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4061 nfsm_reply(2 * NFSX_UNSIGNED
);
4062 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
4065 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4067 nfsm_reply(2 * NFSX_UNSIGNED
);
4068 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
4071 context
.vc_proc
= procp
;
4072 context
.vc_ucred
= nfsd
->nd_cr
;
4074 nfsm_srv_pre_vattr_init(&bfor
, 1);
4075 for_ret
= vnode_getattr(vp
, &bfor
, &context
);
4076 error
= VNOP_FSYNC(vp
, MNT_WAIT
, &context
);
4077 nfsm_srv_vattr_init(&aft
, 1);
4078 aft_ret
= vnode_getattr(vp
, &aft
, &context
);
4080 nfsm_reply(NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
4081 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
4083 nfsm_build(tl
, u_long
*, NFSX_V3WRITEVERF
);
4084 *tl
++ = txdr_unsigned(boottime_sec());
4085 *tl
= txdr_unsigned(0);
4093 * nfs statfs service
4096 nfsrv_statfs(nfsd
, slp
, procp
, mrq
)
4097 struct nfsrv_descript
*nfsd
;
4098 struct nfssvc_sock
*slp
;
4102 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4103 mbuf_t nam
= nfsd
->nd_nam
;
4104 caddr_t dpos
= nfsd
->nd_dpos
;
4106 struct nfs_statfs
*sfp
;
4110 int error
= 0, getret
= 1;
4111 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
4113 mbuf_t mb
, mb2
, mreq
;
4115 struct vnode_attr at
;
4116 struct nfs_filehandle nfh
;
4117 struct nfs_export
*nx
;
4118 struct nfs_export_options
*nxo
;
4121 struct vfs_context context
;
4123 nfsm_srvmtofh(&nfh
);
4124 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4125 nfsm_reply(NFSX_UNSIGNED
);
4126 nfsm_srvpostop_attr(getret
, &at
);
4129 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4131 nfsm_reply(NFSX_UNSIGNED
);
4132 nfsm_srvpostop_attr(getret
, &at
);
4135 context
.vc_proc
= procp
;
4136 context
.vc_ucred
= nfsd
->nd_cr
;
4139 VFSATTR_WANTED(&va
, f_blocks
);
4140 VFSATTR_WANTED(&va
, f_bavail
);
4141 VFSATTR_WANTED(&va
, f_files
);
4142 VFSATTR_WANTED(&va
, f_ffree
);
4143 error
= vfs_getattr(vnode_mount(vp
), &va
, &context
);
4144 blksize
= vnode_mount(vp
)->mnt_vfsstat
.f_bsize
;
4145 nfsm_srv_vattr_init(&at
, v3
);
4146 getret
= vnode_getattr(vp
, &at
, &context
);
4148 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_STATFS(v3
));
4150 nfsm_srvpostop_attr(getret
, &at
);
4153 nfsm_build(sfp
, struct nfs_statfs
*, NFSX_STATFS(v3
));
4155 tval
= (u_quad_t
)(va
.f_blocks
* blksize
);
4156 txdr_hyper(&tval
, &sfp
->sf_tbytes
);
4157 tval
= (u_quad_t
)(va
.f_bfree
* blksize
);
4158 txdr_hyper(&tval
, &sfp
->sf_fbytes
);
4159 tval
= (u_quad_t
)(va
.f_bavail
* blksize
);
4160 txdr_hyper(&tval
, &sfp
->sf_abytes
);
4161 txdr_hyper(&va
.f_files
, &sfp
->sf_tfiles
);
4162 txdr_hyper(&va
.f_ffree
, &sfp
->sf_ffiles
);
4163 txdr_hyper(&va
.f_ffree
, &sfp
->sf_afiles
);
4164 sfp
->sf_invarsec
= 0;
4166 sfp
->sf_tsize
= txdr_unsigned(NFS_V2MAXDATA
);
4167 sfp
->sf_bsize
= txdr_unsigned((unsigned)blksize
);
4168 sfp
->sf_blocks
= txdr_unsigned((unsigned)va
.f_blocks
);
4169 sfp
->sf_bfree
= txdr_unsigned((unsigned)va
.f_bfree
);
4170 sfp
->sf_bavail
= txdr_unsigned((unsigned)va
.f_bavail
);
4177 * nfs fsinfo service
4180 nfsrv_fsinfo(nfsd
, slp
, procp
, mrq
)
4181 struct nfsrv_descript
*nfsd
;
4182 struct nfssvc_sock
*slp
;
4186 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4187 mbuf_t nam
= nfsd
->nd_nam
;
4188 caddr_t dpos
= nfsd
->nd_dpos
;
4190 struct nfsv3_fsinfo
*sip
;
4193 int error
= 0, getret
= 1, prefsize
, maxsize
;
4195 mbuf_t mb
, mb2
, mreq
;
4197 struct vnode_attr at
;
4198 struct nfs_filehandle nfh
;
4199 struct nfs_export
*nx
;
4200 struct nfs_export_options
*nxo
;
4201 struct vfs_context context
;
4203 nfsm_srvmtofh(&nfh
);
4204 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4205 nfsm_reply(NFSX_UNSIGNED
);
4206 nfsm_srvpostop_attr(getret
, &at
);
4209 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4211 nfsm_reply(NFSX_UNSIGNED
);
4212 nfsm_srvpostop_attr(getret
, &at
);
4215 context
.vc_proc
= procp
;
4216 context
.vc_ucred
= nfsd
->nd_cr
;
4218 nfsm_srv_vattr_init(&at
, 1);
4219 getret
= vnode_getattr(vp
, &at
, &context
);
4221 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
4222 nfsm_srvpostop_attr(getret
, &at
);
4223 nfsm_build(sip
, struct nfsv3_fsinfo
*, NFSX_V3FSINFO
);
4227 * There should be file system VFS OP(s) to get this information.
4228 * For now, assume our usual NFS defaults.
4230 if (slp
->ns_sotype
== SOCK_DGRAM
) {
4231 maxsize
= NFS_MAXDGRAMDATA
;
4232 prefsize
= NFS_PREFDGRAMDATA
;
4234 maxsize
= prefsize
= NFS_MAXDATA
;
4235 sip
->fs_rtmax
= txdr_unsigned(maxsize
);
4236 sip
->fs_rtpref
= txdr_unsigned(prefsize
);
4237 sip
->fs_rtmult
= txdr_unsigned(NFS_FABLKSIZE
);
4238 sip
->fs_wtmax
= txdr_unsigned(maxsize
);
4239 sip
->fs_wtpref
= txdr_unsigned(prefsize
);
4240 sip
->fs_wtmult
= txdr_unsigned(NFS_FABLKSIZE
);
4241 sip
->fs_dtpref
= txdr_unsigned(prefsize
);
4242 sip
->fs_maxfilesize
.nfsuquad
[0] = 0xffffffff;
4243 sip
->fs_maxfilesize
.nfsuquad
[1] = 0xffffffff;
4244 sip
->fs_timedelta
.nfsv3_sec
= 0;
4245 sip
->fs_timedelta
.nfsv3_nsec
= txdr_unsigned(1);
4246 sip
->fs_properties
= txdr_unsigned(NFSV3FSINFO_LINK
|
4247 NFSV3FSINFO_SYMLINK
| NFSV3FSINFO_HOMOGENEOUS
|
4248 NFSV3FSINFO_CANSETTIME
);
4254 * nfs pathconf service
4257 nfsrv_pathconf(nfsd
, slp
, procp
, mrq
)
4258 struct nfsrv_descript
*nfsd
;
4259 struct nfssvc_sock
*slp
;
4263 mbuf_t mrep
= nfsd
->nd_mrep
, md
= nfsd
->nd_md
;
4264 mbuf_t nam
= nfsd
->nd_nam
;
4265 caddr_t dpos
= nfsd
->nd_dpos
;
4267 struct nfsv3_pathconf
*pc
;
4270 int error
= 0, getret
= 1, linkmax
, namemax
;
4271 int chownres
, notrunc
, case_sensitive
, case_preserving
;
4273 mbuf_t mb
, mb2
, mreq
;
4275 struct vnode_attr at
;
4276 struct nfs_filehandle nfh
;
4277 struct nfs_export
*nx
;
4278 struct nfs_export_options
*nxo
;
4279 struct vfs_context context
;
4281 nfsm_srvmtofh(&nfh
);
4282 if ((error
= nfsrv_fhtovp(&nfh
, nam
, TRUE
, &vp
, &nx
, &nxo
))) {
4283 nfsm_reply(NFSX_UNSIGNED
);
4284 nfsm_srvpostop_attr(getret
, &at
);
4287 if ((error
= nfsrv_credcheck(nfsd
, nx
, nxo
))) {
4289 nfsm_reply(NFSX_UNSIGNED
);
4290 nfsm_srvpostop_attr(getret
, &at
);
4293 context
.vc_proc
= procp
;
4294 context
.vc_ucred
= nfsd
->nd_cr
;
4296 error
= VNOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
, &context
);
4298 error
= VNOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
, &context
);
4300 error
= VNOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
, &context
);
4302 error
= VNOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
, &context
);
4304 error
= VNOP_PATHCONF(vp
, _PC_CASE_SENSITIVE
, &case_sensitive
, &context
);
4306 error
= VNOP_PATHCONF(vp
, _PC_CASE_PRESERVING
, &case_preserving
, &context
);
4307 nfsm_srv_vattr_init(&at
, 1);
4308 getret
= vnode_getattr(vp
, &at
, &context
);
4310 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
4311 nfsm_srvpostop_attr(getret
, &at
);
4314 nfsm_build(pc
, struct nfsv3_pathconf
*, NFSX_V3PATHCONF
);
4316 pc
->pc_linkmax
= txdr_unsigned(linkmax
);
4317 pc
->pc_namemax
= txdr_unsigned(namemax
);
4318 pc
->pc_notrunc
= txdr_unsigned(notrunc
);
4319 pc
->pc_chownrestricted
= txdr_unsigned(chownres
);
4320 pc
->pc_caseinsensitive
= txdr_unsigned(!case_sensitive
);
4321 pc
->pc_casepreserving
= txdr_unsigned(case_preserving
);
4328 * Null operation, used by clients to ping server
4333 struct nfsrv_descript
*nfsd
,
4334 struct nfssvc_sock
*slp
,
4335 __unused proc_t procp
,
4338 mbuf_t mrep
= nfsd
->nd_mrep
;
4340 int error
= NFSERR_RETVOID
;
4349 * No operation, used for obsolete procedures
4354 struct nfsrv_descript
*nfsd
,
4355 struct nfssvc_sock
*slp
,
4356 __unused proc_t procp
,
4359 mbuf_t mrep
= nfsd
->nd_mrep
;
4364 if (nfsd
->nd_repstat
)
4365 error
= nfsd
->nd_repstat
;
4367 error
= EPROCUNAVAIL
;
4374 * Perform access checking for vnodes obtained from file handles that would
4375 * refer to files already opened by a Unix client. You cannot just use
4376 * vnode_authorize() for two reasons.
4377 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4378 * 2 - The owner is to be given access irrespective of mode bits so that
4379 * processes that chmod after opening a file don't break. I don't like
4380 * this because it opens a security hole, but since the nfs server opens
4381 * a security hole the size of a barn door anyhow, what the heck.
4383 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, vnode_authorize()
4384 * will return EPERM instead of EACCESS. EPERM is always an error.
4391 kauth_action_t action
,
4392 vfs_context_t context
,
4393 struct nfs_export_options
*nxo
,
4396 struct vnode_attr vattr
;
4399 if (action
& KAUTH_VNODE_WRITE_RIGHTS
) {
4401 * Disallow write attempts on read-only exports;
4402 * unless the file is a socket or a block or character
4403 * device resident on the file system.
4405 if (nxo
->nxo_flags
& NX_READONLY
) {
4406 switch (vnode_vtype(vp
)) {
4407 case VREG
: case VDIR
: case VLNK
: case VCPLX
:
4414 error
= vnode_authorize(vp
, dvp
, action
, context
);
4416 * Allow certain operations for the owner (reads and writes
4417 * on files that are already open). Picking up from FreeBSD.
4419 if (override
&& (error
== EACCES
)) {
4421 VATTR_WANTED(&vattr
, va_uid
);
4422 if ((vnode_getattr(vp
, &vattr
, context
) == 0) &&
4423 (kauth_cred_getuid(vfs_context_ucred(context
)) == vattr
.va_uid
))
4428 #endif /* NFS_NOSERVER */