]>
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 * 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 vrele() or vput()'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/namei.h>
86 #include <sys/unistd.h>
87 #include <sys/malloc.h>
88 #include <sys/vnode.h>
89 #include <sys/mount.h>
90 #include <sys/socket.h>
91 #include <sys/socketvar.h>
93 #include <sys/dirent.h>
95 #include <sys/kernel.h>
96 #include <sys/sysctl.h>
99 #include <ufs/ufs/dir.h>
102 #include <sys/vmparam.h>
103 #include <machine/spl.h>
105 #include <nfs/nfsproto.h>
106 #include <nfs/rpcv2.h>
108 #include <nfs/xdr_subs.h>
109 #include <nfs/nfsm_subs.h>
110 #include <nfs/nqnfs.h>
112 nfstype nfsv3_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFSOCK
,
115 nfstype nfsv2_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFNON
,
118 extern u_long nfs_xdrneg1
;
119 extern u_long nfs_false
, nfs_true
;
120 extern enum vtype nv3tov_type
[8];
121 extern struct nfsstats nfsstats
;
123 int nfsrvw_procrastinate
= NFS_GATHERDELAY
* 1000;
124 int nfsrvw_procrastinate_v3
= 0;
128 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
129 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, async
, CTLFLAG_RW
, &nfs_async
, 0, "");
132 static int nfsrv_access
__P((struct vnode
*,int,struct ucred
*,int,
133 struct proc
*, int));
134 static void nfsrvw_coalesce
__P((struct nfsrv_descript
*,
135 struct nfsrv_descript
*));
138 * nfs v3 access service
141 nfsrv3_access(nfsd
, slp
, procp
, mrq
)
142 struct nfsrv_descript
*nfsd
;
143 struct nfssvc_sock
*slp
;
147 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
148 struct mbuf
*nam
= nfsd
->nd_nam
;
149 caddr_t dpos
= nfsd
->nd_dpos
;
150 struct ucred
*cred
= &nfsd
->nd_cr
;
157 int error
= 0, rdonly
, cache
, getret
;
159 struct mbuf
*mb
, *mreq
, *mb2
;
160 struct vattr vattr
, *vap
= &vattr
;
161 u_long testmode
, nfsmode
;
167 fhp
= &nfh
.fh_generic
;
169 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
170 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
171 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
172 nfsm_reply(NFSX_UNSIGNED
);
173 nfsm_srvpostop_attr(1, (struct vattr
*)0);
176 nfsmode
= fxdr_unsigned(u_long
, *tl
);
177 if ((nfsmode
& NFSV3ACCESS_READ
) &&
178 nfsrv_access(vp
, VREAD
, cred
, rdonly
, procp
, 0))
179 nfsmode
&= ~NFSV3ACCESS_READ
;
180 if (vp
->v_type
== VDIR
)
181 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
|
184 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
);
185 if ((nfsmode
& testmode
) &&
186 nfsrv_access(vp
, VWRITE
, cred
, rdonly
, procp
, 0))
187 nfsmode
&= ~testmode
;
188 if (vp
->v_type
== VDIR
)
189 testmode
= NFSV3ACCESS_LOOKUP
;
191 testmode
= NFSV3ACCESS_EXECUTE
;
192 if ((nfsmode
& testmode
) &&
193 nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 0))
194 nfsmode
&= ~testmode
;
195 getret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
197 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED
);
198 nfsm_srvpostop_attr(getret
, vap
);
199 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
200 *tl
= txdr_unsigned(nfsmode
);
205 * nfs getattr service
208 nfsrv_getattr(nfsd
, slp
, procp
, mrq
)
209 struct nfsrv_descript
*nfsd
;
210 struct nfssvc_sock
*slp
;
214 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
215 struct mbuf
*nam
= nfsd
->nd_nam
;
216 caddr_t dpos
= nfsd
->nd_dpos
;
217 struct ucred
*cred
= &nfsd
->nd_cr
;
218 register struct nfs_fattr
*fp
;
220 register struct vattr
*vap
= &va
;
227 int error
= 0, rdonly
, cache
;
229 struct mbuf
*mb
, *mb2
, *mreq
;
232 fhp
= &nfh
.fh_generic
;
234 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
235 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
239 nqsrv_getl(vp
, ND_READ
);
240 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
242 nfsm_reply(NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
245 nfsm_build(fp
, struct nfs_fattr
*, NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
246 nfsm_srvfillattr(vap
, fp
);
251 * nfs setattr service
254 nfsrv_setattr(nfsd
, slp
, procp
, mrq
)
255 struct nfsrv_descript
*nfsd
;
256 struct nfssvc_sock
*slp
;
260 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
261 struct mbuf
*nam
= nfsd
->nd_nam
;
262 caddr_t dpos
= nfsd
->nd_dpos
;
263 struct ucred
*cred
= &nfsd
->nd_cr
;
264 struct vattr va
, preat
;
265 register struct vattr
*vap
= &va
;
266 register struct nfsv2_sattr
*sp
;
267 register struct nfs_fattr
*fp
;
274 int error
= 0, rdonly
, cache
, preat_ret
= 1, postat_ret
= 1;
275 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), gcheck
= 0;
277 struct mbuf
*mb
, *mb2
, *mreq
;
279 struct timespec guard
;
281 fhp
= &nfh
.fh_generic
;
286 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
287 gcheck
= fxdr_unsigned(int, *tl
);
289 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
290 fxdr_nfsv3time(tl
, &guard
);
293 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
295 * Nah nah nah nah na nah
296 * There is a bug in the Sun client that puts 0xffff in the mode
297 * field of sattr when it should put in 0xffffffff. The u_short
298 * doesn't sign extend.
299 * --> check the low order 2 bytes for 0xffff
301 if ((fxdr_unsigned(int, sp
->sa_mode
) & 0xffff) != 0xffff)
302 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
303 if (sp
->sa_uid
!= nfs_xdrneg1
)
304 vap
->va_uid
= fxdr_unsigned(uid_t
, sp
->sa_uid
);
305 if (sp
->sa_gid
!= nfs_xdrneg1
)
306 vap
->va_gid
= fxdr_unsigned(gid_t
, sp
->sa_gid
);
307 if (sp
->sa_size
!= nfs_xdrneg1
)
308 vap
->va_size
= fxdr_unsigned(u_quad_t
, sp
->sa_size
);
309 if (sp
->sa_atime
.nfsv2_sec
!= nfs_xdrneg1
) {
311 fxdr_nfsv2time(&sp
->sa_atime
, &vap
->va_atime
);
313 vap
->va_atime
.tv_sec
=
314 fxdr_unsigned(long, sp
->sa_atime
.nfsv2_sec
);
315 vap
->va_atime
.tv_nsec
= 0;
318 if (sp
->sa_mtime
.nfsv2_sec
!= nfs_xdrneg1
)
319 fxdr_nfsv2time(&sp
->sa_mtime
, &vap
->va_mtime
);
324 * Now that we have all the fields, lets do it.
326 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
327 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
328 nfsm_reply(2 * NFSX_UNSIGNED
);
329 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
332 nqsrv_getl(vp
, ND_WRITE
);
334 error
= preat_ret
= VOP_GETATTR(vp
, &preat
, cred
, procp
);
335 if (!error
&& gcheck
&&
336 (preat
.va_ctime
.tv_sec
!= guard
.tv_sec
||
337 preat
.va_ctime
.tv_nsec
!= guard
.tv_nsec
))
338 error
= NFSERR_NOT_SYNC
;
341 nfsm_reply(NFSX_WCCDATA(v3
));
342 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
348 * If the size is being changed write acces is required, otherwise
349 * just check for a read only file system.
351 if (vap
->va_size
== ((u_quad_t
)((quad_t
) -1))) {
352 if (rdonly
|| (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
357 if (vp
->v_type
== VDIR
) {
360 } else if ((error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
,
364 error
= VOP_SETATTR(vp
, vap
, cred
, procp
);
365 postat_ret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
370 nfsm_reply(NFSX_WCCORFATTR(v3
));
372 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
375 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
376 nfsm_srvfillattr(vap
, fp
);
385 nfsrv_lookup(nfsd
, slp
, procp
, mrq
)
386 struct nfsrv_descript
*nfsd
;
387 struct nfssvc_sock
*slp
;
391 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
392 struct mbuf
*nam
= nfsd
->nd_nam
;
393 caddr_t dpos
= nfsd
->nd_dpos
;
394 struct ucred
*cred
= &nfsd
->nd_cr
;
395 register struct nfs_fattr
*fp
;
396 struct nameidata nd
, *ndp
= &nd
;
398 struct nameidata ind
;
400 struct vnode
*vp
, *dirp
;
407 int error
= 0, cache
, len
, dirattr_ret
= 1;
408 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), pubflag
;
410 struct mbuf
*mb
, *mb2
, *mreq
;
411 struct vattr va
, dirattr
, *vap
= &va
;
414 fhp
= &nfh
.fh_generic
;
416 nfsm_srvnamesiz(len
);
418 pubflag
= nfs_ispublicfh(fhp
);
420 nd
.ni_cnd
.cn_cred
= cred
;
421 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
422 nd
.ni_cnd
.cn_flags
= LOCKLEAF
| SAVESTART
;
423 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
424 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), pubflag
);
426 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
428 if (!error
&& pubflag
) {
429 if (nd
.ni_vp
->v_type
== VDIR
&& nfs_pub
.np_index
!= NULL
) {
431 * Setup call to lookup() to see if we can find
432 * the index file. Arguably, this doesn't belong
436 VOP_UNLOCK(nd
.ni_vp
, 0, procp
);
437 ind
.ni_pathlen
= strlen(nfs_pub
.np_index
);
438 ind
.ni_cnd
.cn_nameptr
= ind
.ni_cnd
.cn_pnbuf
=
440 ind
.ni_startdir
= nd
.ni_vp
;
441 VREF(ind
.ni_startdir
);
442 error
= lookup(&ind
);
445 * Found an index file. Get rid of
446 * the old references.
451 vrele(nd
.ni_startdir
);
457 * If the public filehandle was used, check that this lookup
458 * didn't result in a filehandle outside the publicly exported
462 if (!error
&& ndp
->ni_vp
->v_mount
!= nfs_pub
.np_mount
) {
471 dirattr_ret
= VOP_GETATTR(dirp
, &dirattr
, cred
,
477 nfsm_reply(NFSX_POSTOPATTR(v3
));
478 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
482 nqsrv_getl(ndp
->ni_startdir
, ND_READ
);
483 vrele(ndp
->ni_startdir
);
484 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
486 bzero((caddr_t
)fhp
, sizeof(nfh
));
487 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
488 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
490 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
492 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPORFATTR(v3
) + NFSX_POSTOPATTR(v3
));
494 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
497 nfsm_srvfhtom(fhp
, v3
);
499 nfsm_srvpostop_attr(0, vap
);
500 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
502 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
503 nfsm_srvfillattr(vap
, fp
);
509 * nfs readlink service
512 nfsrv_readlink(nfsd
, slp
, procp
, mrq
)
513 struct nfsrv_descript
*nfsd
;
514 struct nfssvc_sock
*slp
;
518 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
519 struct mbuf
*nam
= nfsd
->nd_nam
;
520 caddr_t dpos
= nfsd
->nd_dpos
;
521 struct ucred
*cred
= &nfsd
->nd_cr
;
522 struct iovec iv
[(NFS_MAXPATHLEN
+MLEN
-1)/MLEN
];
523 register struct iovec
*ivp
= iv
;
524 register struct mbuf
*mp
;
528 int error
= 0, rdonly
, cache
, i
, tlen
, len
, getret
;
529 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
531 struct mbuf
*mb
, *mb2
, *mp2
, *mp3
, *mreq
;
536 struct uio io
, *uiop
= &io
;
540 mp2
= mp3
= (struct mbuf
*)0;
542 fhp
= &nfh
.fh_generic
;
546 while (len
< NFS_MAXPATHLEN
) {
547 MGET(mp
, M_WAIT
, MT_DATA
);
549 mp
->m_len
= NFSMSIZ(mp
);
556 if ((len
+mp
->m_len
) > NFS_MAXPATHLEN
) {
557 mp
->m_len
= NFS_MAXPATHLEN
-len
;
558 len
= NFS_MAXPATHLEN
;
561 ivp
->iov_base
= mtod(mp
, caddr_t
);
562 ivp
->iov_len
= mp
->m_len
;
567 uiop
->uio_iovcnt
= i
;
568 uiop
->uio_offset
= 0;
569 uiop
->uio_resid
= len
;
570 uiop
->uio_rw
= UIO_READ
;
571 uiop
->uio_segflg
= UIO_SYSSPACE
;
572 uiop
->uio_procp
= (struct proc
*)0;
573 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
574 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
576 nfsm_reply(2 * NFSX_UNSIGNED
);
577 nfsm_srvpostop_attr(1, (struct vattr
*)0);
580 if (vp
->v_type
!= VLNK
) {
587 nqsrv_getl(vp
, ND_READ
);
588 error
= VOP_READLINK(vp
, uiop
, cred
);
590 getret
= VOP_GETATTR(vp
, &attr
, cred
, procp
);
594 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_UNSIGNED
);
596 nfsm_srvpostop_attr(getret
, &attr
);
600 if (uiop
->uio_resid
> 0) {
601 len
-= uiop
->uio_resid
;
602 tlen
= nfsm_rndup(len
);
603 nfsm_adj(mp3
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
605 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
606 *tl
= txdr_unsigned(len
);
615 nfsrv_read(nfsd
, slp
, procp
, mrq
)
616 struct nfsrv_descript
*nfsd
;
617 struct nfssvc_sock
*slp
;
621 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
622 struct mbuf
*nam
= nfsd
->nd_nam
;
623 caddr_t dpos
= nfsd
->nd_dpos
;
624 struct ucred
*cred
= &nfsd
->nd_cr
;
625 register struct iovec
*iv
;
627 register struct mbuf
*m
;
628 register struct nfs_fattr
*fp
;
633 int error
= 0, rdonly
, cache
, cnt
, len
, left
, siz
, tlen
, getret
;
634 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), reqlen
;
636 struct mbuf
*mb
, *mb2
, *mreq
;
641 struct uio io
, *uiop
= &io
;
642 struct vattr va
, *vap
= &va
;
646 fhp
= &nfh
.fh_generic
;
649 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
650 fxdr_hyper(tl
, &off
);
652 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
653 off
= (off_t
)fxdr_unsigned(u_long
, *tl
);
655 nfsm_srvstrsiz(reqlen
, NFS_SRVMAXDATA(nfsd
));
656 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
657 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
658 nfsm_reply(2 * NFSX_UNSIGNED
);
659 nfsm_srvpostop_attr(1, (struct vattr
*)0);
662 if (vp
->v_type
!= VREG
) {
666 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
669 nqsrv_getl(vp
, ND_READ
);
670 if ((error
= nfsrv_access(vp
, VREAD
, cred
, rdonly
, procp
, 1)))
671 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 1);
673 getret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
678 nfsm_reply(NFSX_POSTOPATTR(v3
));
679 nfsm_srvpostop_attr(getret
, vap
);
682 if (off
>= vap
->va_size
)
684 else if ((off
+ reqlen
) > vap
->va_size
)
685 cnt
= nfsm_rndup(vap
->va_size
- off
);
688 nfsm_reply(NFSX_POSTOPORFATTR(v3
) + 3 * NFSX_UNSIGNED
+nfsm_rndup(cnt
));
690 nfsm_build(tl
, u_long
*, NFSX_V3FATTR
+ 4 * NFSX_UNSIGNED
);
692 fp
= (struct nfs_fattr
*)tl
;
693 tl
+= (NFSX_V3FATTR
/ sizeof (u_long
));
695 nfsm_build(tl
, u_long
*, NFSX_V2FATTR
+ NFSX_UNSIGNED
);
696 fp
= (struct nfs_fattr
*)tl
;
697 tl
+= (NFSX_V2FATTR
/ sizeof (u_long
));
702 * Generate the mbuf list with the uio_iov ref. to it.
707 siz
= min(M_TRAILINGSPACE(m
), left
);
713 MGET(m
, M_WAIT
, MT_DATA
);
720 MALLOC(iv
, struct iovec
*, i
* sizeof (struct iovec
),
722 uiop
->uio_iov
= iv2
= iv
;
728 panic("nfsrv_read iov");
729 siz
= min(M_TRAILINGSPACE(m
), left
);
731 iv
->iov_base
= mtod(m
, caddr_t
) + m
->m_len
;
740 uiop
->uio_iovcnt
= i
;
741 uiop
->uio_offset
= off
;
742 uiop
->uio_resid
= cnt
;
743 uiop
->uio_rw
= UIO_READ
;
744 uiop
->uio_segflg
= UIO_SYSSPACE
;
745 error
= VOP_READ(vp
, uiop
, IO_NODELOCKED
, cred
);
746 off
= uiop
->uio_offset
;
747 FREE((caddr_t
)iv2
, M_TEMP
);
748 /* Though our code replaces error with getret, the way I read
749 * the v3 spec, it appears you should leave the error alone, but
750 * still return vap and not assign error = getret. But leaving
751 * that alone. m_freem(mreq) looks bogus. Taking it out. Should be
752 * mrep or not there at all. Causes panic. ekn */
753 if (error
|| (getret
= VOP_GETATTR(vp
, vap
, cred
, procp
))) {
758 nfsm_reply(NFSX_POSTOPATTR(v3
));
759 nfsm_srvpostop_attr(getret
, vap
);
765 nfsm_srvfillattr(vap
, fp
);
766 len
-= uiop
->uio_resid
;
767 tlen
= nfsm_rndup(len
);
768 if (cnt
!= tlen
|| tlen
!= len
)
769 nfsm_adj(mb
, cnt
- tlen
, tlen
- len
);
771 *tl
++ = txdr_unsigned(len
);
777 *tl
= txdr_unsigned(len
);
785 nfsrv_write(nfsd
, slp
, procp
, mrq
)
786 struct nfsrv_descript
*nfsd
;
787 struct nfssvc_sock
*slp
;
791 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
792 struct mbuf
*nam
= nfsd
->nd_nam
;
793 caddr_t dpos
= nfsd
->nd_dpos
;
794 struct ucred
*cred
= &nfsd
->nd_cr
;
795 register struct iovec
*ivp
;
797 register struct mbuf
*mp
;
798 register struct nfs_fattr
*fp
;
800 struct vattr va
, forat
;
801 register struct vattr
*vap
= &va
;
805 int error
= 0, rdonly
, cache
, len
, forat_ret
= 1;
806 int ioflags
, aftat_ret
= 1, retlen
, zeroing
, adjust
;
807 int stable
= NFSV3WRITE_FILESYNC
;
808 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
810 struct mbuf
*mb
, *mb2
, *mreq
;
814 struct uio io
, *uiop
= &io
;
822 fhp
= &nfh
.fh_generic
;
825 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
826 fxdr_hyper(tl
, &off
);
828 stable
= fxdr_unsigned(int, *tl
++);
830 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
831 off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
834 stable
= NFSV3WRITE_UNSTABLE
;
836 retlen
= len
= fxdr_unsigned(long, *tl
);
840 * For NFS Version 2, it is not obvious what a write of zero length
841 * should do, but I might as well be consistent with Version 3,
842 * which is to return ok so long as there are no permission problems.
850 adjust
= dpos
- mtod(mp
, caddr_t
);
852 if (mp
->m_len
> 0 && adjust
> 0)
857 else if (mp
->m_len
> 0) {
860 mp
->m_len
-= (i
- len
);
869 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
871 nfsm_reply(2 * NFSX_UNSIGNED
);
872 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
875 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
876 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
877 nfsm_reply(2 * NFSX_UNSIGNED
);
878 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
882 forat_ret
= VOP_GETATTR(vp
, &forat
, cred
, procp
);
883 if (vp
->v_type
!= VREG
) {
887 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
890 nqsrv_getl(vp
, ND_WRITE
);
891 error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
, procp
, 1);
895 nfsm_reply(NFSX_WCCDATA(v3
));
896 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
901 MALLOC(ivp
, struct iovec
*, cnt
* sizeof (struct iovec
), M_TEMP
,
903 uiop
->uio_iov
= iv
= ivp
;
904 uiop
->uio_iovcnt
= cnt
;
908 ivp
->iov_base
= mtod(mp
, caddr_t
);
909 ivp
->iov_len
= mp
->m_len
;
917 * The IO_METASYNC flag indicates that all metadata (and not just
918 * enough to ensure data integrity) mus be written to stable storage
920 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
922 if (stable
== NFSV3WRITE_UNSTABLE
)
923 ioflags
= IO_NODELOCKED
;
924 else if (stable
== NFSV3WRITE_DATASYNC
)
925 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
927 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
928 uiop
->uio_resid
= len
;
929 uiop
->uio_rw
= UIO_WRITE
;
930 uiop
->uio_segflg
= UIO_SYSSPACE
;
931 uiop
->uio_procp
= (struct proc
*)0;
932 uiop
->uio_offset
= off
;
933 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
934 nfsstats
.srvvop_writes
++;
935 FREE((caddr_t
)iv
, M_TEMP
);
937 aftat_ret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
941 nfsm_reply(NFSX_PREOPATTR(v3
) + NFSX_POSTOPORFATTR(v3
) +
942 2 * NFSX_UNSIGNED
+ NFSX_WRITEVERF(v3
));
944 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
947 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
948 *tl
++ = txdr_unsigned(retlen
);
950 * If nfs_async is set, then pretend the write was FILESYNC.
952 if (stable
== NFSV3WRITE_UNSTABLE
&& !nfs_async
)
953 *tl
++ = txdr_unsigned(stable
);
955 *tl
++ = txdr_unsigned(NFSV3WRITE_FILESYNC
);
957 * Actually, there is no need to txdr these fields,
958 * but it may make the values more human readable,
959 * for debugging purposes.
961 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
962 *tl
= txdr_unsigned(boottime
.tv_usec
);
964 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
965 nfsm_srvfillattr(vap
, fp
);
971 * NFS write service with write gathering support. Called when
972 * nfsrvw_procrastinate > 0.
973 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
974 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
978 nfsrv_writegather(ndp
, slp
, procp
, mrq
)
979 struct nfsrv_descript
**ndp
;
980 struct nfssvc_sock
*slp
;
984 register struct iovec
*ivp
;
985 register struct mbuf
*mp
;
986 register struct nfsrv_descript
*wp
, *nfsd
, *owp
, *swp
;
987 register struct nfs_fattr
*fp
;
990 struct nfsrvw_delayhash
*wpp
;
992 struct vattr va
, forat
;
996 int error
= 0, rdonly
, cache
, len
, forat_ret
= 1;
997 int ioflags
, aftat_ret
= 1, s
, adjust
, v3
, zeroing
;
999 struct mbuf
*mb
, *mb2
, *mreq
, *mrep
, *md
;
1001 struct uio io
, *uiop
= &io
;
1002 u_quad_t frev
, cur_usec
;
1012 mrep
= nfsd
->nd_mrep
;
1014 dpos
= nfsd
->nd_dpos
;
1015 cred
= &nfsd
->nd_cr
;
1016 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1017 LIST_INIT(&nfsd
->nd_coalesce
);
1018 nfsd
->nd_mreq
= NULL
;
1019 nfsd
->nd_stable
= NFSV3WRITE_FILESYNC
;
1020 cur_usec
= (u_quad_t
)time
.tv_sec
* 1000000 + (u_quad_t
)time
.tv_usec
;
1021 nfsd
->nd_time
= cur_usec
+
1022 (v3
? nfsrvw_procrastinate_v3
: nfsrvw_procrastinate
);
1025 * Now, get the write header..
1027 nfsm_srvmtofh(&nfsd
->nd_fh
);
1029 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1030 fxdr_hyper(tl
, &nfsd
->nd_off
);
1032 nfsd
->nd_stable
= fxdr_unsigned(int, *tl
++);
1034 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1035 nfsd
->nd_off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
1038 nfsd
->nd_stable
= NFSV3WRITE_UNSTABLE
;
1040 len
= fxdr_unsigned(long, *tl
);
1042 nfsd
->nd_eoff
= nfsd
->nd_off
+ len
;
1045 * Trim the header out of the mbuf list and trim off any trailing
1046 * junk so that the mbuf list has only the write data.
1054 adjust
= dpos
- mtod(mp
, caddr_t
);
1055 mp
->m_len
-= adjust
;
1056 if (mp
->m_len
> 0 && adjust
> 0)
1057 NFSMADV(mp
, adjust
);
1064 mp
->m_len
-= (i
- len
);
1070 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1074 nfsm_writereply(2 * NFSX_UNSIGNED
, v3
);
1076 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1077 nfsd
->nd_mreq
= mreq
;
1078 nfsd
->nd_mrep
= NULL
;
1083 * Add this entry to the hash and time queues.
1087 wp
= slp
->ns_tq
.lh_first
;
1088 while (wp
&& wp
->nd_time
< nfsd
->nd_time
) {
1090 wp
= wp
->nd_tq
.le_next
;
1092 NFS_DPF(WG
, ("Q%03x", nfsd
->nd_retxid
& 0xfff));
1094 LIST_INSERT_AFTER(owp
, nfsd
, nd_tq
);
1096 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1098 if (nfsd
->nd_mrep
) {
1099 wpp
= NWDELAYHASH(slp
, nfsd
->nd_fh
.fh_fid
.fid_data
);
1103 bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1105 wp
= wp
->nd_hash
.le_next
;
1107 while (wp
&& wp
->nd_off
< nfsd
->nd_off
&&
1108 !bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1110 wp
= wp
->nd_hash
.le_next
;
1113 LIST_INSERT_AFTER(owp
, nfsd
, nd_hash
);
1116 * Search the hash list for overlapping entries and
1119 for(; nfsd
&& NFSW_CONTIG(owp
, nfsd
); nfsd
= wp
) {
1120 wp
= nfsd
->nd_hash
.le_next
;
1121 if (NFSW_SAMECRED(owp
, nfsd
))
1122 nfsrvw_coalesce(owp
, nfsd
);
1125 LIST_INSERT_HEAD(wpp
, nfsd
, nd_hash
);
1132 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1133 * and generate the associated reply mbuf list(s).
1136 cur_usec
= (u_quad_t
)time
.tv_sec
* 1000000 + (u_quad_t
)time
.tv_usec
;
1138 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= owp
) {
1139 owp
= nfsd
->nd_tq
.le_next
;
1140 if (nfsd
->nd_time
> cur_usec
)
1144 NFS_DPF(WG
, ("P%03x", nfsd
->nd_retxid
& 0xfff));
1145 LIST_REMOVE(nfsd
, nd_tq
);
1146 LIST_REMOVE(nfsd
, nd_hash
);
1148 mrep
= nfsd
->nd_mrep
;
1149 nfsd
->nd_mrep
= NULL
;
1150 cred
= &nfsd
->nd_cr
;
1151 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1152 forat_ret
= aftat_ret
= 1;
1153 error
= nfsrv_fhtovp(&nfsd
->nd_fh
, 1, &vp
, cred
, slp
,
1154 nfsd
->nd_nam
, &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
1157 forat_ret
= VOP_GETATTR(vp
, &forat
, cred
, procp
);
1158 if (vp
->v_type
!= VREG
) {
1162 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
1167 nqsrv_getl(vp
, ND_WRITE
);
1168 error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
, procp
, 1);
1171 if (nfsd
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1172 ioflags
= IO_NODELOCKED
;
1173 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
)
1174 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1176 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1177 uiop
->uio_rw
= UIO_WRITE
;
1178 uiop
->uio_segflg
= UIO_SYSSPACE
;
1179 uiop
->uio_procp
= (struct proc
*)0;
1180 uiop
->uio_offset
= nfsd
->nd_off
;
1181 uiop
->uio_resid
= nfsd
->nd_eoff
- nfsd
->nd_off
;
1182 if (uiop
->uio_resid
> 0) {
1190 uiop
->uio_iovcnt
= i
;
1191 MALLOC(iov
, struct iovec
*, i
* sizeof (struct iovec
),
1193 uiop
->uio_iov
= ivp
= iov
;
1196 if (mp
->m_len
> 0) {
1197 ivp
->iov_base
= mtod(mp
, caddr_t
);
1198 ivp
->iov_len
= mp
->m_len
;
1204 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
1205 nfsstats
.srvvop_writes
++;
1207 FREE((caddr_t
)iov
, M_TEMP
);
1211 aftat_ret
= VOP_GETATTR(vp
, &va
, cred
, procp
);
1216 * Loop around generating replies for all write rpcs that have
1217 * now been completed.
1221 NFS_DPF(WG
, ("R%03x", nfsd
->nd_retxid
& 0xfff));
1223 nfsm_writereply(NFSX_WCCDATA(v3
), v3
);
1225 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1228 nfsm_writereply(NFSX_PREOPATTR(v3
) +
1229 NFSX_POSTOPORFATTR(v3
) + 2 * NFSX_UNSIGNED
+
1230 NFSX_WRITEVERF(v3
), v3
);
1232 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1233 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1234 *tl
++ = txdr_unsigned(nfsd
->nd_len
);
1235 *tl
++ = txdr_unsigned(swp
->nd_stable
);
1237 * Actually, there is no need to txdr these fields,
1238 * but it may make the values more human readable,
1239 * for debugging purposes.
1241 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
1242 *tl
= txdr_unsigned(boottime
.tv_usec
);
1244 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1245 nfsm_srvfillattr(&va
, fp
);
1248 nfsd
->nd_mreq
= mreq
;
1250 panic("nfsrv_write: nd_mrep not free");
1253 * Done. Put it at the head of the timer queue so that
1254 * the final phase can return the reply.
1259 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1261 nfsd
= swp
->nd_coalesce
.lh_first
;
1263 LIST_REMOVE(nfsd
, nd_tq
);
1269 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1276 * Search for a reply to return.
1279 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= nfsd
->nd_tq
.le_next
)
1280 if (nfsd
->nd_mreq
) {
1281 NFS_DPF(WG
, ("X%03x", nfsd
->nd_retxid
& 0xfff));
1282 LIST_REMOVE(nfsd
, nd_tq
);
1283 *mrq
= nfsd
->nd_mreq
;
1292 * Coalesce the write request nfsd into owp. To do this we must:
1293 * - remove nfsd from the queues
1294 * - merge nfsd->nd_mrep into owp->nd_mrep
1295 * - update the nd_eoff and nd_stable for owp
1296 * - put nfsd on owp's nd_coalesce list
1297 * NB: Must be called at splsoftclock().
1300 nfsrvw_coalesce(owp
, nfsd
)
1301 register struct nfsrv_descript
*owp
;
1302 register struct nfsrv_descript
*nfsd
;
1304 register int overlap
;
1305 register struct mbuf
*mp
;
1306 struct nfsrv_descript
*p
;
1308 NFS_DPF(WG
, ("C%03x-%03x",
1309 nfsd
->nd_retxid
& 0xfff, owp
->nd_retxid
& 0xfff));
1310 LIST_REMOVE(nfsd
, nd_hash
);
1311 LIST_REMOVE(nfsd
, nd_tq
);
1312 if (owp
->nd_eoff
< nfsd
->nd_eoff
) {
1313 overlap
= owp
->nd_eoff
- nfsd
->nd_off
;
1315 panic("nfsrv_coalesce: bad off");
1317 m_adj(nfsd
->nd_mrep
, overlap
);
1321 mp
->m_next
= nfsd
->nd_mrep
;
1322 owp
->nd_eoff
= nfsd
->nd_eoff
;
1324 m_freem(nfsd
->nd_mrep
);
1325 nfsd
->nd_mrep
= NULL
;
1326 if (nfsd
->nd_stable
== NFSV3WRITE_FILESYNC
)
1327 owp
->nd_stable
= NFSV3WRITE_FILESYNC
;
1328 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
&&
1329 owp
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1330 owp
->nd_stable
= NFSV3WRITE_DATASYNC
;
1331 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nfsd
, nd_tq
);
1334 * If nfsd had anything else coalesced into it, transfer them
1335 * to owp, otherwise their replies will never get sent.
1337 for (p
= nfsd
->nd_coalesce
.lh_first
; p
;
1338 p
= nfsd
->nd_coalesce
.lh_first
) {
1339 LIST_REMOVE(p
, nd_tq
);
1340 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1345 * Sort the group list in increasing numerical order.
1346 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1347 * that used to be here.)
1350 nfsrvw_sort(list
, num
)
1351 register gid_t
*list
;
1357 /* Insertion sort. */
1358 for (i
= 1; i
< num
; i
++) {
1360 /* find correct slot for value v, moving others up */
1361 for (j
= i
; --j
>= 0 && v
< list
[j
];)
1362 list
[j
+ 1] = list
[j
];
1368 * copy credentials making sure that the result can be compared with bcmp().
1371 nfsrv_setcred(incred
, outcred
)
1372 register struct ucred
*incred
, *outcred
;
1376 bzero((caddr_t
)outcred
, sizeof (struct ucred
));
1377 outcred
->cr_ref
= 1;
1378 outcred
->cr_uid
= incred
->cr_uid
;
1379 outcred
->cr_ngroups
= incred
->cr_ngroups
;
1380 for (i
= 0; i
< incred
->cr_ngroups
; i
++)
1381 outcred
->cr_groups
[i
] = incred
->cr_groups
[i
];
1382 nfsrvw_sort(outcred
->cr_groups
, outcred
->cr_ngroups
);
1386 * nfs create service
1387 * now does a truncate to 0 length via. setattr if it already exists
1390 nfsrv_create(nfsd
, slp
, procp
, mrq
)
1391 struct nfsrv_descript
*nfsd
;
1392 struct nfssvc_sock
*slp
;
1396 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1397 struct mbuf
*nam
= nfsd
->nd_nam
;
1398 caddr_t dpos
= nfsd
->nd_dpos
;
1399 struct ucred
*cred
= &nfsd
->nd_cr
;
1400 register struct nfs_fattr
*fp
;
1401 struct vattr va
, dirfor
, diraft
;
1402 register struct vattr
*vap
= &va
;
1403 register struct nfsv2_sattr
*sp
;
1404 register u_long
*tl
;
1405 struct nameidata nd
;
1406 register caddr_t cp
;
1409 int error
= 0, rdev
, cache
, len
, tsize
, dirfor_ret
= 1, diraft_ret
= 1;
1410 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), how
, exclusive_flag
= 0;
1412 struct mbuf
*mb
, *mb2
, *mreq
;
1413 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
1416 u_quad_t frev
, tempsize
;
1417 u_char cverf
[NFSX_V3CREATEVERF
];
1422 nd
.ni_cnd
.cn_nameiop
= 0;
1423 fhp
= &nfh
.fh_generic
;
1425 nfsm_srvnamesiz(len
);
1426 nd
.ni_cnd
.cn_cred
= cred
;
1427 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1428 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| SAVESTART
;
1429 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
1430 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1433 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
1437 dirp
= (struct vnode
*)0;
1441 nfsm_reply(NFSX_WCCDATA(v3
));
1442 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1449 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
1450 how
= fxdr_unsigned(int, *tl
);
1452 case NFSV3CREATE_GUARDED
:
1457 case NFSV3CREATE_UNCHECKED
:
1460 case NFSV3CREATE_EXCLUSIVE
:
1461 nfsm_dissect(cp
, caddr_t
, NFSX_V3CREATEVERF
);
1462 bcopy(cp
, cverf
, NFSX_V3CREATEVERF
);
1464 if (nd
.ni_vp
== NULL
)
1468 vap
->va_type
= VREG
;
1470 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1471 vap
->va_type
= IFTOVT(fxdr_unsigned(u_long
, sp
->sa_mode
));
1472 if (vap
->va_type
== VNON
)
1473 vap
->va_type
= VREG
;
1474 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
1475 switch (vap
->va_type
) {
1477 tsize
= fxdr_unsigned(long, sp
->sa_size
);
1479 vap
->va_size
= (u_quad_t
)tsize
;
1484 rdev
= fxdr_unsigned(long, sp
->sa_size
);
1490 * Iff doesn't exist, create it
1491 * otherwise just truncate to 0 length
1492 * should I set the mode too ??
1494 if (nd
.ni_vp
== NULL
) {
1495 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1496 vrele(nd
.ni_startdir
);
1497 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1498 error
= VOP_CREATE(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
);
1500 nfsrv_object_create(nd
.ni_vp
);
1501 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1502 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1503 if (exclusive_flag
) {
1506 bcopy(cverf
, (caddr_t
)&vap
->va_atime
,
1508 error
= VOP_SETATTR(nd
.ni_vp
, vap
, cred
,
1512 } else if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
||
1513 vap
->va_type
== VFIFO
) {
1514 if (vap
->va_type
== VCHR
&& rdev
== 0xffffffff)
1515 vap
->va_type
= VFIFO
;
1516 if (vap
->va_type
!= VFIFO
&&
1517 (error
= suser(cred
, (u_short
*)0))) {
1518 vrele(nd
.ni_startdir
);
1519 _FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1520 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1521 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1526 vap
->va_rdev
= (dev_t
)rdev
;
1527 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1528 if ((error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
))) {
1529 vrele(nd
.ni_startdir
);
1532 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1533 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| SAVESTART
);
1534 nd
.ni_cnd
.cn_proc
= procp
;
1535 nd
.ni_cnd
.cn_cred
= cred
;
1536 if ((error
= lookup(&nd
))) {
1537 _FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1538 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1541 nfsrv_object_create(nd
.ni_vp
);
1542 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1543 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1544 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
) {
1547 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1552 vrele(nd
.ni_startdir
);
1553 _FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1554 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1555 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1561 vrele(nd
.ni_startdir
);
1562 _FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1564 if (nd
.ni_dvp
== vp
)
1568 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1569 if (vap
->va_size
!= -1) {
1570 error
= nfsrv_access(vp
, VWRITE
, cred
,
1571 (nd
.ni_cnd
.cn_flags
& RDONLY
), procp
, 0);
1573 nqsrv_getl(vp
, ND_WRITE
);
1574 tempsize
= vap
->va_size
;
1576 vap
->va_size
= tempsize
;
1577 error
= VOP_SETATTR(vp
, vap
, cred
,
1584 vput(vp
); /* make sure we catch the EEXIST for nfsv3 */
1588 bzero((caddr_t
)fhp
, sizeof(nfh
));
1589 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
1590 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1592 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
1596 if (exclusive_flag
&& !error
&&
1597 bcmp(cverf
, (caddr_t
)&vap
->va_atime
, NFSX_V3CREATEVERF
))
1599 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
1602 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_FATTR(v3
) + NFSX_WCCDATA(v3
));
1605 nfsm_srvpostop_fh(fhp
);
1606 nfsm_srvpostop_attr(0, vap
);
1608 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1610 nfsm_srvfhtom(fhp
, v3
);
1611 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1612 nfsm_srvfillattr(vap
, fp
);
1618 if (nd
.ni_cnd
.cn_nameiop
) {
1619 vrele(nd
.ni_startdir
);
1620 _FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1621 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1623 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1624 if (nd
.ni_dvp
== nd
.ni_vp
)
1634 * nfs v3 mknod service
1637 nfsrv_mknod(nfsd
, slp
, procp
, mrq
)
1638 struct nfsrv_descript
*nfsd
;
1639 struct nfssvc_sock
*slp
;
1643 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1644 struct mbuf
*nam
= nfsd
->nd_nam
;
1645 caddr_t dpos
= nfsd
->nd_dpos
;
1646 struct ucred
*cred
= &nfsd
->nd_cr
;
1647 struct vattr va
, dirfor
, diraft
;
1648 register struct vattr
*vap
= &va
;
1649 register u_long
*tl
;
1650 struct nameidata nd
;
1653 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
1654 u_long major
, minor
;
1657 struct mbuf
*mb
, *mb2
, *mreq
;
1658 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
1663 nd
.ni_cnd
.cn_nameiop
= 0;
1664 fhp
= &nfh
.fh_generic
;
1666 nfsm_srvnamesiz(len
);
1667 nd
.ni_cnd
.cn_cred
= cred
;
1668 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1669 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| SAVESTART
;
1670 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
1671 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1673 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
, procp
);
1675 nfsm_reply(NFSX_WCCDATA(1));
1676 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1681 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
1682 vtyp
= nfsv3tov_type(*tl
);
1683 if (vtyp
!= VCHR
&& vtyp
!= VBLK
&& vtyp
!= VSOCK
&& vtyp
!= VFIFO
) {
1684 vrele(nd
.ni_startdir
);
1685 _FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1686 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1687 error
= NFSERR_BADTYPE
;
1688 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1694 if (vtyp
== VCHR
|| vtyp
== VBLK
) {
1695 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1696 major
= fxdr_unsigned(u_long
, *tl
++);
1697 minor
= fxdr_unsigned(u_long
, *tl
);
1698 vap
->va_rdev
= makedev(major
, minor
);
1702 * Iff doesn't exist, create it.
1705 vrele(nd
.ni_startdir
);
1706 _FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1707 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1709 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1713 vap
->va_type
= vtyp
;
1714 if (vtyp
== VSOCK
) {
1715 vrele(nd
.ni_startdir
);
1716 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1717 error
= VOP_CREATE(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
);
1719 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1720 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1722 if (vtyp
!= VFIFO
&& (error
= suser(cred
, (u_short
*)0))) {
1723 vrele(nd
.ni_startdir
);
1724 _FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1725 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1726 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1730 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1731 if ((error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
))) {
1732 vrele(nd
.ni_startdir
);
1735 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1736 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| SAVESTART
);
1737 nd
.ni_cnd
.cn_proc
= procp
;
1738 nd
.ni_cnd
.cn_cred
= procp
->p_ucred
;
1739 error
= lookup(&nd
);
1740 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1743 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
) {
1746 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1753 bzero((caddr_t
)fhp
, sizeof(nfh
));
1754 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
1755 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1757 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
1760 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
1762 nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
1764 nfsm_srvpostop_fh(fhp
);
1765 nfsm_srvpostop_attr(0, vap
);
1767 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1772 if (nd
.ni_cnd
.cn_nameiop
) {
1773 vrele(nd
.ni_startdir
);
1774 _FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1775 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1777 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1778 if (nd
.ni_dvp
== nd
.ni_vp
)
1788 * nfs remove service
1791 nfsrv_remove(nfsd
, slp
, procp
, mrq
)
1792 struct nfsrv_descript
*nfsd
;
1793 struct nfssvc_sock
*slp
;
1797 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1798 struct mbuf
*nam
= nfsd
->nd_nam
;
1799 caddr_t dpos
= nfsd
->nd_dpos
;
1800 struct ucred
*cred
= &nfsd
->nd_cr
;
1801 struct nameidata nd
;
1802 register u_long
*tl
;
1805 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
1806 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1808 struct mbuf
*mb
, *mreq
;
1809 struct vnode
*vp
, *dirp
;
1810 struct vattr dirfor
, diraft
;
1816 vp
= (struct vnode
*)0;
1818 fhp
= &nfh
.fh_generic
;
1820 nfsm_srvnamesiz(len
);
1821 nd
.ni_cnd
.cn_cred
= cred
;
1822 nd
.ni_cnd
.cn_nameiop
= DELETE
;
1823 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1824 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
1825 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1828 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
1835 if (vp
->v_type
== VDIR
) {
1836 error
= EPERM
; /* POSIX */
1840 * The root of a mounted filesystem cannot be deleted.
1842 if (vp
->v_flag
& VROOT
) {
1848 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1849 nqsrv_getl(vp
, ND_WRITE
);
1851 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1854 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1855 if (nd
.ni_dvp
== vp
)
1863 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
1866 nfsm_reply(NFSX_WCCDATA(v3
));
1868 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1875 * nfs rename service
1878 nfsrv_rename(nfsd
, slp
, procp
, mrq
)
1879 struct nfsrv_descript
*nfsd
;
1880 struct nfssvc_sock
*slp
;
1884 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1885 struct mbuf
*nam
= nfsd
->nd_nam
;
1886 caddr_t dpos
= nfsd
->nd_dpos
;
1887 struct ucred
*cred
= &nfsd
->nd_cr
;
1888 register u_long
*tl
;
1891 int error
= 0, cache
, len
, len2
, fdirfor_ret
= 1, fdiraft_ret
= 1;
1892 int tdirfor_ret
= 1, tdiraft_ret
= 1;
1893 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1895 struct mbuf
*mb
, *mreq
;
1896 struct nameidata fromnd
, tond
;
1897 struct vnode
*fvp
, *tvp
, *tdvp
, *fdirp
= (struct vnode
*)0;
1898 struct vnode
*tdirp
= (struct vnode
*)0;
1899 struct vattr fdirfor
, fdiraft
, tdirfor
, tdiraft
;
1901 fhandle_t
*ffhp
, *tfhp
;
1906 fvp
= (struct vnode
*)0;
1908 ffhp
= &fnfh
.fh_generic
;
1909 tfhp
= &tnfh
.fh_generic
;
1910 fromnd
.ni_cnd
.cn_nameiop
= 0;
1911 tond
.ni_cnd
.cn_nameiop
= 0;
1912 nfsm_srvmtofh(ffhp
);
1913 nfsm_srvnamesiz(len
);
1915 * Remember our original uid so that we can reset cr_uid before
1916 * the second nfs_namei() call, in case it is remapped.
1918 saved_uid
= cred
->cr_uid
;
1919 fromnd
.ni_cnd
.cn_cred
= cred
;
1920 fromnd
.ni_cnd
.cn_nameiop
= DELETE
;
1921 fromnd
.ni_cnd
.cn_flags
= WANTPARENT
| SAVESTART
;
1922 error
= nfs_namei(&fromnd
, ffhp
, len
, slp
, nam
, &md
,
1923 &dpos
, &fdirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1926 fdirfor_ret
= VOP_GETATTR(fdirp
, &fdirfor
, cred
,
1930 fdirp
= (struct vnode
*)0;
1934 nfsm_reply(2 * NFSX_WCCDATA(v3
));
1935 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
1936 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
1942 nfsm_srvmtofh(tfhp
);
1943 nfsm_strsiz(len2
, NFS_MAXNAMLEN
);
1944 cred
->cr_uid
= saved_uid
;
1945 tond
.ni_cnd
.cn_cred
= cred
;
1946 tond
.ni_cnd
.cn_nameiop
= RENAME
;
1947 tond
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
;
1948 error
= nfs_namei(&tond
, tfhp
, len2
, slp
, nam
, &md
,
1949 &dpos
, &tdirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1952 tdirfor_ret
= VOP_GETATTR(tdirp
, &tdirfor
, cred
,
1956 tdirp
= (struct vnode
*)0;
1960 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
1961 vrele(fromnd
.ni_dvp
);
1968 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
1974 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
1981 if (tvp
->v_type
== VDIR
&& tvp
->v_mountedhere
) {
1989 if (fvp
->v_type
== VDIR
&& fvp
->v_mountedhere
) {
1996 if (fvp
->v_mount
!= tdvp
->v_mount
) {
2009 * If source is the same as the destination (that is the
2010 * same vnode) then there is nothing to do.
2011 * (fixed to have POSIX semantics - CSM 3/2/98)
2017 nqsrv_getl(fromnd
.ni_dvp
, ND_WRITE
);
2018 nqsrv_getl(tdvp
, ND_WRITE
);
2020 nqsrv_getl(tvp
, ND_WRITE
);
2021 error
= VOP_RENAME(fromnd
.ni_dvp
, fromnd
.ni_vp
, &fromnd
.ni_cnd
,
2022 tond
.ni_dvp
, tond
.ni_vp
, &tond
.ni_cnd
);
2024 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2031 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2032 vrele(fromnd
.ni_dvp
);
2037 vrele(tond
.ni_startdir
);
2038 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2041 fdiraft_ret
= VOP_GETATTR(fdirp
, &fdiraft
, cred
, procp
);
2045 tdiraft_ret
= VOP_GETATTR(tdirp
, &tdiraft
, cred
, procp
);
2048 vrele(fromnd
.ni_startdir
);
2049 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2050 nfsm_reply(2 * NFSX_WCCDATA(v3
));
2052 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
2053 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
2062 if (tond
.ni_cnd
.cn_nameiop
) {
2063 vrele(tond
.ni_startdir
);
2064 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2066 if (fromnd
.ni_cnd
.cn_nameiop
) {
2067 vrele(fromnd
.ni_startdir
);
2068 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
,
2069 fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2070 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2071 vrele(fromnd
.ni_dvp
);
2081 nfsrv_link(nfsd
, slp
, procp
, mrq
)
2082 struct nfsrv_descript
*nfsd
;
2083 struct nfssvc_sock
*slp
;
2087 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2088 struct mbuf
*nam
= nfsd
->nd_nam
;
2089 caddr_t dpos
= nfsd
->nd_dpos
;
2090 struct ucred
*cred
= &nfsd
->nd_cr
;
2091 struct nameidata nd
;
2092 register u_long
*tl
;
2095 int error
= 0, rdonly
, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2096 int getret
= 1, v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2098 struct mbuf
*mb
, *mreq
;
2099 struct vnode
*vp
, *xp
, *dirp
= (struct vnode
*)0;
2100 struct vattr dirfor
, diraft
, at
;
2102 fhandle_t
*fhp
, *dfhp
;
2105 fhp
= &nfh
.fh_generic
;
2106 dfhp
= &dnfh
.fh_generic
;
2108 nfsm_srvmtofh(dfhp
);
2109 nfsm_srvnamesiz(len
);
2110 if ((error
= nfsrv_fhtovp(fhp
, FALSE
, &vp
, cred
, slp
, nam
,
2111 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
2112 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2113 nfsm_srvpostop_attr(getret
, &at
);
2114 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2117 if (vp
->v_type
== VDIR
) {
2118 error
= EPERM
; /* POSIX */
2121 nd
.ni_cnd
.cn_cred
= cred
;
2122 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2123 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2124 error
= nfs_namei(&nd
, dfhp
, len
, slp
, nam
, &md
, &dpos
,
2125 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2128 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2132 dirp
= (struct vnode
*)0;
2143 if (vp
->v_mount
!= xp
->v_mount
)
2147 nqsrv_getl(vp
, ND_WRITE
);
2148 nqsrv_getl(xp
, ND_WRITE
);
2149 error
= VOP_LINK(vp
, nd
.ni_dvp
, &nd
.ni_cnd
);
2151 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2152 if (nd
.ni_dvp
== nd
.ni_vp
)
2161 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2163 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2167 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2169 nfsm_srvpostop_attr(getret
, &at
);
2170 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2177 * nfs symbolic link service
2180 nfsrv_symlink(nfsd
, slp
, procp
, mrq
)
2181 struct nfsrv_descript
*nfsd
;
2182 struct nfssvc_sock
*slp
;
2186 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2187 struct mbuf
*nam
= nfsd
->nd_nam
;
2188 caddr_t dpos
= nfsd
->nd_dpos
;
2189 struct ucred
*cred
= &nfsd
->nd_cr
;
2190 struct vattr va
, dirfor
, diraft
;
2191 struct nameidata nd
;
2192 register struct vattr
*vap
= &va
;
2193 register u_long
*tl
;
2195 struct nfsv2_sattr
*sp
;
2196 char *bpos
, *pathcp
= (char *)0, *cp2
;
2199 int error
= 0, cache
, len
, len2
, dirfor_ret
= 1, diraft_ret
= 1;
2200 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2201 struct mbuf
*mb
, *mreq
, *mb2
;
2202 struct vnode
*dirp
= (struct vnode
*)0;
2207 nd
.ni_cnd
.cn_nameiop
= 0;
2208 fhp
= &nfh
.fh_generic
;
2210 nfsm_srvnamesiz(len
);
2211 nd
.ni_cnd
.cn_cred
= cred
;
2212 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2213 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| SAVESTART
;
2214 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
2215 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2218 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2222 dirp
= (struct vnode
*)0;
2230 nfsm_strsiz(len2
, NFS_MAXPATHLEN
);
2231 MALLOC(pathcp
, caddr_t
, len2
+ 1, M_TEMP
, M_WAITOK
);
2232 iv
.iov_base
= pathcp
;
2234 io
.uio_resid
= len2
;
2238 io
.uio_segflg
= UIO_SYSSPACE
;
2239 io
.uio_rw
= UIO_READ
;
2240 io
.uio_procp
= (struct proc
*)0;
2241 nfsm_mtouio(&io
, len2
);
2243 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2244 vap
->va_mode
= fxdr_unsigned(u_short
, sp
->sa_mode
);
2246 *(pathcp
+ len2
) = '\0';
2248 vrele(nd
.ni_startdir
);
2249 _FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2250 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2251 if (nd
.ni_dvp
== nd
.ni_vp
)
2259 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2260 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
, pathcp
);
2262 vrele(nd
.ni_startdir
);
2265 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2266 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| SAVESTART
| FOLLOW
);
2267 nd
.ni_cnd
.cn_flags
|= (NOFOLLOW
| LOCKLEAF
);
2268 nd
.ni_cnd
.cn_proc
= procp
;
2269 nd
.ni_cnd
.cn_cred
= cred
;
2270 error
= lookup(&nd
);
2272 bzero((caddr_t
)fhp
, sizeof(nfh
));
2273 fhp
->fh_fsid
= nd
.ni_vp
->v_mount
->mnt_stat
.f_fsid
;
2274 error
= VFS_VPTOFH(nd
.ni_vp
, &fhp
->fh_fid
);
2276 error
= VOP_GETATTR(nd
.ni_vp
, vap
, cred
,
2281 vrele(nd
.ni_startdir
);
2282 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2286 FREE(pathcp
, M_TEMP
);
2288 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2291 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2294 nfsm_srvpostop_fh(fhp
);
2295 nfsm_srvpostop_attr(0, vap
);
2297 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2301 if (nd
.ni_cnd
.cn_nameiop
) {
2302 vrele(nd
.ni_startdir
);
2303 _FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2307 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2308 if (nd
.ni_dvp
== nd
.ni_vp
)
2315 FREE(pathcp
, M_TEMP
);
2323 nfsrv_mkdir(nfsd
, slp
, procp
, mrq
)
2324 struct nfsrv_descript
*nfsd
;
2325 struct nfssvc_sock
*slp
;
2329 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2330 struct mbuf
*nam
= nfsd
->nd_nam
;
2331 caddr_t dpos
= nfsd
->nd_dpos
;
2332 struct ucred
*cred
= &nfsd
->nd_cr
;
2333 struct vattr va
, dirfor
, diraft
;
2334 register struct vattr
*vap
= &va
;
2335 register struct nfs_fattr
*fp
;
2336 struct nameidata nd
;
2337 register caddr_t cp
;
2338 register u_long
*tl
;
2341 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2342 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2344 struct mbuf
*mb
, *mb2
, *mreq
;
2345 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
2350 fhp
= &nfh
.fh_generic
;
2352 nfsm_srvnamesiz(len
);
2353 nd
.ni_cnd
.cn_cred
= cred
;
2354 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2355 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2356 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
2357 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2360 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2364 dirp
= (struct vnode
*)0;
2368 nfsm_reply(NFSX_WCCDATA(v3
));
2369 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2378 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
2379 vap
->va_mode
= nfstov_mode(*tl
++);
2381 vap
->va_type
= VDIR
;
2384 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2385 if (nd
.ni_dvp
== vp
)
2393 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2394 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
);
2397 bzero((caddr_t
)fhp
, sizeof(nfh
));
2398 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
2399 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
2401 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
2406 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2409 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2412 nfsm_srvpostop_fh(fhp
);
2413 nfsm_srvpostop_attr(0, vap
);
2415 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2417 nfsm_srvfhtom(fhp
, v3
);
2418 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
2419 nfsm_srvfillattr(vap
, fp
);
2425 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2426 if (nd
.ni_dvp
== nd
.ni_vp
)
2439 nfsrv_rmdir(nfsd
, slp
, procp
, mrq
)
2440 struct nfsrv_descript
*nfsd
;
2441 struct nfssvc_sock
*slp
;
2445 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2446 struct mbuf
*nam
= nfsd
->nd_nam
;
2447 caddr_t dpos
= nfsd
->nd_dpos
;
2448 struct ucred
*cred
= &nfsd
->nd_cr
;
2449 register u_long
*tl
;
2452 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2453 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2455 struct mbuf
*mb
, *mreq
;
2456 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
2457 struct vattr dirfor
, diraft
;
2460 struct nameidata nd
;
2463 fhp
= &nfh
.fh_generic
;
2465 nfsm_srvnamesiz(len
);
2466 nd
.ni_cnd
.cn_cred
= cred
;
2467 nd
.ni_cnd
.cn_nameiop
= DELETE
;
2468 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2469 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
2470 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2473 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2477 dirp
= (struct vnode
*)0;
2481 nfsm_reply(NFSX_WCCDATA(v3
));
2482 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2488 if (vp
->v_type
!= VDIR
) {
2493 * No rmdir "." please.
2495 if (nd
.ni_dvp
== vp
) {
2500 * The root of a mounted filesystem cannot be deleted.
2502 if (vp
->v_flag
& VROOT
)
2506 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2507 nqsrv_getl(vp
, ND_WRITE
);
2508 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2510 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2511 if (nd
.ni_dvp
== nd
.ni_vp
)
2518 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2521 nfsm_reply(NFSX_WCCDATA(v3
));
2523 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2530 * nfs readdir service
2531 * - mallocs what it thinks is enough to read
2532 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2533 * - calls VOP_READDIR()
2534 * - loops around building the reply
2535 * if the output generated exceeds count break out of loop
2536 * The nfsm_clget macro is used here so that the reply will be packed
2537 * tightly in mbuf clusters.
2538 * - it only knows that it has encountered eof when the VOP_READDIR()
2540 * - as such one readdir rpc will return eof false although you are there
2541 * and then the next will return eof
2542 * - it trims out records with d_fileno == 0
2543 * this doesn't matter for Unix clients, but they might confuse clients
2545 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2546 * than requested, but this may not apply to all filesystems. For
2547 * example, client NFS does not { although it is never remote mounted
2549 * The alternate call nfsrv_readdirplus() does lookups as well.
2550 * PS: The NFS protocol spec. does not clarify what the "count" byte
2551 * argument is a count of.. just name strings and file id's or the
2552 * entire reply rpc or ...
2553 * I tried just file name and id sizes and it confused the Sun client,
2554 * so I am using the full rpc size now. The "paranoia.." comment refers
2555 * to including the status longwords that are not a part of the dir.
2556 * "entry" structures, but are in the rpc.
2561 u_long fl_fattr
[NFSX_V3FATTR
/ sizeof (u_long
)];
2564 u_long fl_nfh
[NFSX_V3FH
/ sizeof (u_long
)];
2568 nfsrv_readdir(nfsd
, slp
, procp
, mrq
)
2569 struct nfsrv_descript
*nfsd
;
2570 struct nfssvc_sock
*slp
;
2574 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2575 struct mbuf
*nam
= nfsd
->nd_nam
;
2576 caddr_t dpos
= nfsd
->nd_dpos
;
2577 struct ucred
*cred
= &nfsd
->nd_cr
;
2578 register char *bp
, *be
;
2579 register struct mbuf
*mp
;
2580 register struct dirent
*dp
;
2581 register caddr_t cp
;
2582 register u_long
*tl
;
2585 struct mbuf
*mb
, *mb2
, *mreq
, *mp2
;
2586 char *cpos
, *cend
, *cp2
, *rbuf
;
2593 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2594 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, cache
, ncookies
= 0;
2595 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2596 u_quad_t frev
, off
, toff
, verf
;
2597 u_long
*cookies
= NULL
, *cookiep
;
2599 fhp
= &nfh
.fh_generic
;
2602 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
2603 fxdr_hyper(tl
, &toff
);
2605 fxdr_hyper(tl
, &verf
);
2608 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2609 toff
= fxdr_unsigned(u_quad_t
, *tl
++);
2612 cnt
= fxdr_unsigned(int, *tl
);
2613 siz
= ((cnt
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
2614 xfer
= NFS_SRVMAXDATA(nfsd
);
2618 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
2619 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
2620 nfsm_reply(NFSX_UNSIGNED
);
2621 nfsm_srvpostop_attr(getret
, &at
);
2624 nqsrv_getl(vp
, ND_READ
);
2626 error
= getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2627 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
2628 error
= NFSERR_BAD_COOKIE
;
2631 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 0);
2634 nfsm_reply(NFSX_POSTOPATTR(v3
));
2635 nfsm_srvpostop_attr(getret
, &at
);
2638 VOP_UNLOCK(vp
, 0, procp
);
2639 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
2642 iv
.iov_len
= fullsiz
;
2645 io
.uio_offset
= (off_t
)off
;
2646 io
.uio_resid
= fullsiz
;
2647 io
.uio_segflg
= UIO_SYSSPACE
;
2648 io
.uio_rw
= UIO_READ
;
2649 io
.uio_procp
= (struct proc
*)0;
2653 _FREE((caddr_t
)cookies
, M_TEMP
);
2656 if (error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, procp
)) {
2657 FREE((caddr_t
)rbuf
, M_TEMP
);
2658 nfsm_reply(NFSX_POSTOPATTR(v3
));
2659 nfsm_srvpostop_attr(getret
, &at
);
2662 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
2663 off
= (off_t
)io
.uio_offset
;
2665 * We cannot set the error in the case where there are no cookies
2666 * and no error, only, as FreeBSD. In the scenario the client is
2667 * calling us back being told there were "more" entries on last readdir
2668 * return, and we have no more entries, our VOP_READDIR can give
2669 * cookies = NULL and no error. This is due to a zero size to MALLOC
2670 * returning NULL unlike FreeBSD which returns a pointer.
2671 * With FreeBSD it makes sense if the MALLOC failed and you get in that
2672 * bind. For us, we need something more. Thus, we should make sure we
2673 * had some cookies to return, but no pointer and no error for EPERM case.
2674 * Otherwise, go thru normal processing of sending back the eofflag. This check
2675 * is also legit on first call to the routine by client since . and ..
2676 * should be returned. Make same change to nfsrv_readdirplus.
2678 if ((ncookies
!= 0) && !cookies
&& !error
)
2679 error
= NFSERR_PERM
;
2682 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2686 VOP_UNLOCK(vp
, 0, procp
);
2689 _FREE((caddr_t
)rbuf
, M_TEMP
);
2691 _FREE((caddr_t
)cookies
, M_TEMP
);
2692 nfsm_reply(NFSX_POSTOPATTR(v3
));
2693 nfsm_srvpostop_attr(getret
, &at
);
2697 siz
-= io
.uio_resid
;
2700 * If nothing read, return eof
2705 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) +
2708 nfsm_srvpostop_attr(getret
, &at
);
2709 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
2710 txdr_hyper(&at
.va_filerev
, tl
);
2713 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2716 FREE((caddr_t
)rbuf
, M_TEMP
);
2717 FREE((caddr_t
)cookies
, M_TEMP
);
2723 * Check for degenerate cases of nothing useful read.
2724 * If so go try again
2728 dp
= (struct dirent
*)cpos
;
2732 * For some reason FreeBSD's ufs_readdir() chooses to back the
2733 * directory offset up to a block boundary, so it is necessary to
2734 * skip over the records that preceed the requested offset. This
2735 * requires the assumption that file offset cookies monotonically
2738 while (cpos
< cend
&& ncookies
> 0 &&
2739 (dp
->d_fileno
== 0 || ((u_quad_t
)(*cookiep
)) <= toff
)) {
2741 while (dp
->d_fileno
== 0 && cpos
< cend
&& ncookies
> 0) {
2743 cpos
+= dp
->d_reclen
;
2744 dp
= (struct dirent
*)cpos
;
2748 if (cpos
>= cend
|| ncookies
== 0) {
2754 len
= 3 * NFSX_UNSIGNED
; /* paranoia, probably can be 0 */
2755 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) + siz
);
2757 nfsm_srvpostop_attr(getret
, &at
);
2758 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2759 txdr_hyper(&at
.va_filerev
, tl
);
2763 be
= bp
+ M_TRAILINGSPACE(mp
);
2765 /* Loop through the records and build reply */
2766 while (cpos
< cend
&& ncookies
> 0) {
2767 if (dp
->d_fileno
!= 0) {
2768 nlen
= dp
->d_namlen
;
2769 rem
= nfsm_rndup(nlen
)-nlen
;
2770 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
2772 len
+= 2 * NFSX_UNSIGNED
;
2778 * Build the directory record xdr from
2783 bp
+= NFSX_UNSIGNED
;
2787 bp
+= NFSX_UNSIGNED
;
2790 *tl
= txdr_unsigned(dp
->d_fileno
);
2791 bp
+= NFSX_UNSIGNED
;
2793 *tl
= txdr_unsigned(nlen
);
2794 bp
+= NFSX_UNSIGNED
;
2796 /* And loop around copying the name */
2805 bcopy(cp
, bp
, tsiz
);
2811 /* And null pad to a long boundary */
2812 for (i
= 0; i
< rem
; i
++)
2816 /* Finish off the record */
2819 bp
+= NFSX_UNSIGNED
;
2822 *tl
= txdr_unsigned(*cookiep
);
2823 bp
+= NFSX_UNSIGNED
;
2825 cpos
+= dp
->d_reclen
;
2826 dp
= (struct dirent
*)cpos
;
2833 bp
+= NFSX_UNSIGNED
;
2839 bp
+= NFSX_UNSIGNED
;
2842 mp
->m_len
= bp
- mtod(mp
, caddr_t
);
2844 mp
->m_len
+= bp
- bpos
;
2845 FREE((caddr_t
)rbuf
, M_TEMP
);
2846 FREE((caddr_t
)cookies
, M_TEMP
);
2851 nfsrv_readdirplus(nfsd
, slp
, procp
, mrq
)
2852 struct nfsrv_descript
*nfsd
;
2853 struct nfssvc_sock
*slp
;
2857 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2858 struct mbuf
*nam
= nfsd
->nd_nam
;
2859 caddr_t dpos
= nfsd
->nd_dpos
;
2860 struct ucred
*cred
= &nfsd
->nd_cr
;
2861 register char *bp
, *be
;
2862 register struct mbuf
*mp
;
2863 register struct dirent
*dp
;
2864 register caddr_t cp
;
2865 register u_long
*tl
;
2868 struct mbuf
*mb
, *mb2
, *mreq
, *mp2
;
2869 char *cpos
, *cend
, *cp2
, *rbuf
;
2870 struct vnode
*vp
, *nvp
;
2873 fhandle_t
*fhp
, *nfhp
= (fhandle_t
*)fl
.fl_nfh
;
2876 struct vattr va
, at
, *vap
= &va
;
2877 struct nfs_fattr
*fp
;
2878 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2879 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, cache
, dirlen
, ncookies
= 0;
2880 u_quad_t frev
, off
, toff
, verf
;
2881 u_long
*cookies
= NULL
, *cookiep
;
2884 fhp
= &nfh
.fh_generic
;
2886 nfsm_dissect(tl
, u_long
*, 6 * NFSX_UNSIGNED
);
2887 fxdr_hyper(tl
, &toff
);
2889 fxdr_hyper(tl
, &verf
);
2891 siz
= fxdr_unsigned(int, *tl
++);
2892 cnt
= fxdr_unsigned(int, *tl
);
2894 siz
= ((siz
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
2895 xfer
= NFS_SRVMAXDATA(nfsd
);
2899 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
2900 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
2901 nfsm_reply(NFSX_UNSIGNED
);
2902 nfsm_srvpostop_attr(getret
, &at
);
2905 error
= getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2906 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
2907 error
= NFSERR_BAD_COOKIE
;
2909 nqsrv_getl(vp
, ND_READ
);
2910 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 0);
2914 nfsm_reply(NFSX_V3POSTOPATTR
);
2915 nfsm_srvpostop_attr(getret
, &at
);
2918 VOP_UNLOCK(vp
, 0, procp
);
2919 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
2922 iv
.iov_len
= fullsiz
;
2925 io
.uio_offset
= (off_t
)off
;
2926 io
.uio_resid
= fullsiz
;
2927 io
.uio_segflg
= UIO_SYSSPACE
;
2928 io
.uio_rw
= UIO_READ
;
2929 io
.uio_procp
= (struct proc
*)0;
2932 _FREE((caddr_t
)cookies
, M_TEMP
);
2935 if (error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, procp
)) {
2936 FREE((caddr_t
)rbuf
, M_TEMP
);
2937 nfsm_reply(NFSX_V3POSTOPATTR
);
2938 nfsm_srvpostop_attr(getret
, &at
);
2941 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
2942 off
= (u_quad_t
)io
.uio_offset
;
2943 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2944 VOP_UNLOCK(vp
, 0, procp
);
2946 * See nfsrv_readdir comment above on this
2948 if ((ncookies
!= 0) && !cookies
&& !error
)
2949 error
= NFSERR_PERM
;
2956 _FREE((caddr_t
)cookies
, M_TEMP
);
2957 _FREE((caddr_t
)rbuf
, M_TEMP
);
2958 nfsm_reply(NFSX_V3POSTOPATTR
);
2959 nfsm_srvpostop_attr(getret
, &at
);
2963 siz
-= io
.uio_resid
;
2966 * If nothing read, return eof
2971 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+
2973 nfsm_srvpostop_attr(getret
, &at
);
2974 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
2975 txdr_hyper(&at
.va_filerev
, tl
);
2979 FREE((caddr_t
)cookies
, M_TEMP
);
2980 FREE((caddr_t
)rbuf
, M_TEMP
);
2986 * Check for degenerate cases of nothing useful read.
2987 * If so go try again
2991 dp
= (struct dirent
*)cpos
;
2995 * For some reason FreeBSD's ufs_readdir() chooses to back the
2996 * directory offset up to a block boundary, so it is necessary to
2997 * skip over the records that preceed the requested offset. This
2998 * requires the assumption that file offset cookies monotonically
3001 while (cpos
< cend
&& ncookies
> 0 &&
3002 (dp
->d_fileno
== 0 || ((u_quad_t
)(*cookiep
)) <= toff
)) {
3004 while (dp
->d_fileno
== 0 && cpos
< cend
&& ncookies
> 0) {
3006 cpos
+= dp
->d_reclen
;
3007 dp
= (struct dirent
*)cpos
;
3011 if (cpos
>= cend
|| ncookies
== 0) {
3018 * Probe one of the directory entries to see if the filesystem
3019 * supports VGET. See later comment for VFS_VGET changes.
3021 if (vp
->v_tag
== VT_UFS
)
3022 file
= (void *) dp
->d_fileno
;
3024 file
= &dp
->d_fileno
;
3027 if (error
= VFS_VGET(vp
->v_mount
, file
, &nvp
)) {
3028 if (error
== EOPNOTSUPP
) /* let others get passed back */
3029 error
= NFSERR_NOTSUPP
;
3031 _FREE((caddr_t
)cookies
, M_TEMP
);
3032 _FREE((caddr_t
)rbuf
, M_TEMP
);
3033 nfsm_reply(NFSX_V3POSTOPATTR
);
3034 nfsm_srvpostop_attr(getret
, &at
);
3039 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3041 nfsm_srvpostop_attr(getret
, &at
);
3042 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3043 txdr_hyper(&at
.va_filerev
, tl
);
3046 be
= bp
+ M_TRAILINGSPACE(mp
);
3048 /* Loop through the records and build reply */
3049 while (cpos
< cend
&& ncookies
> 0) {
3050 if (dp
->d_fileno
!= 0) {
3051 nlen
= dp
->d_namlen
;
3052 rem
= nfsm_rndup(nlen
)-nlen
;
3055 * Got to get the vnode for lookup per entry.
3056 * HFS+/volfs and others use address of file identifier to VGET
3057 * UFS, nullfs, umapfs use inode (u_int32_t)
3058 * until they are consistent, we must differentiate now.
3059 * UFS is the only one of the latter class that is exported.
3060 * Note this will be pulled out as we resolve the VGET issue
3061 * of which it should use u_in32_t or addresses.
3064 if (vp
->v_tag
== VT_UFS
)
3065 file
= (void *) dp
->d_fileno
;
3067 file
= &dp
->d_fileno
;
3069 if (VFS_VGET(vp
->v_mount
, file
, &nvp
))
3071 bzero((caddr_t
)nfhp
, NFSX_V3FH
);
3073 nvp
->v_mount
->mnt_stat
.f_fsid
;
3074 if (VFS_VPTOFH(nvp
, &nfhp
->fh_fid
)) {
3078 if (VOP_GETATTR(nvp
, vap
, cred
, procp
)) {
3085 * If either the dircount or maxcount will be
3086 * exceeded, get out now. Both of these lengths
3087 * are calculated conservatively, including all
3090 len
+= (7 * NFSX_UNSIGNED
+ nlen
+ rem
+ NFSX_V3FH
+
3092 dirlen
+= (6 * NFSX_UNSIGNED
+ nlen
+ rem
);
3093 if (len
> cnt
|| dirlen
> fullsiz
) {
3099 * Build the directory record xdr from
3102 fp
= (struct nfs_fattr
*)&fl
.fl_fattr
;
3103 nfsm_srvfillattr(vap
, fp
);
3104 fl
.fl_fhsize
= txdr_unsigned(NFSX_V3FH
);
3105 fl
.fl_fhok
= nfs_true
;
3106 fl
.fl_postopok
= nfs_true
;
3107 fl
.fl_off
.nfsuquad
[0] = 0;
3108 fl
.fl_off
.nfsuquad
[1] = txdr_unsigned(*cookiep
);
3112 bp
+= NFSX_UNSIGNED
;
3115 bp
+= NFSX_UNSIGNED
;
3117 *tl
= txdr_unsigned(dp
->d_fileno
);
3118 bp
+= NFSX_UNSIGNED
;
3120 *tl
= txdr_unsigned(nlen
);
3121 bp
+= NFSX_UNSIGNED
;
3123 /* And loop around copying the name */
3128 if ((bp
+ xfer
) > be
)
3132 bcopy(cp
, bp
, tsiz
);
3138 /* And null pad to a long boundary */
3139 for (i
= 0; i
< rem
; i
++)
3143 * Now copy the flrep structure out.
3145 xfer
= sizeof (struct flrep
);
3149 if ((bp
+ xfer
) > be
)
3153 bcopy(cp
, bp
, tsiz
);
3161 cpos
+= dp
->d_reclen
;
3162 dp
= (struct dirent
*)cpos
;
3169 bp
+= NFSX_UNSIGNED
;
3175 bp
+= NFSX_UNSIGNED
;
3178 mp
->m_len
= bp
- mtod(mp
, caddr_t
);
3180 mp
->m_len
+= bp
- bpos
;
3181 FREE((caddr_t
)cookies
, M_TEMP
);
3182 FREE((caddr_t
)rbuf
, M_TEMP
);
3187 * nfs commit service
3190 nfsrv_commit(nfsd
, slp
, procp
, mrq
)
3191 struct nfsrv_descript
*nfsd
;
3192 struct nfssvc_sock
*slp
;
3196 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3197 struct mbuf
*nam
= nfsd
->nd_nam
;
3198 caddr_t dpos
= nfsd
->nd_dpos
;
3199 struct ucred
*cred
= &nfsd
->nd_cr
;
3200 struct vattr bfor
, aft
;
3204 register u_long
*tl
;
3207 int error
= 0, rdonly
, for_ret
= 1, aft_ret
= 1, cnt
, cache
;
3209 struct mbuf
*mb
, *mb2
, *mreq
;
3215 fhp
= &nfh
.fh_generic
;
3217 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
3220 * XXX At this time VOP_FSYNC() does not accept offset and byte
3221 * count parameters, so these arguments are useless (someday maybe).
3223 fxdr_hyper(tl
, &off
);
3225 cnt
= fxdr_unsigned(int, *tl
);
3226 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3227 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3228 nfsm_reply(2 * NFSX_UNSIGNED
);
3229 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
3232 for_ret
= VOP_GETATTR(vp
, &bfor
, cred
, procp
);
3233 error
= VOP_FSYNC(vp
, cred
, MNT_WAIT
, procp
);
3234 aft_ret
= VOP_GETATTR(vp
, &aft
, cred
, procp
);
3236 nfsm_reply(NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
3237 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
3239 nfsm_build(tl
, u_long
*, NFSX_V3WRITEVERF
);
3240 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
3241 *tl
= txdr_unsigned(boottime
.tv_usec
);
3248 * nfs statfs service
3251 nfsrv_statfs(nfsd
, slp
, procp
, mrq
)
3252 struct nfsrv_descript
*nfsd
;
3253 struct nfssvc_sock
*slp
;
3257 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3258 struct mbuf
*nam
= nfsd
->nd_nam
;
3259 caddr_t dpos
= nfsd
->nd_dpos
;
3260 struct ucred
*cred
= &nfsd
->nd_cr
;
3261 register struct statfs
*sf
;
3262 register struct nfs_statfs
*sfp
;
3263 register u_long
*tl
;
3266 int error
= 0, rdonly
, cache
, getret
= 1;
3267 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3269 struct mbuf
*mb
, *mb2
, *mreq
;
3274 struct statfs statfs
;
3275 u_quad_t frev
, tval
;
3280 fhp
= &nfh
.fh_generic
;
3282 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3283 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3284 nfsm_reply(NFSX_UNSIGNED
);
3285 nfsm_srvpostop_attr(getret
, &at
);
3289 error
= VFS_STATFS(vp
->v_mount
, sf
, procp
);
3290 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
3292 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_STATFS(v3
));
3294 nfsm_srvpostop_attr(getret
, &at
);
3297 nfsm_build(sfp
, struct nfs_statfs
*, NFSX_STATFS(v3
));
3299 tval
= (u_quad_t
)sf
->f_blocks
;
3300 tval
*= (u_quad_t
)sf
->f_bsize
;
3301 txdr_hyper(&tval
, &sfp
->sf_tbytes
);
3302 tval
= (u_quad_t
)sf
->f_bfree
;
3303 tval
*= (u_quad_t
)sf
->f_bsize
;
3304 txdr_hyper(&tval
, &sfp
->sf_fbytes
);
3305 tval
= (u_quad_t
)sf
->f_bavail
;
3306 tval
*= (u_quad_t
)sf
->f_bsize
;
3307 txdr_hyper(&tval
, &sfp
->sf_abytes
);
3308 sfp
->sf_tfiles
.nfsuquad
[0] = 0;
3309 sfp
->sf_tfiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_files
);
3310 sfp
->sf_ffiles
.nfsuquad
[0] = 0;
3311 sfp
->sf_ffiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3312 sfp
->sf_afiles
.nfsuquad
[0] = 0;
3313 sfp
->sf_afiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3314 sfp
->sf_invarsec
= 0;
3316 sfp
->sf_tsize
= txdr_unsigned(NFS_MAXDGRAMDATA
);
3317 sfp
->sf_bsize
= txdr_unsigned(sf
->f_bsize
);
3318 sfp
->sf_blocks
= txdr_unsigned(sf
->f_blocks
);
3319 sfp
->sf_bfree
= txdr_unsigned(sf
->f_bfree
);
3320 sfp
->sf_bavail
= txdr_unsigned(sf
->f_bavail
);
3326 * nfs fsinfo service
3329 nfsrv_fsinfo(nfsd
, slp
, procp
, mrq
)
3330 struct nfsrv_descript
*nfsd
;
3331 struct nfssvc_sock
*slp
;
3335 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3336 struct mbuf
*nam
= nfsd
->nd_nam
;
3337 caddr_t dpos
= nfsd
->nd_dpos
;
3338 struct ucred
*cred
= &nfsd
->nd_cr
;
3339 register u_long
*tl
;
3340 register struct nfsv3_fsinfo
*sip
;
3343 int error
= 0, rdonly
, cache
, getret
= 1, pref
;
3345 struct mbuf
*mb
, *mb2
, *mreq
;
3355 fhp
= &nfh
.fh_generic
;
3357 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3358 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3359 nfsm_reply(NFSX_UNSIGNED
);
3360 nfsm_srvpostop_attr(getret
, &at
);
3363 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
3365 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
3366 nfsm_srvpostop_attr(getret
, &at
);
3367 nfsm_build(sip
, struct nfsv3_fsinfo
*, NFSX_V3FSINFO
);
3371 * There should be file system VFS OP(s) to get this information.
3372 * For now, assume ufs.
3374 if (slp
->ns_so
->so_type
== SOCK_DGRAM
)
3375 pref
= NFS_MAXDGRAMDATA
;
3378 sip
->fs_rtmax
= txdr_unsigned(NFS_MAXDATA
);
3379 sip
->fs_rtpref
= txdr_unsigned(pref
);
3380 sip
->fs_rtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3381 sip
->fs_wtmax
= txdr_unsigned(NFS_MAXDATA
);
3382 sip
->fs_wtpref
= txdr_unsigned(pref
);
3383 sip
->fs_wtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3384 sip
->fs_dtpref
= txdr_unsigned(pref
);
3385 sip
->fs_maxfilesize
.nfsuquad
[0] = 0xffffffff;
3386 sip
->fs_maxfilesize
.nfsuquad
[1] = 0xffffffff;
3387 sip
->fs_timedelta
.nfsv3_sec
= 0;
3388 sip
->fs_timedelta
.nfsv3_nsec
= txdr_unsigned(1);
3389 sip
->fs_properties
= txdr_unsigned(NFSV3FSINFO_LINK
|
3390 NFSV3FSINFO_SYMLINK
| NFSV3FSINFO_HOMOGENEOUS
|
3391 NFSV3FSINFO_CANSETTIME
);
3396 * nfs pathconf service
3399 nfsrv_pathconf(nfsd
, slp
, procp
, mrq
)
3400 struct nfsrv_descript
*nfsd
;
3401 struct nfssvc_sock
*slp
;
3405 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3406 struct mbuf
*nam
= nfsd
->nd_nam
;
3407 caddr_t dpos
= nfsd
->nd_dpos
;
3408 struct ucred
*cred
= &nfsd
->nd_cr
;
3409 register u_long
*tl
;
3410 register struct nfsv3_pathconf
*pc
;
3413 int error
= 0, rdonly
, cache
, getret
= 1, linkmax
, namemax
;
3414 int chownres
, notrunc
;
3416 struct mbuf
*mb
, *mb2
, *mreq
;
3426 fhp
= &nfh
.fh_generic
;
3428 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3429 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3430 nfsm_reply(NFSX_UNSIGNED
);
3431 nfsm_srvpostop_attr(getret
, &at
);
3434 error
= VOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
);
3436 error
= VOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
);
3438 error
= VOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
);
3440 error
= VOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
);
3441 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
3443 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
3444 nfsm_srvpostop_attr(getret
, &at
);
3447 nfsm_build(pc
, struct nfsv3_pathconf
*, NFSX_V3PATHCONF
);
3449 pc
->pc_linkmax
= txdr_unsigned(linkmax
);
3450 pc
->pc_namemax
= txdr_unsigned(namemax
);
3451 pc
->pc_notrunc
= txdr_unsigned(notrunc
);
3452 pc
->pc_chownrestricted
= txdr_unsigned(chownres
);
3455 * These should probably be supported by VOP_PATHCONF(), but
3456 * until msdosfs is exportable (why would you want to?), the
3457 * Unix defaults should be ok.
3459 pc
->pc_caseinsensitive
= nfs_false
;
3460 pc
->pc_casepreserving
= nfs_true
;
3465 * Null operation, used by clients to ping server
3469 nfsrv_null(nfsd
, slp
, procp
, mrq
)
3470 struct nfsrv_descript
*nfsd
;
3471 struct nfssvc_sock
*slp
;
3475 struct mbuf
*mrep
= nfsd
->nd_mrep
;
3477 int error
= NFSERR_RETVOID
, cache
;
3478 struct mbuf
*mb
, *mreq
;
3489 * No operation, used for obsolete procedures
3493 nfsrv_noop(nfsd
, slp
, procp
, mrq
)
3494 struct nfsrv_descript
*nfsd
;
3495 struct nfssvc_sock
*slp
;
3499 struct mbuf
*mrep
= nfsd
->nd_mrep
;
3502 struct mbuf
*mb
, *mreq
;
3508 if (nfsd
->nd_repstat
)
3509 error
= nfsd
->nd_repstat
;
3511 error
= EPROCUNAVAIL
;
3517 * Perform access checking for vnodes obtained from file handles that would
3518 * refer to files already opened by a Unix client. You cannot just use
3519 * vn_writechk() and VOP_ACCESS() for two reasons.
3520 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3521 * 2 - The owner is to be given access irrespective of mode bits so that
3522 * processes that chmod after opening a file don't break. I don't like
3523 * this because it opens a security hole, but since the nfs server opens
3524 * a security hole the size of a barn door anyhow, what the heck.
3526 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
3527 * will return EPERM instead of EACCESS. EPERM is always an error.
3531 nfsrv_access(vp
, flags
, cred
, rdonly
, p
, override
)
3532 register struct vnode
*vp
;
3534 register struct ucred
*cred
;
3541 if (flags
& VWRITE
) {
3542 /* Just vn_writechk() changed to check rdonly */
3544 * Disallow write attempts on read-only file systems;
3545 * unless the file is a socket or a block or character
3546 * device resident on the file system.
3548 if (rdonly
|| (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
3549 switch (vp
->v_type
) {
3550 case VREG
: case VDIR
: case VLNK
: case VCPLX
:
3555 * If there's shared text associated with
3556 * the inode, we can't allow writing.
3558 if (vp
->v_flag
& VTEXT
)
3561 if ((error
= VOP_GETATTR(vp
, &vattr
, cred
, p
)))
3563 error
= VOP_ACCESS(vp
, flags
, cred
, p
);
3565 * Allow certain operations for the owner (reads and writes
3566 * on files that are already open). Picking up from FreeBSD.
3568 if (override
&& error
== EACCES
&& cred
->cr_uid
== vattr
.va_uid
)
3572 #endif /* NFS_NOSERVER */