]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_serv.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
27 * Copyright (c) 1989, 1993
28 * The Regents of the University of California. All rights reserved.
30 * This code is derived from software contributed to Berkeley by
31 * Rick Macklem at The University of Guelph.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * @(#)nfs_serv.c 8.7 (Berkeley) 5/14/95
62 * FreeBSD-Id: nfs_serv.c,v 1.52 1997/10/28 15:59:05 bde Exp $
66 * nfs version 2 and 3 server calls to vnode ops
67 * - these routines generally have 3 phases
68 * 1 - break down and validate rpc request in mbuf list
69 * 2 - do the vnode ops for the request
70 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
71 * 3 - build the rpc reply in an mbuf list
73 * - do not mix the phases, since the nfsm_?? macros can return failures
74 * on a bad rpc or similar and do not do any vrele() or vput()'s
76 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
77 * error number iff error != 0 whereas
78 * returning an error from the server function implies a fatal error
79 * such as a badly constructed rpc request that should be dropped without
81 * For Version 3, nfsm_reply() does not return for the error case, since
82 * most version 3 rpcs return more than the status for error cases.
85 #include <sys/param.h>
86 #include <sys/systm.h>
88 #include <sys/namei.h>
89 #include <sys/unistd.h>
90 #include <sys/malloc.h>
91 #include <sys/vnode.h>
92 #include <sys/mount.h>
93 #include <sys/socket.h>
94 #include <sys/socketvar.h>
96 #include <sys/dirent.h>
98 #include <sys/kernel.h>
99 #include <sys/sysctl.h>
102 #include <ufs/ufs/dir.h>
105 #include <sys/vmparam.h>
106 #include <machine/spl.h>
108 #include <nfs/nfsproto.h>
109 #include <nfs/rpcv2.h>
111 #include <nfs/xdr_subs.h>
112 #include <nfs/nfsm_subs.h>
113 #include <nfs/nqnfs.h>
115 nfstype nfsv3_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFSOCK
,
118 nfstype nfsv2_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFNON
,
121 extern u_long nfs_xdrneg1
;
122 extern u_long nfs_false
, nfs_true
;
123 extern enum vtype nv3tov_type
[8];
124 extern struct nfsstats nfsstats
;
126 int nfsrvw_procrastinate
= NFS_GATHERDELAY
* 1000;
127 int nfsrvw_procrastinate_v3
= 0;
131 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
132 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, async
, CTLFLAG_RW
, &nfs_async
, 0, "");
135 static int nfsrv_access
__P((struct vnode
*,int,struct ucred
*,int,
136 struct proc
*, int));
137 static void nfsrvw_coalesce
__P((struct nfsrv_descript
*,
138 struct nfsrv_descript
*));
141 * nfs v3 access service
144 nfsrv3_access(nfsd
, slp
, procp
, mrq
)
145 struct nfsrv_descript
*nfsd
;
146 struct nfssvc_sock
*slp
;
150 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
151 struct mbuf
*nam
= nfsd
->nd_nam
;
152 caddr_t dpos
= nfsd
->nd_dpos
;
153 struct ucred
*cred
= &nfsd
->nd_cr
;
160 int error
= 0, rdonly
, cache
, getret
;
162 struct mbuf
*mb
, *mreq
, *mb2
;
163 struct vattr vattr
, *vap
= &vattr
;
164 u_long testmode
, nfsmode
;
170 fhp
= &nfh
.fh_generic
;
172 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
173 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
174 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
175 nfsm_reply(NFSX_UNSIGNED
);
176 nfsm_srvpostop_attr(1, (struct vattr
*)0);
179 nfsmode
= fxdr_unsigned(u_long
, *tl
);
180 if ((nfsmode
& NFSV3ACCESS_READ
) &&
181 nfsrv_access(vp
, VREAD
, cred
, rdonly
, procp
, 0))
182 nfsmode
&= ~NFSV3ACCESS_READ
;
183 if (vp
->v_type
== VDIR
)
184 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
|
187 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
);
188 if ((nfsmode
& testmode
) &&
189 nfsrv_access(vp
, VWRITE
, cred
, rdonly
, procp
, 0))
190 nfsmode
&= ~testmode
;
191 if (vp
->v_type
== VDIR
)
192 testmode
= NFSV3ACCESS_LOOKUP
;
194 testmode
= NFSV3ACCESS_EXECUTE
;
195 if ((nfsmode
& testmode
) &&
196 nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 0))
197 nfsmode
&= ~testmode
;
198 getret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
200 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED
);
201 nfsm_srvpostop_attr(getret
, vap
);
202 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
203 *tl
= txdr_unsigned(nfsmode
);
208 * nfs getattr service
211 nfsrv_getattr(nfsd
, slp
, procp
, mrq
)
212 struct nfsrv_descript
*nfsd
;
213 struct nfssvc_sock
*slp
;
217 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
218 struct mbuf
*nam
= nfsd
->nd_nam
;
219 caddr_t dpos
= nfsd
->nd_dpos
;
220 struct ucred
*cred
= &nfsd
->nd_cr
;
221 register struct nfs_fattr
*fp
;
223 register struct vattr
*vap
= &va
;
230 int error
= 0, rdonly
, cache
;
232 struct mbuf
*mb
, *mb2
, *mreq
;
235 fhp
= &nfh
.fh_generic
;
237 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
238 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
242 nqsrv_getl(vp
, ND_READ
);
243 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
245 nfsm_reply(NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
248 nfsm_build(fp
, struct nfs_fattr
*, NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
249 nfsm_srvfillattr(vap
, fp
);
254 * nfs setattr service
257 nfsrv_setattr(nfsd
, slp
, procp
, mrq
)
258 struct nfsrv_descript
*nfsd
;
259 struct nfssvc_sock
*slp
;
263 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
264 struct mbuf
*nam
= nfsd
->nd_nam
;
265 caddr_t dpos
= nfsd
->nd_dpos
;
266 struct ucred
*cred
= &nfsd
->nd_cr
;
267 struct vattr va
, preat
;
268 register struct vattr
*vap
= &va
;
269 register struct nfsv2_sattr
*sp
;
270 register struct nfs_fattr
*fp
;
277 int error
= 0, rdonly
, cache
, preat_ret
= 1, postat_ret
= 1;
278 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), gcheck
= 0;
280 struct mbuf
*mb
, *mb2
, *mreq
;
282 struct timespec guard
;
284 fhp
= &nfh
.fh_generic
;
289 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
290 gcheck
= fxdr_unsigned(int, *tl
);
292 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
293 fxdr_nfsv3time(tl
, &guard
);
296 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
298 * Nah nah nah nah na nah
299 * There is a bug in the Sun client that puts 0xffff in the mode
300 * field of sattr when it should put in 0xffffffff. The u_short
301 * doesn't sign extend.
302 * --> check the low order 2 bytes for 0xffff
304 if ((fxdr_unsigned(int, sp
->sa_mode
) & 0xffff) != 0xffff)
305 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
306 if (sp
->sa_uid
!= nfs_xdrneg1
)
307 vap
->va_uid
= fxdr_unsigned(uid_t
, sp
->sa_uid
);
308 if (sp
->sa_gid
!= nfs_xdrneg1
)
309 vap
->va_gid
= fxdr_unsigned(gid_t
, sp
->sa_gid
);
310 if (sp
->sa_size
!= nfs_xdrneg1
)
311 vap
->va_size
= fxdr_unsigned(u_quad_t
, sp
->sa_size
);
312 if (sp
->sa_atime
.nfsv2_sec
!= nfs_xdrneg1
) {
314 fxdr_nfsv2time(&sp
->sa_atime
, &vap
->va_atime
);
316 vap
->va_atime
.tv_sec
=
317 fxdr_unsigned(long, sp
->sa_atime
.nfsv2_sec
);
318 vap
->va_atime
.tv_nsec
= 0;
321 if (sp
->sa_mtime
.nfsv2_sec
!= nfs_xdrneg1
)
322 fxdr_nfsv2time(&sp
->sa_mtime
, &vap
->va_mtime
);
327 * Now that we have all the fields, lets do it.
329 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
330 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
331 nfsm_reply(2 * NFSX_UNSIGNED
);
332 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
335 nqsrv_getl(vp
, ND_WRITE
);
337 error
= preat_ret
= VOP_GETATTR(vp
, &preat
, cred
, procp
);
338 if (!error
&& gcheck
&&
339 (preat
.va_ctime
.tv_sec
!= guard
.tv_sec
||
340 preat
.va_ctime
.tv_nsec
!= guard
.tv_nsec
))
341 error
= NFSERR_NOT_SYNC
;
344 nfsm_reply(NFSX_WCCDATA(v3
));
345 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
351 * If the size is being changed write acces is required, otherwise
352 * just check for a read only file system.
354 if (vap
->va_size
== ((u_quad_t
)((quad_t
) -1))) {
355 if (rdonly
|| (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
360 if (vp
->v_type
== VDIR
) {
363 } else if ((error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
,
367 error
= VOP_SETATTR(vp
, vap
, cred
, procp
);
368 postat_ret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
373 nfsm_reply(NFSX_WCCORFATTR(v3
));
375 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
378 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
379 nfsm_srvfillattr(vap
, fp
);
388 nfsrv_lookup(nfsd
, slp
, procp
, mrq
)
389 struct nfsrv_descript
*nfsd
;
390 struct nfssvc_sock
*slp
;
394 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
395 struct mbuf
*nam
= nfsd
->nd_nam
;
396 caddr_t dpos
= nfsd
->nd_dpos
;
397 struct ucred
*cred
= &nfsd
->nd_cr
;
398 register struct nfs_fattr
*fp
;
399 struct nameidata nd
, *ndp
= &nd
;
401 struct nameidata ind
;
403 struct vnode
*vp
, *dirp
;
410 int error
= 0, cache
, len
, dirattr_ret
= 1;
411 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), pubflag
;
413 struct mbuf
*mb
, *mb2
, *mreq
;
414 struct vattr va
, dirattr
, *vap
= &va
;
417 fhp
= &nfh
.fh_generic
;
419 nfsm_srvnamesiz(len
);
421 pubflag
= nfs_ispublicfh(fhp
);
423 nd
.ni_cnd
.cn_cred
= cred
;
424 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
425 nd
.ni_cnd
.cn_flags
= LOCKLEAF
| SAVESTART
;
426 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
427 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), pubflag
);
429 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
431 if (!error
&& pubflag
) {
432 if (nd
.ni_vp
->v_type
== VDIR
&& nfs_pub
.np_index
!= NULL
) {
434 * Setup call to lookup() to see if we can find
435 * the index file. Arguably, this doesn't belong
439 VOP_UNLOCK(nd
.ni_vp
, 0, procp
);
440 ind
.ni_pathlen
= strlen(nfs_pub
.np_index
);
441 ind
.ni_cnd
.cn_nameptr
= ind
.ni_cnd
.cn_pnbuf
=
443 ind
.ni_startdir
= nd
.ni_vp
;
444 VREF(ind
.ni_startdir
);
445 error
= lookup(&ind
);
448 * Found an index file. Get rid of
449 * the old references.
454 vrele(nd
.ni_startdir
);
460 * If the public filehandle was used, check that this lookup
461 * didn't result in a filehandle outside the publicly exported
465 if (!error
&& ndp
->ni_vp
->v_mount
!= nfs_pub
.np_mount
) {
474 dirattr_ret
= VOP_GETATTR(dirp
, &dirattr
, cred
,
480 nfsm_reply(NFSX_POSTOPATTR(v3
));
481 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
485 nqsrv_getl(ndp
->ni_startdir
, ND_READ
);
486 vrele(ndp
->ni_startdir
);
487 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
489 bzero((caddr_t
)fhp
, sizeof(nfh
));
490 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
491 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
493 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
495 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPORFATTR(v3
) + NFSX_POSTOPATTR(v3
));
497 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
500 nfsm_srvfhtom(fhp
, v3
);
502 nfsm_srvpostop_attr(0, vap
);
503 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
505 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
506 nfsm_srvfillattr(vap
, fp
);
512 * nfs readlink service
515 nfsrv_readlink(nfsd
, slp
, procp
, mrq
)
516 struct nfsrv_descript
*nfsd
;
517 struct nfssvc_sock
*slp
;
521 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
522 struct mbuf
*nam
= nfsd
->nd_nam
;
523 caddr_t dpos
= nfsd
->nd_dpos
;
524 struct ucred
*cred
= &nfsd
->nd_cr
;
525 struct iovec iv
[(NFS_MAXPATHLEN
+MLEN
-1)/MLEN
];
526 register struct iovec
*ivp
= iv
;
527 register struct mbuf
*mp
;
531 int error
= 0, rdonly
, cache
, i
, tlen
, len
, getret
;
532 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
534 struct mbuf
*mb
, *mb2
, *mp2
, *mp3
, *mreq
;
539 struct uio io
, *uiop
= &io
;
543 mp2
= mp3
= (struct mbuf
*)0;
545 fhp
= &nfh
.fh_generic
;
549 while (len
< NFS_MAXPATHLEN
) {
550 MGET(mp
, M_WAIT
, MT_DATA
);
552 mp
->m_len
= NFSMSIZ(mp
);
559 if ((len
+mp
->m_len
) > NFS_MAXPATHLEN
) {
560 mp
->m_len
= NFS_MAXPATHLEN
-len
;
561 len
= NFS_MAXPATHLEN
;
564 ivp
->iov_base
= mtod(mp
, caddr_t
);
565 ivp
->iov_len
= mp
->m_len
;
570 uiop
->uio_iovcnt
= i
;
571 uiop
->uio_offset
= 0;
572 uiop
->uio_resid
= len
;
573 uiop
->uio_rw
= UIO_READ
;
574 uiop
->uio_segflg
= UIO_SYSSPACE
;
575 uiop
->uio_procp
= (struct proc
*)0;
576 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
577 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
579 nfsm_reply(2 * NFSX_UNSIGNED
);
580 nfsm_srvpostop_attr(1, (struct vattr
*)0);
583 if (vp
->v_type
!= VLNK
) {
590 nqsrv_getl(vp
, ND_READ
);
591 error
= VOP_READLINK(vp
, uiop
, cred
);
593 getret
= VOP_GETATTR(vp
, &attr
, cred
, procp
);
597 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_UNSIGNED
);
599 nfsm_srvpostop_attr(getret
, &attr
);
603 if (uiop
->uio_resid
> 0) {
604 len
-= uiop
->uio_resid
;
605 tlen
= nfsm_rndup(len
);
606 nfsm_adj(mp3
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
608 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
609 *tl
= txdr_unsigned(len
);
618 nfsrv_read(nfsd
, slp
, procp
, mrq
)
619 struct nfsrv_descript
*nfsd
;
620 struct nfssvc_sock
*slp
;
624 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
625 struct mbuf
*nam
= nfsd
->nd_nam
;
626 caddr_t dpos
= nfsd
->nd_dpos
;
627 struct ucred
*cred
= &nfsd
->nd_cr
;
628 register struct iovec
*iv
;
630 register struct mbuf
*m
;
631 register struct nfs_fattr
*fp
;
636 int error
= 0, rdonly
, cache
, cnt
, len
, left
, siz
, tlen
, getret
;
637 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), reqlen
;
639 struct mbuf
*mb
, *mb2
, *mreq
;
644 struct uio io
, *uiop
= &io
;
645 struct vattr va
, *vap
= &va
;
649 fhp
= &nfh
.fh_generic
;
652 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
653 fxdr_hyper(tl
, &off
);
655 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
656 off
= (off_t
)fxdr_unsigned(u_long
, *tl
);
658 nfsm_srvstrsiz(reqlen
, NFS_SRVMAXDATA(nfsd
));
659 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
660 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
661 nfsm_reply(2 * NFSX_UNSIGNED
);
662 nfsm_srvpostop_attr(1, (struct vattr
*)0);
665 if (vp
->v_type
!= VREG
) {
669 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
672 nqsrv_getl(vp
, ND_READ
);
673 if ((error
= nfsrv_access(vp
, VREAD
, cred
, rdonly
, procp
, 1)))
674 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 1);
676 getret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
681 nfsm_reply(NFSX_POSTOPATTR(v3
));
682 nfsm_srvpostop_attr(getret
, vap
);
685 if (off
>= vap
->va_size
)
687 else if ((off
+ reqlen
) > vap
->va_size
)
688 cnt
= nfsm_rndup(vap
->va_size
- off
);
691 nfsm_reply(NFSX_POSTOPORFATTR(v3
) + 3 * NFSX_UNSIGNED
+nfsm_rndup(cnt
));
693 nfsm_build(tl
, u_long
*, NFSX_V3FATTR
+ 4 * NFSX_UNSIGNED
);
695 fp
= (struct nfs_fattr
*)tl
;
696 tl
+= (NFSX_V3FATTR
/ sizeof (u_long
));
698 nfsm_build(tl
, u_long
*, NFSX_V2FATTR
+ NFSX_UNSIGNED
);
699 fp
= (struct nfs_fattr
*)tl
;
700 tl
+= (NFSX_V2FATTR
/ sizeof (u_long
));
705 * Generate the mbuf list with the uio_iov ref. to it.
710 siz
= min(M_TRAILINGSPACE(m
), left
);
716 MGET(m
, M_WAIT
, MT_DATA
);
723 MALLOC(iv
, struct iovec
*, i
* sizeof (struct iovec
),
725 uiop
->uio_iov
= iv2
= iv
;
731 panic("nfsrv_read iov");
732 siz
= min(M_TRAILINGSPACE(m
), left
);
734 iv
->iov_base
= mtod(m
, caddr_t
) + m
->m_len
;
743 uiop
->uio_iovcnt
= i
;
744 uiop
->uio_offset
= off
;
745 uiop
->uio_resid
= cnt
;
746 uiop
->uio_rw
= UIO_READ
;
747 uiop
->uio_segflg
= UIO_SYSSPACE
;
748 error
= VOP_READ(vp
, uiop
, IO_NODELOCKED
, cred
);
749 off
= uiop
->uio_offset
;
750 FREE((caddr_t
)iv2
, M_TEMP
);
751 /* Though our code replaces error with getret, the way I read
752 * the v3 spec, it appears you should leave the error alone, but
753 * still return vap and not assign error = getret. But leaving
754 * that alone. m_freem(mreq) looks bogus. Taking it out. Should be
755 * mrep or not there at all. Causes panic. ekn */
756 if (error
|| (getret
= VOP_GETATTR(vp
, vap
, cred
, procp
))) {
761 nfsm_reply(NFSX_POSTOPATTR(v3
));
762 nfsm_srvpostop_attr(getret
, vap
);
768 nfsm_srvfillattr(vap
, fp
);
769 len
-= uiop
->uio_resid
;
770 tlen
= nfsm_rndup(len
);
771 if (cnt
!= tlen
|| tlen
!= len
)
772 nfsm_adj(mb
, cnt
- tlen
, tlen
- len
);
774 *tl
++ = txdr_unsigned(len
);
780 *tl
= txdr_unsigned(len
);
788 nfsrv_write(nfsd
, slp
, procp
, mrq
)
789 struct nfsrv_descript
*nfsd
;
790 struct nfssvc_sock
*slp
;
794 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
795 struct mbuf
*nam
= nfsd
->nd_nam
;
796 caddr_t dpos
= nfsd
->nd_dpos
;
797 struct ucred
*cred
= &nfsd
->nd_cr
;
798 register struct iovec
*ivp
;
800 register struct mbuf
*mp
;
801 register struct nfs_fattr
*fp
;
803 struct vattr va
, forat
;
804 register struct vattr
*vap
= &va
;
808 int error
= 0, rdonly
, cache
, len
, forat_ret
= 1;
809 int ioflags
, aftat_ret
= 1, retlen
, zeroing
, adjust
;
810 int stable
= NFSV3WRITE_FILESYNC
;
811 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
813 struct mbuf
*mb
, *mb2
, *mreq
;
817 struct uio io
, *uiop
= &io
;
825 fhp
= &nfh
.fh_generic
;
828 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
829 fxdr_hyper(tl
, &off
);
831 stable
= fxdr_unsigned(int, *tl
++);
833 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
834 off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
837 stable
= NFSV3WRITE_UNSTABLE
;
839 retlen
= len
= fxdr_unsigned(long, *tl
);
843 * For NFS Version 2, it is not obvious what a write of zero length
844 * should do, but I might as well be consistent with Version 3,
845 * which is to return ok so long as there are no permission problems.
853 adjust
= dpos
- mtod(mp
, caddr_t
);
855 if (mp
->m_len
> 0 && adjust
> 0)
860 else if (mp
->m_len
> 0) {
863 mp
->m_len
-= (i
- len
);
872 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
874 nfsm_reply(2 * NFSX_UNSIGNED
);
875 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
878 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
879 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
880 nfsm_reply(2 * NFSX_UNSIGNED
);
881 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
885 forat_ret
= VOP_GETATTR(vp
, &forat
, cred
, procp
);
886 if (vp
->v_type
!= VREG
) {
890 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
893 nqsrv_getl(vp
, ND_WRITE
);
894 error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
, procp
, 1);
898 nfsm_reply(NFSX_WCCDATA(v3
));
899 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
904 MALLOC(ivp
, struct iovec
*, cnt
* sizeof (struct iovec
), M_TEMP
,
906 uiop
->uio_iov
= iv
= ivp
;
907 uiop
->uio_iovcnt
= cnt
;
911 ivp
->iov_base
= mtod(mp
, caddr_t
);
912 ivp
->iov_len
= mp
->m_len
;
920 * The IO_METASYNC flag indicates that all metadata (and not just
921 * enough to ensure data integrity) mus be written to stable storage
923 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
925 if (stable
== NFSV3WRITE_UNSTABLE
)
926 ioflags
= IO_NODELOCKED
;
927 else if (stable
== NFSV3WRITE_DATASYNC
)
928 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
930 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
931 uiop
->uio_resid
= len
;
932 uiop
->uio_rw
= UIO_WRITE
;
933 uiop
->uio_segflg
= UIO_SYSSPACE
;
934 uiop
->uio_procp
= (struct proc
*)0;
935 uiop
->uio_offset
= off
;
936 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
937 nfsstats
.srvvop_writes
++;
938 FREE((caddr_t
)iv
, M_TEMP
);
940 aftat_ret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
944 nfsm_reply(NFSX_PREOPATTR(v3
) + NFSX_POSTOPORFATTR(v3
) +
945 2 * NFSX_UNSIGNED
+ NFSX_WRITEVERF(v3
));
947 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
950 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
951 *tl
++ = txdr_unsigned(retlen
);
953 * If nfs_async is set, then pretend the write was FILESYNC.
955 if (stable
== NFSV3WRITE_UNSTABLE
&& !nfs_async
)
956 *tl
++ = txdr_unsigned(stable
);
958 *tl
++ = txdr_unsigned(NFSV3WRITE_FILESYNC
);
960 * Actually, there is no need to txdr these fields,
961 * but it may make the values more human readable,
962 * for debugging purposes.
964 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
965 *tl
= txdr_unsigned(boottime
.tv_usec
);
967 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
968 nfsm_srvfillattr(vap
, fp
);
974 * NFS write service with write gathering support. Called when
975 * nfsrvw_procrastinate > 0.
976 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
977 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
981 nfsrv_writegather(ndp
, slp
, procp
, mrq
)
982 struct nfsrv_descript
**ndp
;
983 struct nfssvc_sock
*slp
;
987 register struct iovec
*ivp
;
988 register struct mbuf
*mp
;
989 register struct nfsrv_descript
*wp
, *nfsd
, *owp
, *swp
;
990 register struct nfs_fattr
*fp
;
993 struct nfsrvw_delayhash
*wpp
;
995 struct vattr va
, forat
;
999 int error
= 0, rdonly
, cache
, len
, forat_ret
= 1;
1000 int ioflags
, aftat_ret
= 1, s
, adjust
, v3
, zeroing
;
1002 struct mbuf
*mb
, *mb2
, *mreq
, *mrep
, *md
;
1004 struct uio io
, *uiop
= &io
;
1005 u_quad_t frev
, cur_usec
;
1015 mrep
= nfsd
->nd_mrep
;
1017 dpos
= nfsd
->nd_dpos
;
1018 cred
= &nfsd
->nd_cr
;
1019 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1020 LIST_INIT(&nfsd
->nd_coalesce
);
1021 nfsd
->nd_mreq
= NULL
;
1022 nfsd
->nd_stable
= NFSV3WRITE_FILESYNC
;
1023 cur_usec
= (u_quad_t
)time
.tv_sec
* 1000000 + (u_quad_t
)time
.tv_usec
;
1024 nfsd
->nd_time
= cur_usec
+
1025 (v3
? nfsrvw_procrastinate_v3
: nfsrvw_procrastinate
);
1028 * Now, get the write header..
1030 nfsm_srvmtofh(&nfsd
->nd_fh
);
1032 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1033 fxdr_hyper(tl
, &nfsd
->nd_off
);
1035 nfsd
->nd_stable
= fxdr_unsigned(int, *tl
++);
1037 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1038 nfsd
->nd_off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
1041 nfsd
->nd_stable
= NFSV3WRITE_UNSTABLE
;
1043 len
= fxdr_unsigned(long, *tl
);
1045 nfsd
->nd_eoff
= nfsd
->nd_off
+ len
;
1048 * Trim the header out of the mbuf list and trim off any trailing
1049 * junk so that the mbuf list has only the write data.
1057 adjust
= dpos
- mtod(mp
, caddr_t
);
1058 mp
->m_len
-= adjust
;
1059 if (mp
->m_len
> 0 && adjust
> 0)
1060 NFSMADV(mp
, adjust
);
1067 mp
->m_len
-= (i
- len
);
1073 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1077 nfsm_writereply(2 * NFSX_UNSIGNED
, v3
);
1079 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1080 nfsd
->nd_mreq
= mreq
;
1081 nfsd
->nd_mrep
= NULL
;
1086 * Add this entry to the hash and time queues.
1090 wp
= slp
->ns_tq
.lh_first
;
1091 while (wp
&& wp
->nd_time
< nfsd
->nd_time
) {
1093 wp
= wp
->nd_tq
.le_next
;
1095 NFS_DPF(WG
, ("Q%03x", nfsd
->nd_retxid
& 0xfff));
1097 LIST_INSERT_AFTER(owp
, nfsd
, nd_tq
);
1099 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1101 if (nfsd
->nd_mrep
) {
1102 wpp
= NWDELAYHASH(slp
, nfsd
->nd_fh
.fh_fid
.fid_data
);
1106 bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1108 wp
= wp
->nd_hash
.le_next
;
1110 while (wp
&& wp
->nd_off
< nfsd
->nd_off
&&
1111 !bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1113 wp
= wp
->nd_hash
.le_next
;
1116 LIST_INSERT_AFTER(owp
, nfsd
, nd_hash
);
1119 * Search the hash list for overlapping entries and
1122 for(; nfsd
&& NFSW_CONTIG(owp
, nfsd
); nfsd
= wp
) {
1123 wp
= nfsd
->nd_hash
.le_next
;
1124 if (NFSW_SAMECRED(owp
, nfsd
))
1125 nfsrvw_coalesce(owp
, nfsd
);
1128 LIST_INSERT_HEAD(wpp
, nfsd
, nd_hash
);
1135 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1136 * and generate the associated reply mbuf list(s).
1139 cur_usec
= (u_quad_t
)time
.tv_sec
* 1000000 + (u_quad_t
)time
.tv_usec
;
1141 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= owp
) {
1142 owp
= nfsd
->nd_tq
.le_next
;
1143 if (nfsd
->nd_time
> cur_usec
)
1147 NFS_DPF(WG
, ("P%03x", nfsd
->nd_retxid
& 0xfff));
1148 LIST_REMOVE(nfsd
, nd_tq
);
1149 LIST_REMOVE(nfsd
, nd_hash
);
1151 mrep
= nfsd
->nd_mrep
;
1152 nfsd
->nd_mrep
= NULL
;
1153 cred
= &nfsd
->nd_cr
;
1154 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1155 forat_ret
= aftat_ret
= 1;
1156 error
= nfsrv_fhtovp(&nfsd
->nd_fh
, 1, &vp
, cred
, slp
,
1157 nfsd
->nd_nam
, &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
1160 forat_ret
= VOP_GETATTR(vp
, &forat
, cred
, procp
);
1161 if (vp
->v_type
!= VREG
) {
1165 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
1170 nqsrv_getl(vp
, ND_WRITE
);
1171 error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
, procp
, 1);
1174 if (nfsd
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1175 ioflags
= IO_NODELOCKED
;
1176 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
)
1177 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1179 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1180 uiop
->uio_rw
= UIO_WRITE
;
1181 uiop
->uio_segflg
= UIO_SYSSPACE
;
1182 uiop
->uio_procp
= (struct proc
*)0;
1183 uiop
->uio_offset
= nfsd
->nd_off
;
1184 uiop
->uio_resid
= nfsd
->nd_eoff
- nfsd
->nd_off
;
1185 if (uiop
->uio_resid
> 0) {
1193 uiop
->uio_iovcnt
= i
;
1194 MALLOC(iov
, struct iovec
*, i
* sizeof (struct iovec
),
1196 uiop
->uio_iov
= ivp
= iov
;
1199 if (mp
->m_len
> 0) {
1200 ivp
->iov_base
= mtod(mp
, caddr_t
);
1201 ivp
->iov_len
= mp
->m_len
;
1207 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
1208 nfsstats
.srvvop_writes
++;
1210 FREE((caddr_t
)iov
, M_TEMP
);
1214 aftat_ret
= VOP_GETATTR(vp
, &va
, cred
, procp
);
1219 * Loop around generating replies for all write rpcs that have
1220 * now been completed.
1224 NFS_DPF(WG
, ("R%03x", nfsd
->nd_retxid
& 0xfff));
1226 nfsm_writereply(NFSX_WCCDATA(v3
), v3
);
1228 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1231 nfsm_writereply(NFSX_PREOPATTR(v3
) +
1232 NFSX_POSTOPORFATTR(v3
) + 2 * NFSX_UNSIGNED
+
1233 NFSX_WRITEVERF(v3
), v3
);
1235 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1236 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1237 *tl
++ = txdr_unsigned(nfsd
->nd_len
);
1238 *tl
++ = txdr_unsigned(swp
->nd_stable
);
1240 * Actually, there is no need to txdr these fields,
1241 * but it may make the values more human readable,
1242 * for debugging purposes.
1244 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
1245 *tl
= txdr_unsigned(boottime
.tv_usec
);
1247 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1248 nfsm_srvfillattr(&va
, fp
);
1251 nfsd
->nd_mreq
= mreq
;
1253 panic("nfsrv_write: nd_mrep not free");
1256 * Done. Put it at the head of the timer queue so that
1257 * the final phase can return the reply.
1262 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1264 nfsd
= swp
->nd_coalesce
.lh_first
;
1266 LIST_REMOVE(nfsd
, nd_tq
);
1272 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1279 * Search for a reply to return.
1282 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= nfsd
->nd_tq
.le_next
)
1283 if (nfsd
->nd_mreq
) {
1284 NFS_DPF(WG
, ("X%03x", nfsd
->nd_retxid
& 0xfff));
1285 LIST_REMOVE(nfsd
, nd_tq
);
1286 *mrq
= nfsd
->nd_mreq
;
1295 * Coalesce the write request nfsd into owp. To do this we must:
1296 * - remove nfsd from the queues
1297 * - merge nfsd->nd_mrep into owp->nd_mrep
1298 * - update the nd_eoff and nd_stable for owp
1299 * - put nfsd on owp's nd_coalesce list
1300 * NB: Must be called at splsoftclock().
1303 nfsrvw_coalesce(owp
, nfsd
)
1304 register struct nfsrv_descript
*owp
;
1305 register struct nfsrv_descript
*nfsd
;
1307 register int overlap
;
1308 register struct mbuf
*mp
;
1309 struct nfsrv_descript
*p
;
1311 NFS_DPF(WG
, ("C%03x-%03x",
1312 nfsd
->nd_retxid
& 0xfff, owp
->nd_retxid
& 0xfff));
1313 LIST_REMOVE(nfsd
, nd_hash
);
1314 LIST_REMOVE(nfsd
, nd_tq
);
1315 if (owp
->nd_eoff
< nfsd
->nd_eoff
) {
1316 overlap
= owp
->nd_eoff
- nfsd
->nd_off
;
1318 panic("nfsrv_coalesce: bad off");
1320 m_adj(nfsd
->nd_mrep
, overlap
);
1324 mp
->m_next
= nfsd
->nd_mrep
;
1325 owp
->nd_eoff
= nfsd
->nd_eoff
;
1327 m_freem(nfsd
->nd_mrep
);
1328 nfsd
->nd_mrep
= NULL
;
1329 if (nfsd
->nd_stable
== NFSV3WRITE_FILESYNC
)
1330 owp
->nd_stable
= NFSV3WRITE_FILESYNC
;
1331 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
&&
1332 owp
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1333 owp
->nd_stable
= NFSV3WRITE_DATASYNC
;
1334 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nfsd
, nd_tq
);
1337 * If nfsd had anything else coalesced into it, transfer them
1338 * to owp, otherwise their replies will never get sent.
1340 for (p
= nfsd
->nd_coalesce
.lh_first
; p
;
1341 p
= nfsd
->nd_coalesce
.lh_first
) {
1342 LIST_REMOVE(p
, nd_tq
);
1343 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1348 * Sort the group list in increasing numerical order.
1349 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1350 * that used to be here.)
1353 nfsrvw_sort(list
, num
)
1354 register gid_t
*list
;
1360 /* Insertion sort. */
1361 for (i
= 1; i
< num
; i
++) {
1363 /* find correct slot for value v, moving others up */
1364 for (j
= i
; --j
>= 0 && v
< list
[j
];)
1365 list
[j
+ 1] = list
[j
];
1371 * copy credentials making sure that the result can be compared with bcmp().
1374 nfsrv_setcred(incred
, outcred
)
1375 register struct ucred
*incred
, *outcred
;
1379 bzero((caddr_t
)outcred
, sizeof (struct ucred
));
1380 outcred
->cr_ref
= 1;
1381 outcred
->cr_uid
= incred
->cr_uid
;
1382 outcred
->cr_ngroups
= incred
->cr_ngroups
;
1383 for (i
= 0; i
< incred
->cr_ngroups
; i
++)
1384 outcred
->cr_groups
[i
] = incred
->cr_groups
[i
];
1385 nfsrvw_sort(outcred
->cr_groups
, outcred
->cr_ngroups
);
1389 * nfs create service
1390 * now does a truncate to 0 length via. setattr if it already exists
1393 nfsrv_create(nfsd
, slp
, procp
, mrq
)
1394 struct nfsrv_descript
*nfsd
;
1395 struct nfssvc_sock
*slp
;
1399 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1400 struct mbuf
*nam
= nfsd
->nd_nam
;
1401 caddr_t dpos
= nfsd
->nd_dpos
;
1402 struct ucred
*cred
= &nfsd
->nd_cr
;
1403 register struct nfs_fattr
*fp
;
1404 struct vattr va
, dirfor
, diraft
;
1405 register struct vattr
*vap
= &va
;
1406 register struct nfsv2_sattr
*sp
;
1407 register u_long
*tl
;
1408 struct nameidata nd
;
1409 register caddr_t cp
;
1412 int error
= 0, rdev
, cache
, len
, tsize
, dirfor_ret
= 1, diraft_ret
= 1;
1413 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), how
, exclusive_flag
= 0;
1415 struct mbuf
*mb
, *mb2
, *mreq
;
1416 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
1419 u_quad_t frev
, tempsize
;
1420 u_char cverf
[NFSX_V3CREATEVERF
];
1425 nd
.ni_cnd
.cn_nameiop
= 0;
1426 fhp
= &nfh
.fh_generic
;
1428 nfsm_srvnamesiz(len
);
1429 nd
.ni_cnd
.cn_cred
= cred
;
1430 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1431 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| SAVESTART
;
1432 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
1433 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1436 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
1440 dirp
= (struct vnode
*)0;
1444 nfsm_reply(NFSX_WCCDATA(v3
));
1445 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1452 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
1453 how
= fxdr_unsigned(int, *tl
);
1455 case NFSV3CREATE_GUARDED
:
1460 case NFSV3CREATE_UNCHECKED
:
1463 case NFSV3CREATE_EXCLUSIVE
:
1464 nfsm_dissect(cp
, caddr_t
, NFSX_V3CREATEVERF
);
1465 bcopy(cp
, cverf
, NFSX_V3CREATEVERF
);
1467 if (nd
.ni_vp
== NULL
)
1471 vap
->va_type
= VREG
;
1473 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1474 vap
->va_type
= IFTOVT(fxdr_unsigned(u_long
, sp
->sa_mode
));
1475 if (vap
->va_type
== VNON
)
1476 vap
->va_type
= VREG
;
1477 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
1478 switch (vap
->va_type
) {
1480 tsize
= fxdr_unsigned(long, sp
->sa_size
);
1482 vap
->va_size
= (u_quad_t
)tsize
;
1487 rdev
= fxdr_unsigned(long, sp
->sa_size
);
1493 * Iff doesn't exist, create it
1494 * otherwise just truncate to 0 length
1495 * should I set the mode too ??
1497 if (nd
.ni_vp
== NULL
) {
1498 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1499 vrele(nd
.ni_startdir
);
1500 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1501 error
= VOP_CREATE(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
);
1503 nfsrv_object_create(nd
.ni_vp
);
1504 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1505 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1506 if (exclusive_flag
) {
1509 bcopy(cverf
, (caddr_t
)&vap
->va_atime
,
1511 error
= VOP_SETATTR(nd
.ni_vp
, vap
, cred
,
1515 } else if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
||
1516 vap
->va_type
== VFIFO
) {
1517 if (vap
->va_type
== VCHR
&& rdev
== 0xffffffff)
1518 vap
->va_type
= VFIFO
;
1519 if (vap
->va_type
!= VFIFO
&&
1520 (error
= suser(cred
, (u_short
*)0))) {
1521 vrele(nd
.ni_startdir
);
1522 _FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1523 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1524 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1529 vap
->va_rdev
= (dev_t
)rdev
;
1530 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1531 if ((error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
))) {
1532 vrele(nd
.ni_startdir
);
1535 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1536 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| SAVESTART
);
1537 nd
.ni_cnd
.cn_proc
= procp
;
1538 nd
.ni_cnd
.cn_cred
= cred
;
1539 if ((error
= lookup(&nd
))) {
1540 _FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1541 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1544 nfsrv_object_create(nd
.ni_vp
);
1545 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1546 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1547 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
) {
1550 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1555 vrele(nd
.ni_startdir
);
1556 _FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1557 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1558 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1564 vrele(nd
.ni_startdir
);
1565 _FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1567 if (nd
.ni_dvp
== vp
)
1571 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1572 if (vap
->va_size
!= -1) {
1573 error
= nfsrv_access(vp
, VWRITE
, cred
,
1574 (nd
.ni_cnd
.cn_flags
& RDONLY
), procp
, 0);
1576 nqsrv_getl(vp
, ND_WRITE
);
1577 tempsize
= vap
->va_size
;
1579 vap
->va_size
= tempsize
;
1580 error
= VOP_SETATTR(vp
, vap
, cred
,
1587 vput(vp
); /* make sure we catch the EEXIST for nfsv3 */
1591 bzero((caddr_t
)fhp
, sizeof(nfh
));
1592 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
1593 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1595 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
1599 if (exclusive_flag
&& !error
&&
1600 bcmp(cverf
, (caddr_t
)&vap
->va_atime
, NFSX_V3CREATEVERF
))
1602 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
1605 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_FATTR(v3
) + NFSX_WCCDATA(v3
));
1608 nfsm_srvpostop_fh(fhp
);
1609 nfsm_srvpostop_attr(0, vap
);
1611 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1613 nfsm_srvfhtom(fhp
, v3
);
1614 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1615 nfsm_srvfillattr(vap
, fp
);
1621 if (nd
.ni_cnd
.cn_nameiop
) {
1622 vrele(nd
.ni_startdir
);
1623 _FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1624 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1626 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1627 if (nd
.ni_dvp
== nd
.ni_vp
)
1637 * nfs v3 mknod service
1640 nfsrv_mknod(nfsd
, slp
, procp
, mrq
)
1641 struct nfsrv_descript
*nfsd
;
1642 struct nfssvc_sock
*slp
;
1646 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1647 struct mbuf
*nam
= nfsd
->nd_nam
;
1648 caddr_t dpos
= nfsd
->nd_dpos
;
1649 struct ucred
*cred
= &nfsd
->nd_cr
;
1650 struct vattr va
, dirfor
, diraft
;
1651 register struct vattr
*vap
= &va
;
1652 register u_long
*tl
;
1653 struct nameidata nd
;
1656 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
1657 u_long major
, minor
;
1660 struct mbuf
*mb
, *mb2
, *mreq
;
1661 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
1666 nd
.ni_cnd
.cn_nameiop
= 0;
1667 fhp
= &nfh
.fh_generic
;
1669 nfsm_srvnamesiz(len
);
1670 nd
.ni_cnd
.cn_cred
= cred
;
1671 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1672 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| SAVESTART
;
1673 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
1674 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1676 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
, procp
);
1678 nfsm_reply(NFSX_WCCDATA(1));
1679 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1684 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
1685 vtyp
= nfsv3tov_type(*tl
);
1686 if (vtyp
!= VCHR
&& vtyp
!= VBLK
&& vtyp
!= VSOCK
&& vtyp
!= VFIFO
) {
1687 vrele(nd
.ni_startdir
);
1688 _FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1689 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1690 error
= NFSERR_BADTYPE
;
1691 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1697 if (vtyp
== VCHR
|| vtyp
== VBLK
) {
1698 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1699 major
= fxdr_unsigned(u_long
, *tl
++);
1700 minor
= fxdr_unsigned(u_long
, *tl
);
1701 vap
->va_rdev
= makedev(major
, minor
);
1705 * Iff doesn't exist, create it.
1708 vrele(nd
.ni_startdir
);
1709 _FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1710 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1712 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1716 vap
->va_type
= vtyp
;
1717 if (vtyp
== VSOCK
) {
1718 vrele(nd
.ni_startdir
);
1719 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1720 error
= VOP_CREATE(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
);
1722 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1723 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1725 if (vtyp
!= VFIFO
&& (error
= suser(cred
, (u_short
*)0))) {
1726 vrele(nd
.ni_startdir
);
1727 _FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1728 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1729 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1733 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1734 if ((error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
))) {
1735 vrele(nd
.ni_startdir
);
1738 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1739 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| SAVESTART
);
1740 nd
.ni_cnd
.cn_proc
= procp
;
1741 nd
.ni_cnd
.cn_cred
= procp
->p_ucred
;
1742 error
= lookup(&nd
);
1743 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1746 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
) {
1749 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1756 bzero((caddr_t
)fhp
, sizeof(nfh
));
1757 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
1758 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1760 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
1763 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
1765 nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
1767 nfsm_srvpostop_fh(fhp
);
1768 nfsm_srvpostop_attr(0, vap
);
1770 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1775 if (nd
.ni_cnd
.cn_nameiop
) {
1776 vrele(nd
.ni_startdir
);
1777 _FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1778 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1780 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1781 if (nd
.ni_dvp
== nd
.ni_vp
)
1791 * nfs remove service
1794 nfsrv_remove(nfsd
, slp
, procp
, mrq
)
1795 struct nfsrv_descript
*nfsd
;
1796 struct nfssvc_sock
*slp
;
1800 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1801 struct mbuf
*nam
= nfsd
->nd_nam
;
1802 caddr_t dpos
= nfsd
->nd_dpos
;
1803 struct ucred
*cred
= &nfsd
->nd_cr
;
1804 struct nameidata nd
;
1805 register u_long
*tl
;
1808 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
1809 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1811 struct mbuf
*mb
, *mreq
;
1812 struct vnode
*vp
, *dirp
;
1813 struct vattr dirfor
, diraft
;
1819 vp
= (struct vnode
*)0;
1821 fhp
= &nfh
.fh_generic
;
1823 nfsm_srvnamesiz(len
);
1824 nd
.ni_cnd
.cn_cred
= cred
;
1825 nd
.ni_cnd
.cn_nameiop
= DELETE
;
1826 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1827 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
1828 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1831 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
1838 if (vp
->v_type
== VDIR
) {
1839 error
= EPERM
; /* POSIX */
1843 * The root of a mounted filesystem cannot be deleted.
1845 if (vp
->v_flag
& VROOT
) {
1851 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1852 nqsrv_getl(vp
, ND_WRITE
);
1854 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1857 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1858 if (nd
.ni_dvp
== vp
)
1866 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
1869 nfsm_reply(NFSX_WCCDATA(v3
));
1871 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1878 * nfs rename service
1881 nfsrv_rename(nfsd
, slp
, procp
, mrq
)
1882 struct nfsrv_descript
*nfsd
;
1883 struct nfssvc_sock
*slp
;
1887 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1888 struct mbuf
*nam
= nfsd
->nd_nam
;
1889 caddr_t dpos
= nfsd
->nd_dpos
;
1890 struct ucred
*cred
= &nfsd
->nd_cr
;
1891 register u_long
*tl
;
1894 int error
= 0, cache
, len
, len2
, fdirfor_ret
= 1, fdiraft_ret
= 1;
1895 int tdirfor_ret
= 1, tdiraft_ret
= 1;
1896 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1898 struct mbuf
*mb
, *mreq
;
1899 struct nameidata fromnd
, tond
;
1900 struct vnode
*fvp
, *tvp
, *tdvp
, *fdirp
= (struct vnode
*)0;
1901 struct vnode
*tdirp
= (struct vnode
*)0;
1902 struct vattr fdirfor
, fdiraft
, tdirfor
, tdiraft
;
1904 fhandle_t
*ffhp
, *tfhp
;
1909 fvp
= (struct vnode
*)0;
1911 ffhp
= &fnfh
.fh_generic
;
1912 tfhp
= &tnfh
.fh_generic
;
1913 fromnd
.ni_cnd
.cn_nameiop
= 0;
1914 tond
.ni_cnd
.cn_nameiop
= 0;
1915 nfsm_srvmtofh(ffhp
);
1916 nfsm_srvnamesiz(len
);
1918 * Remember our original uid so that we can reset cr_uid before
1919 * the second nfs_namei() call, in case it is remapped.
1921 saved_uid
= cred
->cr_uid
;
1922 fromnd
.ni_cnd
.cn_cred
= cred
;
1923 fromnd
.ni_cnd
.cn_nameiop
= DELETE
;
1924 fromnd
.ni_cnd
.cn_flags
= WANTPARENT
| SAVESTART
;
1925 error
= nfs_namei(&fromnd
, ffhp
, len
, slp
, nam
, &md
,
1926 &dpos
, &fdirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1929 fdirfor_ret
= VOP_GETATTR(fdirp
, &fdirfor
, cred
,
1933 fdirp
= (struct vnode
*)0;
1937 nfsm_reply(2 * NFSX_WCCDATA(v3
));
1938 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
1939 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
1945 nfsm_srvmtofh(tfhp
);
1946 nfsm_strsiz(len2
, NFS_MAXNAMLEN
);
1947 cred
->cr_uid
= saved_uid
;
1948 tond
.ni_cnd
.cn_cred
= cred
;
1949 tond
.ni_cnd
.cn_nameiop
= RENAME
;
1950 tond
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
;
1951 error
= nfs_namei(&tond
, tfhp
, len2
, slp
, nam
, &md
,
1952 &dpos
, &tdirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1955 tdirfor_ret
= VOP_GETATTR(tdirp
, &tdirfor
, cred
,
1959 tdirp
= (struct vnode
*)0;
1963 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
1964 vrele(fromnd
.ni_dvp
);
1971 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
1977 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
1984 if (tvp
->v_type
== VDIR
&& tvp
->v_mountedhere
) {
1992 if (fvp
->v_type
== VDIR
&& fvp
->v_mountedhere
) {
1999 if (fvp
->v_mount
!= tdvp
->v_mount
) {
2012 * If source is the same as the destination (that is the
2013 * same vnode) then there is nothing to do.
2014 * (fixed to have POSIX semantics - CSM 3/2/98)
2020 nqsrv_getl(fromnd
.ni_dvp
, ND_WRITE
);
2021 nqsrv_getl(tdvp
, ND_WRITE
);
2023 nqsrv_getl(tvp
, ND_WRITE
);
2024 error
= VOP_RENAME(fromnd
.ni_dvp
, fromnd
.ni_vp
, &fromnd
.ni_cnd
,
2025 tond
.ni_dvp
, tond
.ni_vp
, &tond
.ni_cnd
);
2027 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2034 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2035 vrele(fromnd
.ni_dvp
);
2040 vrele(tond
.ni_startdir
);
2041 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2044 fdiraft_ret
= VOP_GETATTR(fdirp
, &fdiraft
, cred
, procp
);
2048 tdiraft_ret
= VOP_GETATTR(tdirp
, &tdiraft
, cred
, procp
);
2051 vrele(fromnd
.ni_startdir
);
2052 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2053 nfsm_reply(2 * NFSX_WCCDATA(v3
));
2055 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
2056 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
2065 if (tond
.ni_cnd
.cn_nameiop
) {
2066 vrele(tond
.ni_startdir
);
2067 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2069 if (fromnd
.ni_cnd
.cn_nameiop
) {
2070 vrele(fromnd
.ni_startdir
);
2071 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
,
2072 fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2073 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2074 vrele(fromnd
.ni_dvp
);
2084 nfsrv_link(nfsd
, slp
, procp
, mrq
)
2085 struct nfsrv_descript
*nfsd
;
2086 struct nfssvc_sock
*slp
;
2090 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2091 struct mbuf
*nam
= nfsd
->nd_nam
;
2092 caddr_t dpos
= nfsd
->nd_dpos
;
2093 struct ucred
*cred
= &nfsd
->nd_cr
;
2094 struct nameidata nd
;
2095 register u_long
*tl
;
2098 int error
= 0, rdonly
, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2099 int getret
= 1, v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2101 struct mbuf
*mb
, *mreq
;
2102 struct vnode
*vp
, *xp
, *dirp
= (struct vnode
*)0;
2103 struct vattr dirfor
, diraft
, at
;
2105 fhandle_t
*fhp
, *dfhp
;
2108 fhp
= &nfh
.fh_generic
;
2109 dfhp
= &dnfh
.fh_generic
;
2111 nfsm_srvmtofh(dfhp
);
2112 nfsm_srvnamesiz(len
);
2113 if ((error
= nfsrv_fhtovp(fhp
, FALSE
, &vp
, cred
, slp
, nam
,
2114 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
2115 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2116 nfsm_srvpostop_attr(getret
, &at
);
2117 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2120 if (vp
->v_type
== VDIR
) {
2121 error
= EPERM
; /* POSIX */
2124 nd
.ni_cnd
.cn_cred
= cred
;
2125 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2126 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2127 error
= nfs_namei(&nd
, dfhp
, len
, slp
, nam
, &md
, &dpos
,
2128 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2131 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2135 dirp
= (struct vnode
*)0;
2146 if (vp
->v_mount
!= xp
->v_mount
)
2150 nqsrv_getl(vp
, ND_WRITE
);
2151 nqsrv_getl(xp
, ND_WRITE
);
2152 error
= VOP_LINK(vp
, nd
.ni_dvp
, &nd
.ni_cnd
);
2154 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2155 if (nd
.ni_dvp
== nd
.ni_vp
)
2164 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2166 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2170 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2172 nfsm_srvpostop_attr(getret
, &at
);
2173 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2180 * nfs symbolic link service
2183 nfsrv_symlink(nfsd
, slp
, procp
, mrq
)
2184 struct nfsrv_descript
*nfsd
;
2185 struct nfssvc_sock
*slp
;
2189 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2190 struct mbuf
*nam
= nfsd
->nd_nam
;
2191 caddr_t dpos
= nfsd
->nd_dpos
;
2192 struct ucred
*cred
= &nfsd
->nd_cr
;
2193 struct vattr va
, dirfor
, diraft
;
2194 struct nameidata nd
;
2195 register struct vattr
*vap
= &va
;
2196 register u_long
*tl
;
2198 struct nfsv2_sattr
*sp
;
2199 char *bpos
, *pathcp
= (char *)0, *cp2
;
2202 int error
= 0, cache
, len
, len2
, dirfor_ret
= 1, diraft_ret
= 1;
2203 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2204 struct mbuf
*mb
, *mreq
, *mb2
;
2205 struct vnode
*dirp
= (struct vnode
*)0;
2210 nd
.ni_cnd
.cn_nameiop
= 0;
2211 fhp
= &nfh
.fh_generic
;
2213 nfsm_srvnamesiz(len
);
2214 nd
.ni_cnd
.cn_cred
= cred
;
2215 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2216 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| SAVESTART
;
2217 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
2218 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2221 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2225 dirp
= (struct vnode
*)0;
2233 nfsm_strsiz(len2
, NFS_MAXPATHLEN
);
2234 MALLOC(pathcp
, caddr_t
, len2
+ 1, M_TEMP
, M_WAITOK
);
2235 iv
.iov_base
= pathcp
;
2237 io
.uio_resid
= len2
;
2241 io
.uio_segflg
= UIO_SYSSPACE
;
2242 io
.uio_rw
= UIO_READ
;
2243 io
.uio_procp
= (struct proc
*)0;
2244 nfsm_mtouio(&io
, len2
);
2246 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2247 vap
->va_mode
= fxdr_unsigned(u_short
, sp
->sa_mode
);
2249 *(pathcp
+ len2
) = '\0';
2251 vrele(nd
.ni_startdir
);
2252 _FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2253 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2254 if (nd
.ni_dvp
== nd
.ni_vp
)
2262 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2263 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
, pathcp
);
2265 vrele(nd
.ni_startdir
);
2268 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2269 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| SAVESTART
| FOLLOW
);
2270 nd
.ni_cnd
.cn_flags
|= (NOFOLLOW
| LOCKLEAF
);
2271 nd
.ni_cnd
.cn_proc
= procp
;
2272 nd
.ni_cnd
.cn_cred
= cred
;
2273 error
= lookup(&nd
);
2275 bzero((caddr_t
)fhp
, sizeof(nfh
));
2276 fhp
->fh_fsid
= nd
.ni_vp
->v_mount
->mnt_stat
.f_fsid
;
2277 error
= VFS_VPTOFH(nd
.ni_vp
, &fhp
->fh_fid
);
2279 error
= VOP_GETATTR(nd
.ni_vp
, vap
, cred
,
2284 vrele(nd
.ni_startdir
);
2285 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2289 FREE(pathcp
, M_TEMP
);
2291 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2294 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2297 nfsm_srvpostop_fh(fhp
);
2298 nfsm_srvpostop_attr(0, vap
);
2300 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2304 if (nd
.ni_cnd
.cn_nameiop
) {
2305 vrele(nd
.ni_startdir
);
2306 _FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2310 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2311 if (nd
.ni_dvp
== nd
.ni_vp
)
2318 FREE(pathcp
, M_TEMP
);
2326 nfsrv_mkdir(nfsd
, slp
, procp
, mrq
)
2327 struct nfsrv_descript
*nfsd
;
2328 struct nfssvc_sock
*slp
;
2332 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2333 struct mbuf
*nam
= nfsd
->nd_nam
;
2334 caddr_t dpos
= nfsd
->nd_dpos
;
2335 struct ucred
*cred
= &nfsd
->nd_cr
;
2336 struct vattr va
, dirfor
, diraft
;
2337 register struct vattr
*vap
= &va
;
2338 register struct nfs_fattr
*fp
;
2339 struct nameidata nd
;
2340 register caddr_t cp
;
2341 register u_long
*tl
;
2344 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2345 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2347 struct mbuf
*mb
, *mb2
, *mreq
;
2348 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
2353 fhp
= &nfh
.fh_generic
;
2355 nfsm_srvnamesiz(len
);
2356 nd
.ni_cnd
.cn_cred
= cred
;
2357 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2358 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2359 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
2360 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2363 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2367 dirp
= (struct vnode
*)0;
2371 nfsm_reply(NFSX_WCCDATA(v3
));
2372 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2381 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
2382 vap
->va_mode
= nfstov_mode(*tl
++);
2384 vap
->va_type
= VDIR
;
2387 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2388 if (nd
.ni_dvp
== vp
)
2396 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2397 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
);
2400 bzero((caddr_t
)fhp
, sizeof(nfh
));
2401 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
2402 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
2404 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
2409 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2412 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2415 nfsm_srvpostop_fh(fhp
);
2416 nfsm_srvpostop_attr(0, vap
);
2418 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2420 nfsm_srvfhtom(fhp
, v3
);
2421 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
2422 nfsm_srvfillattr(vap
, fp
);
2428 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2429 if (nd
.ni_dvp
== nd
.ni_vp
)
2442 nfsrv_rmdir(nfsd
, slp
, procp
, mrq
)
2443 struct nfsrv_descript
*nfsd
;
2444 struct nfssvc_sock
*slp
;
2448 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2449 struct mbuf
*nam
= nfsd
->nd_nam
;
2450 caddr_t dpos
= nfsd
->nd_dpos
;
2451 struct ucred
*cred
= &nfsd
->nd_cr
;
2452 register u_long
*tl
;
2455 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2456 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2458 struct mbuf
*mb
, *mreq
;
2459 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
2460 struct vattr dirfor
, diraft
;
2463 struct nameidata nd
;
2466 fhp
= &nfh
.fh_generic
;
2468 nfsm_srvnamesiz(len
);
2469 nd
.ni_cnd
.cn_cred
= cred
;
2470 nd
.ni_cnd
.cn_nameiop
= DELETE
;
2471 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2472 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
2473 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2476 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2480 dirp
= (struct vnode
*)0;
2484 nfsm_reply(NFSX_WCCDATA(v3
));
2485 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2491 if (vp
->v_type
!= VDIR
) {
2496 * No rmdir "." please.
2498 if (nd
.ni_dvp
== vp
) {
2503 * The root of a mounted filesystem cannot be deleted.
2505 if (vp
->v_flag
& VROOT
)
2509 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2510 nqsrv_getl(vp
, ND_WRITE
);
2511 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2513 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2514 if (nd
.ni_dvp
== nd
.ni_vp
)
2521 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2524 nfsm_reply(NFSX_WCCDATA(v3
));
2526 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2533 * nfs readdir service
2534 * - mallocs what it thinks is enough to read
2535 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2536 * - calls VOP_READDIR()
2537 * - loops around building the reply
2538 * if the output generated exceeds count break out of loop
2539 * The nfsm_clget macro is used here so that the reply will be packed
2540 * tightly in mbuf clusters.
2541 * - it only knows that it has encountered eof when the VOP_READDIR()
2543 * - as such one readdir rpc will return eof false although you are there
2544 * and then the next will return eof
2545 * - it trims out records with d_fileno == 0
2546 * this doesn't matter for Unix clients, but they might confuse clients
2548 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2549 * than requested, but this may not apply to all filesystems. For
2550 * example, client NFS does not { although it is never remote mounted
2552 * The alternate call nfsrv_readdirplus() does lookups as well.
2553 * PS: The NFS protocol spec. does not clarify what the "count" byte
2554 * argument is a count of.. just name strings and file id's or the
2555 * entire reply rpc or ...
2556 * I tried just file name and id sizes and it confused the Sun client,
2557 * so I am using the full rpc size now. The "paranoia.." comment refers
2558 * to including the status longwords that are not a part of the dir.
2559 * "entry" structures, but are in the rpc.
2564 u_long fl_fattr
[NFSX_V3FATTR
/ sizeof (u_long
)];
2567 u_long fl_nfh
[NFSX_V3FH
/ sizeof (u_long
)];
2571 nfsrv_readdir(nfsd
, slp
, procp
, mrq
)
2572 struct nfsrv_descript
*nfsd
;
2573 struct nfssvc_sock
*slp
;
2577 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2578 struct mbuf
*nam
= nfsd
->nd_nam
;
2579 caddr_t dpos
= nfsd
->nd_dpos
;
2580 struct ucred
*cred
= &nfsd
->nd_cr
;
2581 register char *bp
, *be
;
2582 register struct mbuf
*mp
;
2583 register struct dirent
*dp
;
2584 register caddr_t cp
;
2585 register u_long
*tl
;
2588 struct mbuf
*mb
, *mb2
, *mreq
, *mp2
;
2589 char *cpos
, *cend
, *cp2
, *rbuf
;
2596 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2597 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, cache
, ncookies
= 0;
2598 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2599 u_quad_t frev
, off
, toff
, verf
;
2600 u_long
*cookies
= NULL
, *cookiep
;
2602 fhp
= &nfh
.fh_generic
;
2605 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
2606 fxdr_hyper(tl
, &toff
);
2608 fxdr_hyper(tl
, &verf
);
2611 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2612 toff
= fxdr_unsigned(u_quad_t
, *tl
++);
2615 cnt
= fxdr_unsigned(int, *tl
);
2616 siz
= ((cnt
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
2617 xfer
= NFS_SRVMAXDATA(nfsd
);
2621 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
2622 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
2623 nfsm_reply(NFSX_UNSIGNED
);
2624 nfsm_srvpostop_attr(getret
, &at
);
2627 nqsrv_getl(vp
, ND_READ
);
2629 error
= getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2630 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
2631 error
= NFSERR_BAD_COOKIE
;
2634 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 0);
2637 nfsm_reply(NFSX_POSTOPATTR(v3
));
2638 nfsm_srvpostop_attr(getret
, &at
);
2641 VOP_UNLOCK(vp
, 0, procp
);
2642 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
2645 iv
.iov_len
= fullsiz
;
2648 io
.uio_offset
= (off_t
)off
;
2649 io
.uio_resid
= fullsiz
;
2650 io
.uio_segflg
= UIO_SYSSPACE
;
2651 io
.uio_rw
= UIO_READ
;
2652 io
.uio_procp
= (struct proc
*)0;
2656 _FREE((caddr_t
)cookies
, M_TEMP
);
2659 if (error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, procp
)) {
2660 FREE((caddr_t
)rbuf
, M_TEMP
);
2661 nfsm_reply(NFSX_POSTOPATTR(v3
));
2662 nfsm_srvpostop_attr(getret
, &at
);
2665 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
2666 off
= (off_t
)io
.uio_offset
;
2668 * We cannot set the error in the case where there are no cookies
2669 * and no error, only, as FreeBSD. In the scenario the client is
2670 * calling us back being told there were "more" entries on last readdir
2671 * return, and we have no more entries, our VOP_READDIR can give
2672 * cookies = NULL and no error. This is due to a zero size to MALLOC
2673 * returning NULL unlike FreeBSD which returns a pointer.
2674 * With FreeBSD it makes sense if the MALLOC failed and you get in that
2675 * bind. For us, we need something more. Thus, we should make sure we
2676 * had some cookies to return, but no pointer and no error for EPERM case.
2677 * Otherwise, go thru normal processing of sending back the eofflag. This check
2678 * is also legit on first call to the routine by client since . and ..
2679 * should be returned. Make same change to nfsrv_readdirplus.
2681 if ((ncookies
!= 0) && !cookies
&& !error
)
2682 error
= NFSERR_PERM
;
2685 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2689 VOP_UNLOCK(vp
, 0, procp
);
2692 _FREE((caddr_t
)rbuf
, M_TEMP
);
2694 _FREE((caddr_t
)cookies
, M_TEMP
);
2695 nfsm_reply(NFSX_POSTOPATTR(v3
));
2696 nfsm_srvpostop_attr(getret
, &at
);
2700 siz
-= io
.uio_resid
;
2703 * If nothing read, return eof
2708 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) +
2711 nfsm_srvpostop_attr(getret
, &at
);
2712 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
2713 txdr_hyper(&at
.va_filerev
, tl
);
2716 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2719 FREE((caddr_t
)rbuf
, M_TEMP
);
2720 FREE((caddr_t
)cookies
, M_TEMP
);
2726 * Check for degenerate cases of nothing useful read.
2727 * If so go try again
2731 dp
= (struct dirent
*)cpos
;
2735 * For some reason FreeBSD's ufs_readdir() chooses to back the
2736 * directory offset up to a block boundary, so it is necessary to
2737 * skip over the records that preceed the requested offset. This
2738 * requires the assumption that file offset cookies monotonically
2741 while (cpos
< cend
&& ncookies
> 0 &&
2742 (dp
->d_fileno
== 0 || ((u_quad_t
)(*cookiep
)) <= toff
)) {
2744 while (dp
->d_fileno
== 0 && cpos
< cend
&& ncookies
> 0) {
2746 cpos
+= dp
->d_reclen
;
2747 dp
= (struct dirent
*)cpos
;
2751 if (cpos
>= cend
|| ncookies
== 0) {
2757 len
= 3 * NFSX_UNSIGNED
; /* paranoia, probably can be 0 */
2758 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) + siz
);
2760 nfsm_srvpostop_attr(getret
, &at
);
2761 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2762 txdr_hyper(&at
.va_filerev
, tl
);
2766 be
= bp
+ M_TRAILINGSPACE(mp
);
2768 /* Loop through the records and build reply */
2769 while (cpos
< cend
&& ncookies
> 0) {
2770 if (dp
->d_fileno
!= 0) {
2771 nlen
= dp
->d_namlen
;
2772 rem
= nfsm_rndup(nlen
)-nlen
;
2773 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
2775 len
+= 2 * NFSX_UNSIGNED
;
2781 * Build the directory record xdr from
2786 bp
+= NFSX_UNSIGNED
;
2790 bp
+= NFSX_UNSIGNED
;
2793 *tl
= txdr_unsigned(dp
->d_fileno
);
2794 bp
+= NFSX_UNSIGNED
;
2796 *tl
= txdr_unsigned(nlen
);
2797 bp
+= NFSX_UNSIGNED
;
2799 /* And loop around copying the name */
2808 bcopy(cp
, bp
, tsiz
);
2814 /* And null pad to a long boundary */
2815 for (i
= 0; i
< rem
; i
++)
2819 /* Finish off the record */
2822 bp
+= NFSX_UNSIGNED
;
2825 *tl
= txdr_unsigned(*cookiep
);
2826 bp
+= NFSX_UNSIGNED
;
2828 cpos
+= dp
->d_reclen
;
2829 dp
= (struct dirent
*)cpos
;
2836 bp
+= NFSX_UNSIGNED
;
2842 bp
+= NFSX_UNSIGNED
;
2845 mp
->m_len
= bp
- mtod(mp
, caddr_t
);
2847 mp
->m_len
+= bp
- bpos
;
2848 FREE((caddr_t
)rbuf
, M_TEMP
);
2849 FREE((caddr_t
)cookies
, M_TEMP
);
2854 nfsrv_readdirplus(nfsd
, slp
, procp
, mrq
)
2855 struct nfsrv_descript
*nfsd
;
2856 struct nfssvc_sock
*slp
;
2860 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2861 struct mbuf
*nam
= nfsd
->nd_nam
;
2862 caddr_t dpos
= nfsd
->nd_dpos
;
2863 struct ucred
*cred
= &nfsd
->nd_cr
;
2864 register char *bp
, *be
;
2865 register struct mbuf
*mp
;
2866 register struct dirent
*dp
;
2867 register caddr_t cp
;
2868 register u_long
*tl
;
2871 struct mbuf
*mb
, *mb2
, *mreq
, *mp2
;
2872 char *cpos
, *cend
, *cp2
, *rbuf
;
2873 struct vnode
*vp
, *nvp
;
2876 fhandle_t
*fhp
, *nfhp
= (fhandle_t
*)fl
.fl_nfh
;
2879 struct vattr va
, at
, *vap
= &va
;
2880 struct nfs_fattr
*fp
;
2881 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2882 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, cache
, dirlen
, ncookies
= 0;
2883 u_quad_t frev
, off
, toff
, verf
;
2884 u_long
*cookies
= NULL
, *cookiep
;
2887 fhp
= &nfh
.fh_generic
;
2889 nfsm_dissect(tl
, u_long
*, 6 * NFSX_UNSIGNED
);
2890 fxdr_hyper(tl
, &toff
);
2892 fxdr_hyper(tl
, &verf
);
2894 siz
= fxdr_unsigned(int, *tl
++);
2895 cnt
= fxdr_unsigned(int, *tl
);
2897 siz
= ((siz
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
2898 xfer
= NFS_SRVMAXDATA(nfsd
);
2902 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
2903 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
2904 nfsm_reply(NFSX_UNSIGNED
);
2905 nfsm_srvpostop_attr(getret
, &at
);
2908 error
= getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2909 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
2910 error
= NFSERR_BAD_COOKIE
;
2912 nqsrv_getl(vp
, ND_READ
);
2913 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 0);
2917 nfsm_reply(NFSX_V3POSTOPATTR
);
2918 nfsm_srvpostop_attr(getret
, &at
);
2921 VOP_UNLOCK(vp
, 0, procp
);
2922 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
2925 iv
.iov_len
= fullsiz
;
2928 io
.uio_offset
= (off_t
)off
;
2929 io
.uio_resid
= fullsiz
;
2930 io
.uio_segflg
= UIO_SYSSPACE
;
2931 io
.uio_rw
= UIO_READ
;
2932 io
.uio_procp
= (struct proc
*)0;
2935 _FREE((caddr_t
)cookies
, M_TEMP
);
2938 if (error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, procp
)) {
2939 FREE((caddr_t
)rbuf
, M_TEMP
);
2940 nfsm_reply(NFSX_V3POSTOPATTR
);
2941 nfsm_srvpostop_attr(getret
, &at
);
2944 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
2945 off
= (u_quad_t
)io
.uio_offset
;
2946 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2947 VOP_UNLOCK(vp
, 0, procp
);
2949 * See nfsrv_readdir comment above on this
2951 if ((ncookies
!= 0) && !cookies
&& !error
)
2952 error
= NFSERR_PERM
;
2959 _FREE((caddr_t
)cookies
, M_TEMP
);
2960 _FREE((caddr_t
)rbuf
, M_TEMP
);
2961 nfsm_reply(NFSX_V3POSTOPATTR
);
2962 nfsm_srvpostop_attr(getret
, &at
);
2966 siz
-= io
.uio_resid
;
2969 * If nothing read, return eof
2974 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+
2976 nfsm_srvpostop_attr(getret
, &at
);
2977 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
2978 txdr_hyper(&at
.va_filerev
, tl
);
2982 FREE((caddr_t
)cookies
, M_TEMP
);
2983 FREE((caddr_t
)rbuf
, M_TEMP
);
2989 * Check for degenerate cases of nothing useful read.
2990 * If so go try again
2994 dp
= (struct dirent
*)cpos
;
2998 * For some reason FreeBSD's ufs_readdir() chooses to back the
2999 * directory offset up to a block boundary, so it is necessary to
3000 * skip over the records that preceed the requested offset. This
3001 * requires the assumption that file offset cookies monotonically
3004 while (cpos
< cend
&& ncookies
> 0 &&
3005 (dp
->d_fileno
== 0 || ((u_quad_t
)(*cookiep
)) <= toff
)) {
3007 while (dp
->d_fileno
== 0 && cpos
< cend
&& ncookies
> 0) {
3009 cpos
+= dp
->d_reclen
;
3010 dp
= (struct dirent
*)cpos
;
3014 if (cpos
>= cend
|| ncookies
== 0) {
3021 * Probe one of the directory entries to see if the filesystem
3022 * supports VGET. See later comment for VFS_VGET changes.
3024 if (vp
->v_tag
== VT_UFS
)
3025 file
= (void *) dp
->d_fileno
;
3027 file
= &dp
->d_fileno
;
3030 if (error
= VFS_VGET(vp
->v_mount
, file
, &nvp
)) {
3031 if (error
== EOPNOTSUPP
) /* let others get passed back */
3032 error
= NFSERR_NOTSUPP
;
3034 _FREE((caddr_t
)cookies
, M_TEMP
);
3035 _FREE((caddr_t
)rbuf
, M_TEMP
);
3036 nfsm_reply(NFSX_V3POSTOPATTR
);
3037 nfsm_srvpostop_attr(getret
, &at
);
3042 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3044 nfsm_srvpostop_attr(getret
, &at
);
3045 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3046 txdr_hyper(&at
.va_filerev
, tl
);
3049 be
= bp
+ M_TRAILINGSPACE(mp
);
3051 /* Loop through the records and build reply */
3052 while (cpos
< cend
&& ncookies
> 0) {
3053 if (dp
->d_fileno
!= 0) {
3054 nlen
= dp
->d_namlen
;
3055 rem
= nfsm_rndup(nlen
)-nlen
;
3058 * Got to get the vnode for lookup per entry.
3059 * HFS+/volfs and others use address of file identifier to VGET
3060 * UFS, nullfs, umapfs use inode (u_int32_t)
3061 * until they are consistent, we must differentiate now.
3062 * UFS is the only one of the latter class that is exported.
3063 * Note this will be pulled out as we resolve the VGET issue
3064 * of which it should use u_in32_t or addresses.
3067 if (vp
->v_tag
== VT_UFS
)
3068 file
= (void *) dp
->d_fileno
;
3070 file
= &dp
->d_fileno
;
3072 if (VFS_VGET(vp
->v_mount
, file
, &nvp
))
3074 bzero((caddr_t
)nfhp
, NFSX_V3FH
);
3076 nvp
->v_mount
->mnt_stat
.f_fsid
;
3077 if (VFS_VPTOFH(nvp
, &nfhp
->fh_fid
)) {
3081 if (VOP_GETATTR(nvp
, vap
, cred
, procp
)) {
3088 * If either the dircount or maxcount will be
3089 * exceeded, get out now. Both of these lengths
3090 * are calculated conservatively, including all
3093 len
+= (7 * NFSX_UNSIGNED
+ nlen
+ rem
+ NFSX_V3FH
+
3095 dirlen
+= (6 * NFSX_UNSIGNED
+ nlen
+ rem
);
3096 if (len
> cnt
|| dirlen
> fullsiz
) {
3102 * Build the directory record xdr from
3105 fp
= (struct nfs_fattr
*)&fl
.fl_fattr
;
3106 nfsm_srvfillattr(vap
, fp
);
3107 fl
.fl_fhsize
= txdr_unsigned(NFSX_V3FH
);
3108 fl
.fl_fhok
= nfs_true
;
3109 fl
.fl_postopok
= nfs_true
;
3110 fl
.fl_off
.nfsuquad
[0] = 0;
3111 fl
.fl_off
.nfsuquad
[1] = txdr_unsigned(*cookiep
);
3115 bp
+= NFSX_UNSIGNED
;
3118 bp
+= NFSX_UNSIGNED
;
3120 *tl
= txdr_unsigned(dp
->d_fileno
);
3121 bp
+= NFSX_UNSIGNED
;
3123 *tl
= txdr_unsigned(nlen
);
3124 bp
+= NFSX_UNSIGNED
;
3126 /* And loop around copying the name */
3131 if ((bp
+ xfer
) > be
)
3135 bcopy(cp
, bp
, tsiz
);
3141 /* And null pad to a long boundary */
3142 for (i
= 0; i
< rem
; i
++)
3146 * Now copy the flrep structure out.
3148 xfer
= sizeof (struct flrep
);
3152 if ((bp
+ xfer
) > be
)
3156 bcopy(cp
, bp
, tsiz
);
3164 cpos
+= dp
->d_reclen
;
3165 dp
= (struct dirent
*)cpos
;
3172 bp
+= NFSX_UNSIGNED
;
3178 bp
+= NFSX_UNSIGNED
;
3181 mp
->m_len
= bp
- mtod(mp
, caddr_t
);
3183 mp
->m_len
+= bp
- bpos
;
3184 FREE((caddr_t
)cookies
, M_TEMP
);
3185 FREE((caddr_t
)rbuf
, M_TEMP
);
3190 * nfs commit service
3193 nfsrv_commit(nfsd
, slp
, procp
, mrq
)
3194 struct nfsrv_descript
*nfsd
;
3195 struct nfssvc_sock
*slp
;
3199 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3200 struct mbuf
*nam
= nfsd
->nd_nam
;
3201 caddr_t dpos
= nfsd
->nd_dpos
;
3202 struct ucred
*cred
= &nfsd
->nd_cr
;
3203 struct vattr bfor
, aft
;
3207 register u_long
*tl
;
3210 int error
= 0, rdonly
, for_ret
= 1, aft_ret
= 1, cnt
, cache
;
3212 struct mbuf
*mb
, *mb2
, *mreq
;
3218 fhp
= &nfh
.fh_generic
;
3220 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
3223 * XXX At this time VOP_FSYNC() does not accept offset and byte
3224 * count parameters, so these arguments are useless (someday maybe).
3226 fxdr_hyper(tl
, &off
);
3228 cnt
= fxdr_unsigned(int, *tl
);
3229 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3230 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3231 nfsm_reply(2 * NFSX_UNSIGNED
);
3232 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
3235 for_ret
= VOP_GETATTR(vp
, &bfor
, cred
, procp
);
3236 error
= VOP_FSYNC(vp
, cred
, MNT_WAIT
, procp
);
3237 aft_ret
= VOP_GETATTR(vp
, &aft
, cred
, procp
);
3239 nfsm_reply(NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
3240 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
3242 nfsm_build(tl
, u_long
*, NFSX_V3WRITEVERF
);
3243 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
3244 *tl
= txdr_unsigned(boottime
.tv_usec
);
3251 * nfs statfs service
3254 nfsrv_statfs(nfsd
, slp
, procp
, mrq
)
3255 struct nfsrv_descript
*nfsd
;
3256 struct nfssvc_sock
*slp
;
3260 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3261 struct mbuf
*nam
= nfsd
->nd_nam
;
3262 caddr_t dpos
= nfsd
->nd_dpos
;
3263 struct ucred
*cred
= &nfsd
->nd_cr
;
3264 register struct statfs
*sf
;
3265 register struct nfs_statfs
*sfp
;
3266 register u_long
*tl
;
3269 int error
= 0, rdonly
, cache
, getret
= 1;
3270 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3272 struct mbuf
*mb
, *mb2
, *mreq
;
3277 struct statfs statfs
;
3278 u_quad_t frev
, tval
;
3283 fhp
= &nfh
.fh_generic
;
3285 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3286 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3287 nfsm_reply(NFSX_UNSIGNED
);
3288 nfsm_srvpostop_attr(getret
, &at
);
3292 error
= VFS_STATFS(vp
->v_mount
, sf
, procp
);
3293 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
3295 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_STATFS(v3
));
3297 nfsm_srvpostop_attr(getret
, &at
);
3300 nfsm_build(sfp
, struct nfs_statfs
*, NFSX_STATFS(v3
));
3302 tval
= (u_quad_t
)sf
->f_blocks
;
3303 tval
*= (u_quad_t
)sf
->f_bsize
;
3304 txdr_hyper(&tval
, &sfp
->sf_tbytes
);
3305 tval
= (u_quad_t
)sf
->f_bfree
;
3306 tval
*= (u_quad_t
)sf
->f_bsize
;
3307 txdr_hyper(&tval
, &sfp
->sf_fbytes
);
3308 tval
= (u_quad_t
)sf
->f_bavail
;
3309 tval
*= (u_quad_t
)sf
->f_bsize
;
3310 txdr_hyper(&tval
, &sfp
->sf_abytes
);
3311 sfp
->sf_tfiles
.nfsuquad
[0] = 0;
3312 sfp
->sf_tfiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_files
);
3313 sfp
->sf_ffiles
.nfsuquad
[0] = 0;
3314 sfp
->sf_ffiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3315 sfp
->sf_afiles
.nfsuquad
[0] = 0;
3316 sfp
->sf_afiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3317 sfp
->sf_invarsec
= 0;
3319 sfp
->sf_tsize
= txdr_unsigned(NFS_MAXDGRAMDATA
);
3320 sfp
->sf_bsize
= txdr_unsigned(sf
->f_bsize
);
3321 sfp
->sf_blocks
= txdr_unsigned(sf
->f_blocks
);
3322 sfp
->sf_bfree
= txdr_unsigned(sf
->f_bfree
);
3323 sfp
->sf_bavail
= txdr_unsigned(sf
->f_bavail
);
3329 * nfs fsinfo service
3332 nfsrv_fsinfo(nfsd
, slp
, procp
, mrq
)
3333 struct nfsrv_descript
*nfsd
;
3334 struct nfssvc_sock
*slp
;
3338 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3339 struct mbuf
*nam
= nfsd
->nd_nam
;
3340 caddr_t dpos
= nfsd
->nd_dpos
;
3341 struct ucred
*cred
= &nfsd
->nd_cr
;
3342 register u_long
*tl
;
3343 register struct nfsv3_fsinfo
*sip
;
3346 int error
= 0, rdonly
, cache
, getret
= 1, pref
;
3348 struct mbuf
*mb
, *mb2
, *mreq
;
3358 fhp
= &nfh
.fh_generic
;
3360 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3361 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3362 nfsm_reply(NFSX_UNSIGNED
);
3363 nfsm_srvpostop_attr(getret
, &at
);
3366 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
3368 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
3369 nfsm_srvpostop_attr(getret
, &at
);
3370 nfsm_build(sip
, struct nfsv3_fsinfo
*, NFSX_V3FSINFO
);
3374 * There should be file system VFS OP(s) to get this information.
3375 * For now, assume ufs.
3377 if (slp
->ns_so
->so_type
== SOCK_DGRAM
)
3378 pref
= NFS_MAXDGRAMDATA
;
3381 sip
->fs_rtmax
= txdr_unsigned(NFS_MAXDATA
);
3382 sip
->fs_rtpref
= txdr_unsigned(pref
);
3383 sip
->fs_rtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3384 sip
->fs_wtmax
= txdr_unsigned(NFS_MAXDATA
);
3385 sip
->fs_wtpref
= txdr_unsigned(pref
);
3386 sip
->fs_wtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3387 sip
->fs_dtpref
= txdr_unsigned(pref
);
3388 sip
->fs_maxfilesize
.nfsuquad
[0] = 0xffffffff;
3389 sip
->fs_maxfilesize
.nfsuquad
[1] = 0xffffffff;
3390 sip
->fs_timedelta
.nfsv3_sec
= 0;
3391 sip
->fs_timedelta
.nfsv3_nsec
= txdr_unsigned(1);
3392 sip
->fs_properties
= txdr_unsigned(NFSV3FSINFO_LINK
|
3393 NFSV3FSINFO_SYMLINK
| NFSV3FSINFO_HOMOGENEOUS
|
3394 NFSV3FSINFO_CANSETTIME
);
3399 * nfs pathconf service
3402 nfsrv_pathconf(nfsd
, slp
, procp
, mrq
)
3403 struct nfsrv_descript
*nfsd
;
3404 struct nfssvc_sock
*slp
;
3408 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3409 struct mbuf
*nam
= nfsd
->nd_nam
;
3410 caddr_t dpos
= nfsd
->nd_dpos
;
3411 struct ucred
*cred
= &nfsd
->nd_cr
;
3412 register u_long
*tl
;
3413 register struct nfsv3_pathconf
*pc
;
3416 int error
= 0, rdonly
, cache
, getret
= 1, linkmax
, namemax
;
3417 int chownres
, notrunc
;
3419 struct mbuf
*mb
, *mb2
, *mreq
;
3429 fhp
= &nfh
.fh_generic
;
3431 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3432 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3433 nfsm_reply(NFSX_UNSIGNED
);
3434 nfsm_srvpostop_attr(getret
, &at
);
3437 error
= VOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
);
3439 error
= VOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
);
3441 error
= VOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
);
3443 error
= VOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
);
3444 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
3446 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
3447 nfsm_srvpostop_attr(getret
, &at
);
3450 nfsm_build(pc
, struct nfsv3_pathconf
*, NFSX_V3PATHCONF
);
3452 pc
->pc_linkmax
= txdr_unsigned(linkmax
);
3453 pc
->pc_namemax
= txdr_unsigned(namemax
);
3454 pc
->pc_notrunc
= txdr_unsigned(notrunc
);
3455 pc
->pc_chownrestricted
= txdr_unsigned(chownres
);
3458 * These should probably be supported by VOP_PATHCONF(), but
3459 * until msdosfs is exportable (why would you want to?), the
3460 * Unix defaults should be ok.
3462 pc
->pc_caseinsensitive
= nfs_false
;
3463 pc
->pc_casepreserving
= nfs_true
;
3468 * Null operation, used by clients to ping server
3472 nfsrv_null(nfsd
, slp
, procp
, mrq
)
3473 struct nfsrv_descript
*nfsd
;
3474 struct nfssvc_sock
*slp
;
3478 struct mbuf
*mrep
= nfsd
->nd_mrep
;
3480 int error
= NFSERR_RETVOID
, cache
;
3481 struct mbuf
*mb
, *mreq
;
3492 * No operation, used for obsolete procedures
3496 nfsrv_noop(nfsd
, slp
, procp
, mrq
)
3497 struct nfsrv_descript
*nfsd
;
3498 struct nfssvc_sock
*slp
;
3502 struct mbuf
*mrep
= nfsd
->nd_mrep
;
3505 struct mbuf
*mb
, *mreq
;
3511 if (nfsd
->nd_repstat
)
3512 error
= nfsd
->nd_repstat
;
3514 error
= EPROCUNAVAIL
;
3520 * Perform access checking for vnodes obtained from file handles that would
3521 * refer to files already opened by a Unix client. You cannot just use
3522 * vn_writechk() and VOP_ACCESS() for two reasons.
3523 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3524 * 2 - The owner is to be given access irrespective of mode bits so that
3525 * processes that chmod after opening a file don't break. I don't like
3526 * this because it opens a security hole, but since the nfs server opens
3527 * a security hole the size of a barn door anyhow, what the heck.
3529 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
3530 * will return EPERM instead of EACCESS. EPERM is always an error.
3534 nfsrv_access(vp
, flags
, cred
, rdonly
, p
, override
)
3535 register struct vnode
*vp
;
3537 register struct ucred
*cred
;
3544 if (flags
& VWRITE
) {
3545 /* Just vn_writechk() changed to check rdonly */
3547 * Disallow write attempts on read-only file systems;
3548 * unless the file is a socket or a block or character
3549 * device resident on the file system.
3551 if (rdonly
|| (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
3552 switch (vp
->v_type
) {
3553 case VREG
: case VDIR
: case VLNK
: case VCPLX
:
3558 * If there's shared text associated with
3559 * the inode, we can't allow writing.
3561 if (vp
->v_flag
& VTEXT
)
3564 if ((error
= VOP_GETATTR(vp
, &vattr
, cred
, p
)))
3566 error
= VOP_ACCESS(vp
, flags
, cred
, p
);
3568 * Allow certain operations for the owner (reads and writes
3569 * on files that are already open). Picking up from FreeBSD.
3571 if (override
&& error
== EACCES
&& cred
->cr_uid
== vattr
.va_uid
)
3575 #endif /* NFS_NOSERVER */