]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_serv.c
2 * Copyright (c) 2000-2003 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>
103 #include <sys/vmparam.h>
104 #include <machine/spl.h>
106 #include <nfs/nfsproto.h>
107 #include <nfs/rpcv2.h>
109 #include <nfs/xdr_subs.h>
110 #include <nfs/nfsm_subs.h>
111 #include <nfs/nqnfs.h>
113 nfstype nfsv3_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFSOCK
,
116 nfstype nfsv2_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFNON
,
119 extern u_long nfs_xdrneg1
;
120 extern u_long nfs_false
, nfs_true
;
121 extern enum vtype nv3tov_type
[8];
122 extern struct nfsstats nfsstats
;
124 int nfsrvw_procrastinate
= NFS_GATHERDELAY
* 1000;
125 int nfsrvw_procrastinate_v3
= 0;
129 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
130 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, async
, CTLFLAG_RW
, &nfs_async
, 0, "");
133 static int nfsrv_access
__P((struct vnode
*,int,struct ucred
*,int,
134 struct proc
*, int));
135 static void nfsrvw_coalesce
__P((struct nfsrv_descript
*,
136 struct nfsrv_descript
*));
139 * nfs v3 access service
142 nfsrv3_access(nfsd
, slp
, procp
, mrq
)
143 struct nfsrv_descript
*nfsd
;
144 struct nfssvc_sock
*slp
;
148 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
149 struct mbuf
*nam
= nfsd
->nd_nam
;
150 caddr_t dpos
= nfsd
->nd_dpos
;
151 struct ucred
*cred
= &nfsd
->nd_cr
;
158 int error
= 0, rdonly
, cache
, getret
;
160 struct mbuf
*mb
, *mreq
, *mb2
;
161 struct vattr vattr
, *vap
= &vattr
;
162 u_long testmode
, nfsmode
;
168 fhp
= &nfh
.fh_generic
;
170 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
171 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
172 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
173 nfsm_reply(NFSX_UNSIGNED
);
174 nfsm_srvpostop_attr(1, (struct vattr
*)0);
177 nfsmode
= fxdr_unsigned(u_long
, *tl
);
178 if ((nfsmode
& NFSV3ACCESS_READ
) &&
179 nfsrv_access(vp
, VREAD
, cred
, rdonly
, procp
, 0))
180 nfsmode
&= ~NFSV3ACCESS_READ
;
181 if (vp
->v_type
== VDIR
)
182 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
|
185 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
);
186 if ((nfsmode
& testmode
) &&
187 nfsrv_access(vp
, VWRITE
, cred
, rdonly
, procp
, 0))
188 nfsmode
&= ~testmode
;
189 if (vp
->v_type
== VDIR
)
190 testmode
= NFSV3ACCESS_LOOKUP
;
192 testmode
= NFSV3ACCESS_EXECUTE
;
193 if ((nfsmode
& testmode
) &&
194 nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 0))
195 nfsmode
&= ~testmode
;
196 getret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
198 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED
);
199 nfsm_srvpostop_attr(getret
, vap
);
200 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
201 *tl
= txdr_unsigned(nfsmode
);
206 * nfs getattr service
209 nfsrv_getattr(nfsd
, slp
, procp
, mrq
)
210 struct nfsrv_descript
*nfsd
;
211 struct nfssvc_sock
*slp
;
215 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
216 struct mbuf
*nam
= nfsd
->nd_nam
;
217 caddr_t dpos
= nfsd
->nd_dpos
;
218 struct ucred
*cred
= &nfsd
->nd_cr
;
219 register struct nfs_fattr
*fp
;
221 register struct vattr
*vap
= &va
;
228 int error
= 0, rdonly
, cache
;
230 struct mbuf
*mb
, *mb2
, *mreq
;
233 fhp
= &nfh
.fh_generic
;
235 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
236 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
240 nqsrv_getl(vp
, ND_READ
);
241 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
243 nfsm_reply(NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
246 nfsm_build(fp
, struct nfs_fattr
*, NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
247 nfsm_srvfillattr(vap
, fp
);
252 * nfs setattr service
255 nfsrv_setattr(nfsd
, slp
, procp
, mrq
)
256 struct nfsrv_descript
*nfsd
;
257 struct nfssvc_sock
*slp
;
261 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
262 struct mbuf
*nam
= nfsd
->nd_nam
;
263 caddr_t dpos
= nfsd
->nd_dpos
;
264 struct ucred
*cred
= &nfsd
->nd_cr
;
265 struct vattr va
, preat
;
266 register struct vattr
*vap
= &va
;
267 register struct nfsv2_sattr
*sp
;
268 register struct nfs_fattr
*fp
;
275 int error
= 0, rdonly
, cache
, preat_ret
= 1, postat_ret
= 1;
276 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), gcheck
= 0;
278 struct mbuf
*mb
, *mb2
, *mreq
;
280 struct timespec guard
;
282 fhp
= &nfh
.fh_generic
;
287 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
288 gcheck
= fxdr_unsigned(int, *tl
);
290 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
291 fxdr_nfsv3time(tl
, &guard
);
294 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
296 * Nah nah nah nah na nah
297 * There is a bug in the Sun client that puts 0xffff in the mode
298 * field of sattr when it should put in 0xffffffff. The u_short
299 * doesn't sign extend.
300 * --> check the low order 2 bytes for 0xffff
302 if ((fxdr_unsigned(int, sp
->sa_mode
) & 0xffff) != 0xffff)
303 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
304 if (sp
->sa_uid
!= nfs_xdrneg1
)
305 vap
->va_uid
= fxdr_unsigned(uid_t
, sp
->sa_uid
);
306 if (sp
->sa_gid
!= nfs_xdrneg1
)
307 vap
->va_gid
= fxdr_unsigned(gid_t
, sp
->sa_gid
);
308 if (sp
->sa_size
!= nfs_xdrneg1
)
309 vap
->va_size
= fxdr_unsigned(u_quad_t
, sp
->sa_size
);
310 if (sp
->sa_atime
.nfsv2_sec
!= nfs_xdrneg1
) {
312 fxdr_nfsv2time(&sp
->sa_atime
, &vap
->va_atime
);
314 vap
->va_atime
.tv_sec
=
315 fxdr_unsigned(long, sp
->sa_atime
.nfsv2_sec
);
316 vap
->va_atime
.tv_nsec
= 0;
319 if (sp
->sa_mtime
.nfsv2_sec
!= nfs_xdrneg1
)
320 fxdr_nfsv2time(&sp
->sa_mtime
, &vap
->va_mtime
);
325 * Now that we have all the fields, lets do it.
327 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
328 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
329 nfsm_reply(2 * NFSX_UNSIGNED
);
330 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
333 nqsrv_getl(vp
, ND_WRITE
);
335 error
= preat_ret
= VOP_GETATTR(vp
, &preat
, cred
, procp
);
336 if (!error
&& gcheck
&&
337 (preat
.va_ctime
.tv_sec
!= guard
.tv_sec
||
338 preat
.va_ctime
.tv_nsec
!= guard
.tv_nsec
))
339 error
= NFSERR_NOT_SYNC
;
342 nfsm_reply(NFSX_WCCDATA(v3
));
343 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
349 * If the size is being changed write acces is required, otherwise
350 * just check for a read only file system.
352 if (vap
->va_size
== ((u_quad_t
)((quad_t
) -1))) {
353 if (rdonly
|| (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
358 if (vp
->v_type
== VDIR
) {
361 } else if ((error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
,
365 error
= VOP_SETATTR(vp
, vap
, cred
, procp
);
366 postat_ret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
371 nfsm_reply(NFSX_WCCORFATTR(v3
));
373 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
376 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
377 nfsm_srvfillattr(vap
, fp
);
386 nfsrv_lookup(nfsd
, slp
, procp
, mrq
)
387 struct nfsrv_descript
*nfsd
;
388 struct nfssvc_sock
*slp
;
392 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
393 struct mbuf
*nam
= nfsd
->nd_nam
;
394 caddr_t dpos
= nfsd
->nd_dpos
;
395 struct ucred
*cred
= &nfsd
->nd_cr
;
396 register struct nfs_fattr
*fp
;
397 struct nameidata nd
, *ndp
= &nd
;
399 struct nameidata ind
;
401 struct vnode
*vp
, *dirp
;
408 int error
= 0, cache
, len
, dirattr_ret
= 1;
409 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), pubflag
;
411 struct mbuf
*mb
, *mb2
, *mreq
;
412 struct vattr va
, dirattr
, *vap
= &va
;
415 fhp
= &nfh
.fh_generic
;
417 nfsm_srvnamesiz(len
);
419 pubflag
= nfs_ispublicfh(fhp
);
421 nd
.ni_cnd
.cn_cred
= cred
;
422 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
423 nd
.ni_cnd
.cn_flags
= LOCKLEAF
| SAVESTART
;
424 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
425 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), pubflag
);
427 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
429 if (!error
&& pubflag
) {
430 if (nd
.ni_vp
->v_type
== VDIR
&& nfs_pub
.np_index
!= NULL
) {
432 * Setup call to lookup() to see if we can find
433 * the index file. Arguably, this doesn't belong
437 VOP_UNLOCK(nd
.ni_vp
, 0, procp
);
438 ind
.ni_pathlen
= strlen(nfs_pub
.np_index
);
439 ind
.ni_cnd
.cn_nameptr
= ind
.ni_cnd
.cn_pnbuf
=
441 ind
.ni_startdir
= nd
.ni_vp
;
442 VREF(ind
.ni_startdir
);
443 error
= lookup(&ind
);
446 * Found an index file. Get rid of
447 * the old references.
452 vrele(nd
.ni_startdir
);
458 * If the public filehandle was used, check that this lookup
459 * didn't result in a filehandle outside the publicly exported
463 if (!error
&& ndp
->ni_vp
->v_mount
!= nfs_pub
.np_mount
) {
472 dirattr_ret
= VOP_GETATTR(dirp
, &dirattr
, cred
,
478 nfsm_reply(NFSX_POSTOPATTR(v3
));
479 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
483 nqsrv_getl(ndp
->ni_startdir
, ND_READ
);
484 vrele(ndp
->ni_startdir
);
485 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
486 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
488 bzero((caddr_t
)fhp
, sizeof(nfh
));
489 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
490 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
492 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
494 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPORFATTR(v3
) + NFSX_POSTOPATTR(v3
));
496 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
499 nfsm_srvfhtom(fhp
, v3
);
501 nfsm_srvpostop_attr(0, vap
);
502 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
504 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
505 nfsm_srvfillattr(vap
, fp
);
511 * nfs readlink service
514 nfsrv_readlink(nfsd
, slp
, procp
, mrq
)
515 struct nfsrv_descript
*nfsd
;
516 struct nfssvc_sock
*slp
;
520 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
521 struct mbuf
*nam
= nfsd
->nd_nam
;
522 caddr_t dpos
= nfsd
->nd_dpos
;
523 struct ucred
*cred
= &nfsd
->nd_cr
;
524 struct iovec iv
[(NFS_MAXPATHLEN
+MLEN
-1)/MLEN
];
525 register struct iovec
*ivp
= iv
;
526 register struct mbuf
*mp
;
530 int error
= 0, rdonly
, cache
, i
, tlen
, len
, getret
;
531 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
533 struct mbuf
*mb
, *mb2
, *mp2
, *mp3
, *mreq
;
538 struct uio io
, *uiop
= &io
;
542 mp2
= mp3
= (struct mbuf
*)0;
544 fhp
= &nfh
.fh_generic
;
548 while (len
< NFS_MAXPATHLEN
) {
549 MGET(mp
, M_WAIT
, MT_DATA
);
551 mp
->m_len
= NFSMSIZ(mp
);
558 if ((len
+mp
->m_len
) > NFS_MAXPATHLEN
) {
559 mp
->m_len
= NFS_MAXPATHLEN
-len
;
560 len
= NFS_MAXPATHLEN
;
563 ivp
->iov_base
= mtod(mp
, caddr_t
);
564 ivp
->iov_len
= mp
->m_len
;
569 uiop
->uio_iovcnt
= i
;
570 uiop
->uio_offset
= 0;
571 uiop
->uio_resid
= len
;
572 uiop
->uio_rw
= UIO_READ
;
573 uiop
->uio_segflg
= UIO_SYSSPACE
;
574 uiop
->uio_procp
= (struct proc
*)0;
575 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
576 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
578 nfsm_reply(2 * NFSX_UNSIGNED
);
579 nfsm_srvpostop_attr(1, (struct vattr
*)0);
582 if (vp
->v_type
!= VLNK
) {
589 nqsrv_getl(vp
, ND_READ
);
590 error
= VOP_READLINK(vp
, uiop
, cred
);
592 getret
= VOP_GETATTR(vp
, &attr
, cred
, procp
);
596 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_UNSIGNED
);
598 nfsm_srvpostop_attr(getret
, &attr
);
602 if (uiop
->uio_resid
> 0) {
603 len
-= uiop
->uio_resid
;
604 tlen
= nfsm_rndup(len
);
605 nfsm_adj(mp3
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
607 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
608 *tl
= txdr_unsigned(len
);
617 nfsrv_read(nfsd
, slp
, procp
, mrq
)
618 struct nfsrv_descript
*nfsd
;
619 struct nfssvc_sock
*slp
;
623 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
624 struct mbuf
*nam
= nfsd
->nd_nam
;
625 caddr_t dpos
= nfsd
->nd_dpos
;
626 struct ucred
*cred
= &nfsd
->nd_cr
;
627 register struct iovec
*iv
;
629 register struct mbuf
*m
;
630 register struct nfs_fattr
*fp
;
635 int error
= 0, rdonly
, cache
, cnt
, len
, left
, siz
, tlen
, getret
;
636 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), reqlen
;
638 struct mbuf
*mb
, *mb2
, *mreq
;
643 struct uio io
, *uiop
= &io
;
644 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 didhold
= ubc_hold(vp
);
749 error
= VOP_READ(vp
, uiop
, IO_NODELOCKED
, cred
);
750 off
= uiop
->uio_offset
;
751 FREE((caddr_t
)iv2
, M_TEMP
);
752 /* Though our code replaces error with getret, the way I read
753 * the v3 spec, it appears you should leave the error alone, but
754 * still return vap and not assign error = getret. But leaving
755 * that alone. m_freem(mreq) looks bogus. Taking it out. Should be
756 * mrep or not there at all. Causes panic. ekn */
757 if (error
|| (getret
= VOP_GETATTR(vp
, vap
, cred
, procp
))) {
758 VOP_UNLOCK(vp
, 0, procp
);
765 nfsm_reply(NFSX_POSTOPATTR(v3
));
766 nfsm_srvpostop_attr(getret
, vap
);
769 VOP_UNLOCK(vp
, 0, procp
);
777 nfsm_srvfillattr(vap
, fp
);
778 len
-= uiop
->uio_resid
;
779 tlen
= nfsm_rndup(len
);
780 if (cnt
!= tlen
|| tlen
!= len
)
781 nfsm_adj(mb
, cnt
- tlen
, tlen
- len
);
783 *tl
++ = txdr_unsigned(len
);
789 *tl
= txdr_unsigned(len
);
797 nfsrv_write(nfsd
, slp
, procp
, mrq
)
798 struct nfsrv_descript
*nfsd
;
799 struct nfssvc_sock
*slp
;
803 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
804 struct mbuf
*nam
= nfsd
->nd_nam
;
805 caddr_t dpos
= nfsd
->nd_dpos
;
806 struct ucred
*cred
= &nfsd
->nd_cr
;
807 register struct iovec
*ivp
;
809 register struct mbuf
*mp
;
810 register struct nfs_fattr
*fp
;
812 struct vattr va
, forat
;
813 register struct vattr
*vap
= &va
;
817 int error
= 0, rdonly
, cache
, len
, forat_ret
= 1;
818 int ioflags
, aftat_ret
= 1, retlen
, zeroing
, adjust
;
819 int stable
= NFSV3WRITE_FILESYNC
;
820 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
822 struct mbuf
*mb
, *mb2
, *mreq
;
826 struct uio io
, *uiop
= &io
;
835 fhp
= &nfh
.fh_generic
;
838 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
839 fxdr_hyper(tl
, &off
);
841 stable
= fxdr_unsigned(int, *tl
++);
843 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
844 off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
847 stable
= NFSV3WRITE_UNSTABLE
;
849 retlen
= len
= fxdr_unsigned(long, *tl
);
853 * For NFS Version 2, it is not obvious what a write of zero length
854 * should do, but I might as well be consistent with Version 3,
855 * which is to return ok so long as there are no permission problems.
863 adjust
= dpos
- mtod(mp
, caddr_t
);
865 if (mp
->m_len
> 0 && adjust
> 0)
870 else if (mp
->m_len
> 0) {
873 mp
->m_len
-= (i
- len
);
882 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
884 nfsm_reply(2 * NFSX_UNSIGNED
);
885 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
888 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
889 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
890 nfsm_reply(2 * NFSX_UNSIGNED
);
891 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
895 forat_ret
= VOP_GETATTR(vp
, &forat
, cred
, procp
);
896 if (vp
->v_type
!= VREG
) {
900 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
903 nqsrv_getl(vp
, ND_WRITE
);
904 error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
, procp
, 1);
908 nfsm_reply(NFSX_WCCDATA(v3
));
909 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
914 MALLOC(ivp
, struct iovec
*, cnt
* sizeof (struct iovec
), M_TEMP
,
916 uiop
->uio_iov
= iv
= ivp
;
917 uiop
->uio_iovcnt
= cnt
;
921 ivp
->iov_base
= mtod(mp
, caddr_t
);
922 ivp
->iov_len
= mp
->m_len
;
930 * The IO_METASYNC flag indicates that all metadata (and not just
931 * enough to ensure data integrity) mus be written to stable storage
933 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
935 if (stable
== NFSV3WRITE_UNSTABLE
)
936 ioflags
= IO_NODELOCKED
;
937 else if (stable
== NFSV3WRITE_DATASYNC
)
938 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
940 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
941 uiop
->uio_resid
= len
;
942 uiop
->uio_rw
= UIO_WRITE
;
943 uiop
->uio_segflg
= UIO_SYSSPACE
;
944 uiop
->uio_procp
= (struct proc
*)0;
945 uiop
->uio_offset
= off
;
946 didhold
= ubc_hold(vp
);
947 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
948 nfsstats
.srvvop_writes
++;
949 FREE((caddr_t
)iv
, M_TEMP
);
951 aftat_ret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
952 VOP_UNLOCK(vp
, 0, procp
);
958 nfsm_reply(NFSX_PREOPATTR(v3
) + NFSX_POSTOPORFATTR(v3
) +
959 2 * NFSX_UNSIGNED
+ NFSX_WRITEVERF(v3
));
961 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
964 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
965 *tl
++ = txdr_unsigned(retlen
);
967 * If nfs_async is set, then pretend the write was FILESYNC.
969 if (stable
== NFSV3WRITE_UNSTABLE
&& !nfs_async
)
970 *tl
++ = txdr_unsigned(stable
);
972 *tl
++ = txdr_unsigned(NFSV3WRITE_FILESYNC
);
974 * Actually, there is no need to txdr these fields,
975 * but it may make the values more human readable,
976 * for debugging purposes.
978 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
979 *tl
= txdr_unsigned(boottime
.tv_usec
);
981 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
982 nfsm_srvfillattr(vap
, fp
);
988 * NFS write service with write gathering support. Called when
989 * nfsrvw_procrastinate > 0.
990 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
991 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
995 nfsrv_writegather(ndp
, slp
, procp
, mrq
)
996 struct nfsrv_descript
**ndp
;
997 struct nfssvc_sock
*slp
;
1001 register struct iovec
*ivp
;
1002 register struct mbuf
*mp
;
1003 register struct nfsrv_descript
*wp
, *nfsd
, *owp
, *swp
;
1004 register struct nfs_fattr
*fp
;
1007 struct nfsrvw_delayhash
*wpp
;
1009 struct vattr va
, forat
;
1010 register u_long
*tl
;
1013 int error
= 0, rdonly
, cache
, len
, forat_ret
= 1;
1014 int ioflags
, aftat_ret
= 1, s
, adjust
, v3
, zeroing
;
1016 struct mbuf
*mb
, *mb2
, *mreq
, *mrep
, *md
;
1018 struct uio io
, *uiop
= &io
;
1019 u_quad_t frev
, cur_usec
;
1031 mrep
= nfsd
->nd_mrep
;
1033 dpos
= nfsd
->nd_dpos
;
1034 cred
= &nfsd
->nd_cr
;
1035 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1036 LIST_INIT(&nfsd
->nd_coalesce
);
1037 nfsd
->nd_mreq
= NULL
;
1038 nfsd
->nd_stable
= NFSV3WRITE_FILESYNC
;
1040 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1041 nfsd
->nd_time
= cur_usec
+
1042 (v3
? nfsrvw_procrastinate_v3
: nfsrvw_procrastinate
);
1045 * Now, get the write header..
1047 nfsm_srvmtofh(&nfsd
->nd_fh
);
1049 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1050 fxdr_hyper(tl
, &nfsd
->nd_off
);
1052 nfsd
->nd_stable
= fxdr_unsigned(int, *tl
++);
1054 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1055 nfsd
->nd_off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
1058 nfsd
->nd_stable
= NFSV3WRITE_UNSTABLE
;
1060 len
= fxdr_unsigned(long, *tl
);
1062 nfsd
->nd_eoff
= nfsd
->nd_off
+ len
;
1065 * Trim the header out of the mbuf list and trim off any trailing
1066 * junk so that the mbuf list has only the write data.
1074 adjust
= dpos
- mtod(mp
, caddr_t
);
1075 mp
->m_len
-= adjust
;
1076 if (mp
->m_len
> 0 && adjust
> 0)
1077 NFSMADV(mp
, adjust
);
1084 mp
->m_len
-= (i
- len
);
1090 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1094 nfsm_writereply(2 * NFSX_UNSIGNED
, v3
);
1096 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1097 nfsd
->nd_mreq
= mreq
;
1098 nfsd
->nd_mrep
= NULL
;
1103 * Add this entry to the hash and time queues.
1107 wp
= slp
->ns_tq
.lh_first
;
1108 while (wp
&& wp
->nd_time
< nfsd
->nd_time
) {
1110 wp
= wp
->nd_tq
.le_next
;
1112 NFS_DPF(WG
, ("Q%03x", nfsd
->nd_retxid
& 0xfff));
1114 LIST_INSERT_AFTER(owp
, nfsd
, nd_tq
);
1116 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1118 if (nfsd
->nd_mrep
) {
1119 wpp
= NWDELAYHASH(slp
, nfsd
->nd_fh
.fh_fid
.fid_data
);
1123 bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1125 wp
= wp
->nd_hash
.le_next
;
1127 while (wp
&& wp
->nd_off
< nfsd
->nd_off
&&
1128 !bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1130 wp
= wp
->nd_hash
.le_next
;
1133 LIST_INSERT_AFTER(owp
, nfsd
, nd_hash
);
1136 * Search the hash list for overlapping entries and
1139 for(; nfsd
&& NFSW_CONTIG(owp
, nfsd
); nfsd
= wp
) {
1140 wp
= nfsd
->nd_hash
.le_next
;
1141 if (NFSW_SAMECRED(owp
, nfsd
))
1142 nfsrvw_coalesce(owp
, nfsd
);
1145 LIST_INSERT_HEAD(wpp
, nfsd
, nd_hash
);
1152 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1153 * and generate the associated reply mbuf list(s).
1157 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1159 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= owp
) {
1160 owp
= nfsd
->nd_tq
.le_next
;
1161 if (nfsd
->nd_time
> cur_usec
)
1165 NFS_DPF(WG
, ("P%03x", nfsd
->nd_retxid
& 0xfff));
1166 LIST_REMOVE(nfsd
, nd_tq
);
1167 LIST_REMOVE(nfsd
, nd_hash
);
1169 mrep
= nfsd
->nd_mrep
;
1170 nfsd
->nd_mrep
= NULL
;
1171 cred
= &nfsd
->nd_cr
;
1172 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1173 forat_ret
= aftat_ret
= 1;
1174 error
= nfsrv_fhtovp(&nfsd
->nd_fh
, 1, &vp
, cred
, slp
,
1175 nfsd
->nd_nam
, &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
1178 forat_ret
= VOP_GETATTR(vp
, &forat
, cred
, procp
);
1179 if (vp
->v_type
!= VREG
) {
1183 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
1188 nqsrv_getl(vp
, ND_WRITE
);
1189 error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
, procp
, 1);
1192 if (nfsd
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1193 ioflags
= IO_NODELOCKED
;
1194 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
)
1195 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1197 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1198 uiop
->uio_rw
= UIO_WRITE
;
1199 uiop
->uio_segflg
= UIO_SYSSPACE
;
1200 uiop
->uio_procp
= (struct proc
*)0;
1201 uiop
->uio_offset
= nfsd
->nd_off
;
1202 uiop
->uio_resid
= nfsd
->nd_eoff
- nfsd
->nd_off
;
1204 if (uiop
->uio_resid
> 0) {
1212 uiop
->uio_iovcnt
= i
;
1213 MALLOC(iov
, struct iovec
*, i
* sizeof (struct iovec
),
1215 uiop
->uio_iov
= ivp
= iov
;
1218 if (mp
->m_len
> 0) {
1219 ivp
->iov_base
= mtod(mp
, caddr_t
);
1220 ivp
->iov_len
= mp
->m_len
;
1226 didhold
= ubc_hold(vp
);
1227 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
1228 nfsstats
.srvvop_writes
++;
1230 FREE((caddr_t
)iov
, M_TEMP
);
1234 aftat_ret
= VOP_GETATTR(vp
, &va
, cred
, procp
);
1235 VOP_UNLOCK(vp
, 0, procp
);
1242 * Loop around generating replies for all write rpcs that have
1243 * now been completed.
1247 NFS_DPF(WG
, ("R%03x", nfsd
->nd_retxid
& 0xfff));
1249 nfsm_writereply(NFSX_WCCDATA(v3
), v3
);
1251 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1254 nfsm_writereply(NFSX_PREOPATTR(v3
) +
1255 NFSX_POSTOPORFATTR(v3
) + 2 * NFSX_UNSIGNED
+
1256 NFSX_WRITEVERF(v3
), v3
);
1258 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1259 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1260 *tl
++ = txdr_unsigned(nfsd
->nd_len
);
1261 *tl
++ = txdr_unsigned(swp
->nd_stable
);
1263 * Actually, there is no need to txdr these fields,
1264 * but it may make the values more human readable,
1265 * for debugging purposes.
1267 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
1268 *tl
= txdr_unsigned(boottime
.tv_usec
);
1270 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1271 nfsm_srvfillattr(&va
, fp
);
1274 nfsd
->nd_mreq
= mreq
;
1276 panic("nfsrv_write: nd_mrep not free");
1279 * Done. Put it at the head of the timer queue so that
1280 * the final phase can return the reply.
1285 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1287 nfsd
= swp
->nd_coalesce
.lh_first
;
1289 LIST_REMOVE(nfsd
, nd_tq
);
1295 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1302 * Search for a reply to return.
1305 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= nfsd
->nd_tq
.le_next
)
1306 if (nfsd
->nd_mreq
) {
1307 NFS_DPF(WG
, ("X%03x", nfsd
->nd_retxid
& 0xfff));
1308 LIST_REMOVE(nfsd
, nd_tq
);
1309 *mrq
= nfsd
->nd_mreq
;
1318 * Coalesce the write request nfsd into owp. To do this we must:
1319 * - remove nfsd from the queues
1320 * - merge nfsd->nd_mrep into owp->nd_mrep
1321 * - update the nd_eoff and nd_stable for owp
1322 * - put nfsd on owp's nd_coalesce list
1323 * NB: Must be called at splsoftclock().
1326 nfsrvw_coalesce(owp
, nfsd
)
1327 register struct nfsrv_descript
*owp
;
1328 register struct nfsrv_descript
*nfsd
;
1330 register int overlap
;
1331 register struct mbuf
*mp
;
1332 struct nfsrv_descript
*p
;
1334 NFS_DPF(WG
, ("C%03x-%03x",
1335 nfsd
->nd_retxid
& 0xfff, owp
->nd_retxid
& 0xfff));
1336 LIST_REMOVE(nfsd
, nd_hash
);
1337 LIST_REMOVE(nfsd
, nd_tq
);
1338 if (owp
->nd_eoff
< nfsd
->nd_eoff
) {
1339 overlap
= owp
->nd_eoff
- nfsd
->nd_off
;
1341 panic("nfsrv_coalesce: bad off");
1343 m_adj(nfsd
->nd_mrep
, overlap
);
1347 mp
->m_next
= nfsd
->nd_mrep
;
1348 owp
->nd_eoff
= nfsd
->nd_eoff
;
1350 m_freem(nfsd
->nd_mrep
);
1351 nfsd
->nd_mrep
= NULL
;
1352 if (nfsd
->nd_stable
== NFSV3WRITE_FILESYNC
)
1353 owp
->nd_stable
= NFSV3WRITE_FILESYNC
;
1354 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
&&
1355 owp
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1356 owp
->nd_stable
= NFSV3WRITE_DATASYNC
;
1357 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nfsd
, nd_tq
);
1360 * If nfsd had anything else coalesced into it, transfer them
1361 * to owp, otherwise their replies will never get sent.
1363 for (p
= nfsd
->nd_coalesce
.lh_first
; p
;
1364 p
= nfsd
->nd_coalesce
.lh_first
) {
1365 LIST_REMOVE(p
, nd_tq
);
1366 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1371 * Sort the group list in increasing numerical order.
1372 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1373 * that used to be here.)
1376 nfsrvw_sort(list
, num
)
1377 register gid_t
*list
;
1383 /* Insertion sort. */
1384 for (i
= 1; i
< num
; i
++) {
1386 /* find correct slot for value v, moving others up */
1387 for (j
= i
; --j
>= 0 && v
< list
[j
];)
1388 list
[j
+ 1] = list
[j
];
1394 * copy credentials making sure that the result can be compared with bcmp().
1397 nfsrv_setcred(incred
, outcred
)
1398 register struct ucred
*incred
, *outcred
;
1402 bzero((caddr_t
)outcred
, sizeof (struct ucred
));
1403 outcred
->cr_ref
= 1;
1404 outcred
->cr_uid
= incred
->cr_uid
;
1405 outcred
->cr_ngroups
= incred
->cr_ngroups
;
1406 for (i
= 0; i
< incred
->cr_ngroups
; i
++)
1407 outcred
->cr_groups
[i
] = incred
->cr_groups
[i
];
1408 nfsrvw_sort(outcred
->cr_groups
, outcred
->cr_ngroups
);
1412 * nfs create service
1413 * now does a truncate to 0 length via. setattr if it already exists
1416 nfsrv_create(nfsd
, slp
, procp
, mrq
)
1417 struct nfsrv_descript
*nfsd
;
1418 struct nfssvc_sock
*slp
;
1422 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1423 struct mbuf
*nam
= nfsd
->nd_nam
;
1424 caddr_t dpos
= nfsd
->nd_dpos
;
1425 struct ucred
*cred
= &nfsd
->nd_cr
;
1426 register struct nfs_fattr
*fp
;
1427 struct vattr va
, dirfor
, diraft
;
1428 register struct vattr
*vap
= &va
;
1429 register struct nfsv2_sattr
*sp
;
1430 register u_long
*tl
;
1431 struct nameidata nd
;
1432 register caddr_t cp
;
1435 int error
= 0, rdev
, cache
, len
, tsize
, dirfor_ret
= 1, diraft_ret
= 1;
1436 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), how
, exclusive_flag
= 0;
1438 struct mbuf
*mb
, *mb2
, *mreq
;
1439 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
1442 u_quad_t frev
, tempsize
;
1443 u_char cverf
[NFSX_V3CREATEVERF
];
1448 nd
.ni_cnd
.cn_nameiop
= 0;
1449 fhp
= &nfh
.fh_generic
;
1451 nfsm_srvnamesiz(len
);
1452 nd
.ni_cnd
.cn_cred
= cred
;
1453 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1454 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| SAVESTART
;
1455 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
1456 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1459 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
1463 dirp
= (struct vnode
*)0;
1467 nfsm_reply(NFSX_WCCDATA(v3
));
1468 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1475 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
1476 how
= fxdr_unsigned(int, *tl
);
1478 case NFSV3CREATE_GUARDED
:
1483 case NFSV3CREATE_UNCHECKED
:
1486 case NFSV3CREATE_EXCLUSIVE
:
1487 nfsm_dissect(cp
, caddr_t
, NFSX_V3CREATEVERF
);
1488 bcopy(cp
, cverf
, NFSX_V3CREATEVERF
);
1490 if (nd
.ni_vp
== NULL
)
1494 vap
->va_type
= VREG
;
1496 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1497 vap
->va_type
= IFTOVT(fxdr_unsigned(u_long
, sp
->sa_mode
));
1498 if (vap
->va_type
== VNON
)
1499 vap
->va_type
= VREG
;
1500 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
1501 switch (vap
->va_type
) {
1503 tsize
= fxdr_unsigned(long, sp
->sa_size
);
1505 vap
->va_size
= (u_quad_t
)tsize
;
1510 rdev
= fxdr_unsigned(long, sp
->sa_size
);
1516 * Iff doesn't exist, create it
1517 * otherwise just truncate to 0 length
1518 * should I set the mode too ??
1520 if (nd
.ni_vp
== NULL
) {
1521 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1522 vrele(nd
.ni_startdir
);
1523 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1524 error
= VOP_CREATE(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
);
1526 nfsrv_object_create(nd
.ni_vp
);
1527 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1528 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1529 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1530 if (exclusive_flag
) {
1533 bcopy(cverf
, (caddr_t
)&vap
->va_atime
,
1535 error
= VOP_SETATTR(nd
.ni_vp
, vap
, cred
,
1539 } else if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
||
1540 vap
->va_type
== VFIFO
) {
1541 if (vap
->va_type
== VCHR
&& rdev
== 0xffffffff)
1542 vap
->va_type
= VFIFO
;
1543 if (vap
->va_type
!= VFIFO
&&
1544 (error
= suser(cred
, (u_short
*)0))) {
1545 vrele(nd
.ni_startdir
);
1546 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1547 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1548 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1549 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1554 vap
->va_rdev
= (dev_t
)rdev
;
1555 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1556 if ((error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
))) {
1557 vrele(nd
.ni_startdir
);
1560 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1561 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| SAVESTART
);
1562 nd
.ni_cnd
.cn_proc
= procp
;
1563 nd
.ni_cnd
.cn_cred
= cred
;
1564 if ((error
= lookup(&nd
))) {
1565 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1566 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1567 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1570 nfsrv_object_create(nd
.ni_vp
);
1571 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1572 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1573 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1574 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
) {
1577 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1582 vrele(nd
.ni_startdir
);
1583 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1584 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1585 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1586 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1592 vrele(nd
.ni_startdir
);
1593 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1594 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1596 if (nd
.ni_dvp
== vp
)
1600 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1601 if (vap
->va_size
!= -1) {
1602 error
= nfsrv_access(vp
, VWRITE
, cred
,
1603 (nd
.ni_cnd
.cn_flags
& RDONLY
), procp
, 0);
1605 nqsrv_getl(vp
, ND_WRITE
);
1606 tempsize
= vap
->va_size
;
1608 vap
->va_size
= tempsize
;
1609 error
= VOP_SETATTR(vp
, vap
, cred
,
1616 vput(vp
); /* make sure we catch the EEXIST for nfsv3 */
1620 bzero((caddr_t
)fhp
, sizeof(nfh
));
1621 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
1622 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1624 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
1628 if (exclusive_flag
&& !error
&&
1629 bcmp(cverf
, (caddr_t
)&vap
->va_atime
, NFSX_V3CREATEVERF
))
1631 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
1634 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_FATTR(v3
) + NFSX_WCCDATA(v3
));
1637 nfsm_srvpostop_fh(fhp
);
1638 nfsm_srvpostop_attr(0, vap
);
1640 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1642 nfsm_srvfhtom(fhp
, v3
);
1643 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1644 nfsm_srvfillattr(vap
, fp
);
1650 if (nd
.ni_cnd
.cn_nameiop
) {
1651 vrele(nd
.ni_startdir
);
1652 FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1653 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1654 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1656 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1657 if (nd
.ni_dvp
== nd
.ni_vp
)
1667 * nfs v3 mknod service
1670 nfsrv_mknod(nfsd
, slp
, procp
, mrq
)
1671 struct nfsrv_descript
*nfsd
;
1672 struct nfssvc_sock
*slp
;
1676 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1677 struct mbuf
*nam
= nfsd
->nd_nam
;
1678 caddr_t dpos
= nfsd
->nd_dpos
;
1679 struct ucred
*cred
= &nfsd
->nd_cr
;
1680 struct vattr va
, dirfor
, diraft
;
1681 register struct vattr
*vap
= &va
;
1682 register u_long
*tl
;
1683 struct nameidata nd
;
1686 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
1687 u_long major
, minor
;
1690 struct mbuf
*mb
, *mb2
, *mreq
;
1691 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
1696 nd
.ni_cnd
.cn_nameiop
= 0;
1697 fhp
= &nfh
.fh_generic
;
1699 nfsm_srvnamesiz(len
);
1700 nd
.ni_cnd
.cn_cred
= cred
;
1701 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1702 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| SAVESTART
;
1703 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
1704 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1706 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
, procp
);
1708 nfsm_reply(NFSX_WCCDATA(1));
1709 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1714 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
1715 vtyp
= nfsv3tov_type(*tl
);
1716 if (vtyp
!= VCHR
&& vtyp
!= VBLK
&& vtyp
!= VSOCK
&& vtyp
!= VFIFO
) {
1717 vrele(nd
.ni_startdir
);
1718 FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1719 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1720 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1721 error
= NFSERR_BADTYPE
;
1722 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1728 if (vtyp
== VCHR
|| vtyp
== VBLK
) {
1729 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1730 major
= fxdr_unsigned(u_long
, *tl
++);
1731 minor
= fxdr_unsigned(u_long
, *tl
);
1732 vap
->va_rdev
= makedev(major
, minor
);
1736 * Iff doesn't exist, create it.
1739 vrele(nd
.ni_startdir
);
1740 FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1741 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1742 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1744 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1748 vap
->va_type
= vtyp
;
1749 if (vtyp
== VSOCK
) {
1750 vrele(nd
.ni_startdir
);
1751 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1752 error
= VOP_CREATE(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
);
1754 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1755 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1756 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1758 if (vtyp
!= VFIFO
&& (error
= suser(cred
, (u_short
*)0))) {
1759 vrele(nd
.ni_startdir
);
1760 FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1761 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1762 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1763 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1767 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1768 if ((error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
))) {
1769 vrele(nd
.ni_startdir
);
1772 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1773 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| SAVESTART
);
1774 nd
.ni_cnd
.cn_proc
= procp
;
1775 nd
.ni_cnd
.cn_cred
= procp
->p_ucred
;
1776 error
= lookup(&nd
);
1777 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1778 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1781 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
) {
1784 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1791 bzero((caddr_t
)fhp
, sizeof(nfh
));
1792 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
1793 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1795 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
1798 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
1800 nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
1802 nfsm_srvpostop_fh(fhp
);
1803 nfsm_srvpostop_attr(0, vap
);
1805 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1810 if (nd
.ni_cnd
.cn_nameiop
) {
1811 vrele(nd
.ni_startdir
);
1812 FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1813 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1814 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1816 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1817 if (nd
.ni_dvp
== nd
.ni_vp
)
1827 * nfs remove service
1830 nfsrv_remove(nfsd
, slp
, procp
, mrq
)
1831 struct nfsrv_descript
*nfsd
;
1832 struct nfssvc_sock
*slp
;
1836 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1837 struct mbuf
*nam
= nfsd
->nd_nam
;
1838 caddr_t dpos
= nfsd
->nd_dpos
;
1839 struct ucred
*cred
= &nfsd
->nd_cr
;
1840 struct nameidata nd
;
1841 register u_long
*tl
;
1844 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
1845 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1847 struct mbuf
*mb
, *mreq
;
1848 struct vnode
*vp
, *dirp
;
1849 struct vattr dirfor
, diraft
;
1855 vp
= (struct vnode
*)0;
1857 fhp
= &nfh
.fh_generic
;
1859 nfsm_srvnamesiz(len
);
1860 nd
.ni_cnd
.cn_cred
= cred
;
1861 nd
.ni_cnd
.cn_nameiop
= DELETE
;
1862 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1863 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
1864 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1867 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
1874 if (vp
->v_type
== VDIR
) {
1875 error
= EPERM
; /* POSIX */
1879 * The root of a mounted filesystem cannot be deleted.
1881 if (vp
->v_flag
& VROOT
) {
1887 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1888 nqsrv_getl(vp
, ND_WRITE
);
1890 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1893 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1894 if (nd
.ni_dvp
== vp
)
1902 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
1905 nfsm_reply(NFSX_WCCDATA(v3
));
1907 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1914 * nfs rename service
1917 nfsrv_rename(nfsd
, slp
, procp
, mrq
)
1918 struct nfsrv_descript
*nfsd
;
1919 struct nfssvc_sock
*slp
;
1923 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1924 struct mbuf
*nam
= nfsd
->nd_nam
;
1925 caddr_t dpos
= nfsd
->nd_dpos
;
1926 struct ucred
*cred
= &nfsd
->nd_cr
;
1927 register u_long
*tl
;
1930 int error
= 0, cache
, len
, len2
, fdirfor_ret
= 1, fdiraft_ret
= 1;
1931 int tdirfor_ret
= 1, tdiraft_ret
= 1;
1932 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1934 struct mbuf
*mb
, *mreq
;
1935 struct nameidata fromnd
, tond
;
1936 struct vnode
*fvp
, *tvp
, *tdvp
, *fdirp
= (struct vnode
*)0;
1937 struct vnode
*tdirp
= (struct vnode
*)0;
1938 struct vattr fdirfor
, fdiraft
, tdirfor
, tdiraft
;
1940 fhandle_t
*ffhp
, *tfhp
;
1945 fvp
= (struct vnode
*)0;
1947 ffhp
= &fnfh
.fh_generic
;
1948 tfhp
= &tnfh
.fh_generic
;
1949 fromnd
.ni_cnd
.cn_nameiop
= 0;
1950 tond
.ni_cnd
.cn_nameiop
= 0;
1951 nfsm_srvmtofh(ffhp
);
1952 nfsm_srvnamesiz(len
);
1954 * Remember our original uid so that we can reset cr_uid before
1955 * the second nfs_namei() call, in case it is remapped.
1957 saved_uid
= cred
->cr_uid
;
1958 fromnd
.ni_cnd
.cn_cred
= cred
;
1959 fromnd
.ni_cnd
.cn_nameiop
= DELETE
;
1960 fromnd
.ni_cnd
.cn_flags
= WANTPARENT
| SAVESTART
;
1961 error
= nfs_namei(&fromnd
, ffhp
, len
, slp
, nam
, &md
,
1962 &dpos
, &fdirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1965 fdirfor_ret
= VOP_GETATTR(fdirp
, &fdirfor
, cred
,
1969 fdirp
= (struct vnode
*)0;
1973 nfsm_reply(2 * NFSX_WCCDATA(v3
));
1974 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
1975 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
1981 nfsm_srvmtofh(tfhp
);
1982 nfsm_strsiz(len2
, NFS_MAXNAMLEN
);
1983 cred
->cr_uid
= saved_uid
;
1984 tond
.ni_cnd
.cn_cred
= cred
;
1985 tond
.ni_cnd
.cn_nameiop
= RENAME
;
1986 tond
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
;
1987 error
= nfs_namei(&tond
, tfhp
, len2
, slp
, nam
, &md
,
1988 &dpos
, &tdirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1991 tdirfor_ret
= VOP_GETATTR(tdirp
, &tdirfor
, cred
,
1995 tdirp
= (struct vnode
*)0;
1999 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2000 vrele(fromnd
.ni_dvp
);
2007 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2013 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2020 if (tvp
->v_type
== VDIR
&& tvp
->v_mountedhere
) {
2028 if (fvp
->v_type
== VDIR
&& fvp
->v_mountedhere
) {
2035 if (fvp
->v_mount
!= tdvp
->v_mount
) {
2048 * If source is the same as the destination (that is the
2049 * same vnode) then there is nothing to do.
2050 * (fixed to have POSIX semantics - CSM 3/2/98)
2056 nqsrv_getl(fromnd
.ni_dvp
, ND_WRITE
);
2057 nqsrv_getl(tdvp
, ND_WRITE
);
2059 nqsrv_getl(tvp
, ND_WRITE
);
2060 error
= VOP_RENAME(fromnd
.ni_dvp
, fromnd
.ni_vp
, &fromnd
.ni_cnd
,
2061 tond
.ni_dvp
, tond
.ni_vp
, &tond
.ni_cnd
);
2063 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2070 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2071 vrele(fromnd
.ni_dvp
);
2076 vrele(tond
.ni_startdir
);
2077 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2078 tond
.ni_cnd
.cn_flags
&= ~HASBUF
;
2081 fdiraft_ret
= VOP_GETATTR(fdirp
, &fdiraft
, cred
, procp
);
2085 tdiraft_ret
= VOP_GETATTR(tdirp
, &tdiraft
, cred
, procp
);
2088 vrele(fromnd
.ni_startdir
);
2089 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2090 fromnd
.ni_cnd
.cn_flags
&= ~HASBUF
;
2091 nfsm_reply(2 * NFSX_WCCDATA(v3
));
2093 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
2094 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
2103 if (tond
.ni_cnd
.cn_nameiop
) {
2104 vrele(tond
.ni_startdir
);
2105 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2106 tond
.ni_cnd
.cn_flags
&= ~HASBUF
;
2108 if (fromnd
.ni_cnd
.cn_nameiop
) {
2109 vrele(fromnd
.ni_startdir
);
2110 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
,
2111 fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2112 fromnd
.ni_cnd
.cn_flags
&= ~HASBUF
;
2113 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2114 vrele(fromnd
.ni_dvp
);
2124 nfsrv_link(nfsd
, slp
, procp
, mrq
)
2125 struct nfsrv_descript
*nfsd
;
2126 struct nfssvc_sock
*slp
;
2130 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2131 struct mbuf
*nam
= nfsd
->nd_nam
;
2132 caddr_t dpos
= nfsd
->nd_dpos
;
2133 struct ucred
*cred
= &nfsd
->nd_cr
;
2134 struct nameidata nd
;
2135 register u_long
*tl
;
2138 int error
= 0, rdonly
, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2139 int getret
= 1, v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2141 struct mbuf
*mb
, *mreq
;
2142 struct vnode
*vp
, *xp
, *dirp
= (struct vnode
*)0;
2143 struct vattr dirfor
, diraft
, at
;
2145 fhandle_t
*fhp
, *dfhp
;
2148 fhp
= &nfh
.fh_generic
;
2149 dfhp
= &dnfh
.fh_generic
;
2151 nfsm_srvmtofh(dfhp
);
2152 nfsm_srvnamesiz(len
);
2153 if ((error
= nfsrv_fhtovp(fhp
, FALSE
, &vp
, cred
, slp
, nam
,
2154 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
2155 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2156 nfsm_srvpostop_attr(getret
, &at
);
2157 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2160 if (vp
->v_type
== VDIR
) {
2161 error
= EPERM
; /* POSIX */
2164 nd
.ni_cnd
.cn_cred
= cred
;
2165 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2166 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2167 error
= nfs_namei(&nd
, dfhp
, len
, slp
, nam
, &md
, &dpos
,
2168 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2171 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2175 dirp
= (struct vnode
*)0;
2186 if (vp
->v_mount
!= xp
->v_mount
)
2190 nqsrv_getl(vp
, ND_WRITE
);
2191 nqsrv_getl(xp
, ND_WRITE
);
2192 error
= VOP_LINK(vp
, nd
.ni_dvp
, &nd
.ni_cnd
);
2194 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2195 if (nd
.ni_dvp
== nd
.ni_vp
)
2204 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2206 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2210 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2212 nfsm_srvpostop_attr(getret
, &at
);
2213 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2220 * nfs symbolic link service
2223 nfsrv_symlink(nfsd
, slp
, procp
, mrq
)
2224 struct nfsrv_descript
*nfsd
;
2225 struct nfssvc_sock
*slp
;
2229 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2230 struct mbuf
*nam
= nfsd
->nd_nam
;
2231 caddr_t dpos
= nfsd
->nd_dpos
;
2232 struct ucred
*cred
= &nfsd
->nd_cr
;
2233 struct vattr va
, dirfor
, diraft
;
2234 struct nameidata nd
;
2235 register struct vattr
*vap
= &va
;
2236 register u_long
*tl
;
2238 struct nfsv2_sattr
*sp
;
2239 char *bpos
, *pathcp
= (char *)0, *cp2
;
2242 int error
= 0, cache
, len
, len2
, dirfor_ret
= 1, diraft_ret
= 1;
2243 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2244 struct mbuf
*mb
, *mreq
, *mb2
;
2245 struct vnode
*dirp
= (struct vnode
*)0;
2250 nd
.ni_cnd
.cn_nameiop
= 0;
2251 fhp
= &nfh
.fh_generic
;
2253 nfsm_srvnamesiz(len
);
2254 nd
.ni_cnd
.cn_cred
= cred
;
2255 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2256 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| SAVESTART
;
2257 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
2258 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2261 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2265 dirp
= (struct vnode
*)0;
2273 nfsm_strsiz(len2
, NFS_MAXPATHLEN
);
2274 MALLOC(pathcp
, caddr_t
, len2
+ 1, M_TEMP
, M_WAITOK
);
2275 iv
.iov_base
= pathcp
;
2277 io
.uio_resid
= len2
;
2281 io
.uio_segflg
= UIO_SYSSPACE
;
2282 io
.uio_rw
= UIO_READ
;
2283 io
.uio_procp
= (struct proc
*)0;
2284 nfsm_mtouio(&io
, len2
);
2286 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2287 vap
->va_mode
= fxdr_unsigned(u_short
, sp
->sa_mode
);
2289 *(pathcp
+ len2
) = '\0';
2291 vrele(nd
.ni_startdir
);
2292 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2293 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
2294 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2295 if (nd
.ni_dvp
== nd
.ni_vp
)
2303 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2304 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
, pathcp
);
2306 vrele(nd
.ni_startdir
);
2309 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2310 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| SAVESTART
| FOLLOW
);
2311 nd
.ni_cnd
.cn_flags
|= (NOFOLLOW
| LOCKLEAF
);
2312 nd
.ni_cnd
.cn_proc
= procp
;
2313 nd
.ni_cnd
.cn_cred
= cred
;
2314 error
= lookup(&nd
);
2316 bzero((caddr_t
)fhp
, sizeof(nfh
));
2317 fhp
->fh_fsid
= nd
.ni_vp
->v_mount
->mnt_stat
.f_fsid
;
2318 error
= VFS_VPTOFH(nd
.ni_vp
, &fhp
->fh_fid
);
2320 error
= VOP_GETATTR(nd
.ni_vp
, vap
, cred
,
2325 vrele(nd
.ni_startdir
);
2326 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2327 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
2331 FREE(pathcp
, M_TEMP
);
2333 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2336 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2339 nfsm_srvpostop_fh(fhp
);
2340 nfsm_srvpostop_attr(0, vap
);
2342 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2346 if (nd
.ni_cnd
.cn_nameiop
) {
2347 vrele(nd
.ni_startdir
);
2348 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2349 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
2353 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2354 if (nd
.ni_dvp
== nd
.ni_vp
)
2361 FREE(pathcp
, M_TEMP
);
2369 nfsrv_mkdir(nfsd
, slp
, procp
, mrq
)
2370 struct nfsrv_descript
*nfsd
;
2371 struct nfssvc_sock
*slp
;
2375 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2376 struct mbuf
*nam
= nfsd
->nd_nam
;
2377 caddr_t dpos
= nfsd
->nd_dpos
;
2378 struct ucred
*cred
= &nfsd
->nd_cr
;
2379 struct vattr va
, dirfor
, diraft
;
2380 register struct vattr
*vap
= &va
;
2381 register struct nfs_fattr
*fp
;
2382 struct nameidata nd
;
2383 register caddr_t cp
;
2384 register u_long
*tl
;
2387 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2388 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2390 struct mbuf
*mb
, *mb2
, *mreq
;
2391 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
2396 fhp
= &nfh
.fh_generic
;
2398 nfsm_srvnamesiz(len
);
2399 nd
.ni_cnd
.cn_cred
= cred
;
2400 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2401 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2402 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
2403 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2406 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2410 dirp
= (struct vnode
*)0;
2414 nfsm_reply(NFSX_WCCDATA(v3
));
2415 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2424 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
2425 vap
->va_mode
= nfstov_mode(*tl
++);
2427 vap
->va_type
= VDIR
;
2430 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2431 if (nd
.ni_dvp
== vp
)
2439 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2440 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
);
2443 bzero((caddr_t
)fhp
, sizeof(nfh
));
2444 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
2445 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
2447 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
2452 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2455 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2458 nfsm_srvpostop_fh(fhp
);
2459 nfsm_srvpostop_attr(0, vap
);
2461 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2463 nfsm_srvfhtom(fhp
, v3
);
2464 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
2465 nfsm_srvfillattr(vap
, fp
);
2471 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2472 if (nd
.ni_dvp
== nd
.ni_vp
)
2485 nfsrv_rmdir(nfsd
, slp
, procp
, mrq
)
2486 struct nfsrv_descript
*nfsd
;
2487 struct nfssvc_sock
*slp
;
2491 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2492 struct mbuf
*nam
= nfsd
->nd_nam
;
2493 caddr_t dpos
= nfsd
->nd_dpos
;
2494 struct ucred
*cred
= &nfsd
->nd_cr
;
2495 register u_long
*tl
;
2498 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2499 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2501 struct mbuf
*mb
, *mreq
;
2502 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
2503 struct vattr dirfor
, diraft
;
2506 struct nameidata nd
;
2509 fhp
= &nfh
.fh_generic
;
2511 nfsm_srvnamesiz(len
);
2512 nd
.ni_cnd
.cn_cred
= cred
;
2513 nd
.ni_cnd
.cn_nameiop
= DELETE
;
2514 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2515 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
2516 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2519 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2523 dirp
= (struct vnode
*)0;
2527 nfsm_reply(NFSX_WCCDATA(v3
));
2528 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2534 if (vp
->v_type
!= VDIR
) {
2539 * No rmdir "." please.
2541 if (nd
.ni_dvp
== vp
) {
2546 * The root of a mounted filesystem cannot be deleted.
2548 if (vp
->v_flag
& VROOT
)
2552 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2553 nqsrv_getl(vp
, ND_WRITE
);
2554 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2556 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2557 if (nd
.ni_dvp
== nd
.ni_vp
)
2564 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2567 nfsm_reply(NFSX_WCCDATA(v3
));
2569 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2576 * nfs readdir service
2577 * - mallocs what it thinks is enough to read
2578 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2579 * - calls VOP_READDIR()
2580 * - loops around building the reply
2581 * if the output generated exceeds count break out of loop
2582 * The nfsm_clget macro is used here so that the reply will be packed
2583 * tightly in mbuf clusters.
2584 * - it only knows that it has encountered eof when the VOP_READDIR()
2586 * - as such one readdir rpc will return eof false although you are there
2587 * and then the next will return eof
2588 * - it trims out records with d_fileno == 0
2589 * this doesn't matter for Unix clients, but they might confuse clients
2591 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2592 * than requested, but this may not apply to all filesystems. For
2593 * example, client NFS does not { although it is never remote mounted
2595 * The alternate call nfsrv_readdirplus() does lookups as well.
2596 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
2597 * are supposed to cover. For readdir, the count is the total number of
2598 * bytes included in everything from the directory's postopattr through
2599 * the EOF flag. For readdirplus, the maxcount is the same, and the
2600 * dircount includes all that except for the entry attributes and handles.
2605 u_long fl_fattr
[NFSX_V3FATTR
/ sizeof (u_long
)];
2608 u_long fl_nfh
[NFSX_V3FH
/ sizeof (u_long
)];
2612 nfsrv_readdir(nfsd
, slp
, procp
, mrq
)
2613 struct nfsrv_descript
*nfsd
;
2614 struct nfssvc_sock
*slp
;
2618 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2619 struct mbuf
*nam
= nfsd
->nd_nam
;
2620 caddr_t dpos
= nfsd
->nd_dpos
;
2621 struct ucred
*cred
= &nfsd
->nd_cr
;
2622 register char *bp
, *be
;
2623 register struct mbuf
*mp
;
2624 register struct dirent
*dp
;
2625 register caddr_t cp
;
2626 register u_long
*tl
;
2629 struct mbuf
*mb
, *mb2
, *mreq
, *mp2
;
2630 char *cpos
, *cend
, *cp2
, *rbuf
;
2637 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2638 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, cache
, ncookies
= 0;
2639 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2640 u_quad_t frev
, off
, toff
, verf
;
2641 u_long
*cookies
= NULL
, *cookiep
;
2643 fhp
= &nfh
.fh_generic
;
2646 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
2647 fxdr_hyper(tl
, &toff
);
2649 fxdr_hyper(tl
, &verf
);
2652 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2653 toff
= fxdr_unsigned(u_quad_t
, *tl
++);
2656 cnt
= fxdr_unsigned(int, *tl
);
2657 siz
= ((cnt
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
2658 xfer
= NFS_SRVMAXDATA(nfsd
);
2662 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
2663 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
2664 nfsm_reply(NFSX_UNSIGNED
);
2665 nfsm_srvpostop_attr(getret
, &at
);
2668 nqsrv_getl(vp
, ND_READ
);
2670 error
= getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2671 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
2672 error
= NFSERR_BAD_COOKIE
;
2675 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 0);
2678 nfsm_reply(NFSX_POSTOPATTR(v3
));
2679 nfsm_srvpostop_attr(getret
, &at
);
2682 VOP_UNLOCK(vp
, 0, procp
);
2683 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
2686 iv
.iov_len
= fullsiz
;
2689 io
.uio_offset
= (off_t
)off
;
2690 io
.uio_resid
= fullsiz
;
2691 io
.uio_segflg
= UIO_SYSSPACE
;
2692 io
.uio_rw
= UIO_READ
;
2693 io
.uio_procp
= (struct proc
*)0;
2697 _FREE((caddr_t
)cookies
, M_TEMP
);
2700 if (error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, procp
)) {
2701 FREE((caddr_t
)rbuf
, M_TEMP
);
2702 nfsm_reply(NFSX_POSTOPATTR(v3
));
2703 nfsm_srvpostop_attr(getret
, &at
);
2706 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
2707 off
= (off_t
)io
.uio_offset
;
2709 * We cannot set the error in the case where there are no cookies
2710 * and no error, only, as FreeBSD. In the scenario the client is
2711 * calling us back being told there were "more" entries on last readdir
2712 * return, and we have no more entries, our VOP_READDIR can give
2713 * cookies = NULL and no error. This is due to a zero size to MALLOC
2714 * returning NULL unlike FreeBSD which returns a pointer.
2715 * With FreeBSD it makes sense if the MALLOC failed and you get in that
2716 * bind. For us, we need something more. Thus, we should make sure we
2717 * had some cookies to return, but no pointer and no error for EPERM case.
2718 * Otherwise, go thru normal processing of sending back the eofflag. This check
2719 * is also legit on first call to the routine by client since . and ..
2720 * should be returned. Make same change to nfsrv_readdirplus.
2722 if ((ncookies
!= 0) && !cookies
&& !error
)
2723 error
= NFSERR_PERM
;
2726 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2730 VOP_UNLOCK(vp
, 0, procp
);
2733 _FREE((caddr_t
)rbuf
, M_TEMP
);
2735 _FREE((caddr_t
)cookies
, M_TEMP
);
2736 nfsm_reply(NFSX_POSTOPATTR(v3
));
2737 nfsm_srvpostop_attr(getret
, &at
);
2741 siz
-= io
.uio_resid
;
2744 * If nothing read, return eof
2749 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) +
2752 nfsm_srvpostop_attr(getret
, &at
);
2753 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
2754 txdr_hyper(&at
.va_filerev
, tl
);
2757 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2760 FREE((caddr_t
)rbuf
, M_TEMP
);
2761 FREE((caddr_t
)cookies
, M_TEMP
);
2767 * Check for degenerate cases of nothing useful read.
2768 * If so go try again
2772 dp
= (struct dirent
*)cpos
;
2776 * For some reason FreeBSD's ufs_readdir() chooses to back the
2777 * directory offset up to a block boundary, so it is necessary to
2778 * skip over the records that preceed the requested offset. This
2779 * requires the assumption that file offset cookies monotonically
2782 while (cpos
< cend
&& ncookies
> 0 &&
2783 (dp
->d_fileno
== 0 || ((u_quad_t
)(*cookiep
)) <= toff
)) {
2785 while (dp
->d_fileno
== 0 && cpos
< cend
&& ncookies
> 0) {
2787 cpos
+= dp
->d_reclen
;
2788 dp
= (struct dirent
*)cpos
;
2792 if (cpos
>= cend
|| ncookies
== 0) {
2798 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) + siz
);
2800 len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
2801 nfsm_srvpostop_attr(getret
, &at
);
2802 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2803 txdr_hyper(&at
.va_filerev
, tl
);
2805 len
= 2 * NFSX_UNSIGNED
;
2808 be
= bp
+ M_TRAILINGSPACE(mp
);
2810 /* Loop through the records and build reply */
2811 while (cpos
< cend
&& ncookies
> 0) {
2812 if (dp
->d_fileno
!= 0) {
2813 nlen
= dp
->d_namlen
;
2814 rem
= nfsm_rndup(nlen
)-nlen
;
2815 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
2817 len
+= 2 * NFSX_UNSIGNED
;
2823 * Build the directory record xdr from
2828 bp
+= NFSX_UNSIGNED
;
2832 bp
+= NFSX_UNSIGNED
;
2835 *tl
= txdr_unsigned(dp
->d_fileno
);
2836 bp
+= NFSX_UNSIGNED
;
2838 *tl
= txdr_unsigned(nlen
);
2839 bp
+= NFSX_UNSIGNED
;
2841 /* And loop around copying the name */
2850 bcopy(cp
, bp
, tsiz
);
2856 /* And null pad to a long boundary */
2857 for (i
= 0; i
< rem
; i
++)
2861 /* Finish off the record */
2864 bp
+= NFSX_UNSIGNED
;
2867 *tl
= txdr_unsigned(*cookiep
);
2868 bp
+= NFSX_UNSIGNED
;
2870 cpos
+= dp
->d_reclen
;
2871 dp
= (struct dirent
*)cpos
;
2878 bp
+= NFSX_UNSIGNED
;
2884 bp
+= NFSX_UNSIGNED
;
2887 mp
->m_len
= bp
- mtod(mp
, caddr_t
);
2889 mp
->m_len
+= bp
- bpos
;
2890 FREE((caddr_t
)rbuf
, M_TEMP
);
2891 FREE((caddr_t
)cookies
, M_TEMP
);
2896 nfsrv_readdirplus(nfsd
, slp
, procp
, mrq
)
2897 struct nfsrv_descript
*nfsd
;
2898 struct nfssvc_sock
*slp
;
2902 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2903 struct mbuf
*nam
= nfsd
->nd_nam
;
2904 caddr_t dpos
= nfsd
->nd_dpos
;
2905 struct ucred
*cred
= &nfsd
->nd_cr
;
2906 register char *bp
, *be
;
2907 register struct mbuf
*mp
;
2908 register struct dirent
*dp
;
2909 register caddr_t cp
;
2910 register u_long
*tl
;
2913 struct mbuf
*mb
, *mb2
, *mreq
, *mp2
;
2914 char *cpos
, *cend
, *cp2
, *rbuf
;
2915 struct vnode
*vp
, *nvp
;
2918 fhandle_t
*fhp
, *nfhp
= (fhandle_t
*)fl
.fl_nfh
;
2921 struct vattr va
, at
, *vap
= &va
;
2922 struct nfs_fattr
*fp
;
2923 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2924 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, cache
, dirlen
, ncookies
= 0;
2925 u_quad_t frev
, off
, toff
, verf
;
2926 u_long
*cookies
= NULL
, *cookiep
;
2929 fhp
= &nfh
.fh_generic
;
2931 nfsm_dissect(tl
, u_long
*, 6 * NFSX_UNSIGNED
);
2932 fxdr_hyper(tl
, &toff
);
2934 fxdr_hyper(tl
, &verf
);
2936 siz
= fxdr_unsigned(int, *tl
++);
2937 cnt
= fxdr_unsigned(int, *tl
);
2939 siz
= ((siz
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
2940 xfer
= NFS_SRVMAXDATA(nfsd
);
2944 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
2945 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
2946 nfsm_reply(NFSX_UNSIGNED
);
2947 nfsm_srvpostop_attr(getret
, &at
);
2950 error
= getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2951 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
2952 error
= NFSERR_BAD_COOKIE
;
2954 nqsrv_getl(vp
, ND_READ
);
2955 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 0);
2959 nfsm_reply(NFSX_V3POSTOPATTR
);
2960 nfsm_srvpostop_attr(getret
, &at
);
2963 VOP_UNLOCK(vp
, 0, procp
);
2964 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
2967 iv
.iov_len
= fullsiz
;
2970 io
.uio_offset
= (off_t
)off
;
2971 io
.uio_resid
= fullsiz
;
2972 io
.uio_segflg
= UIO_SYSSPACE
;
2973 io
.uio_rw
= UIO_READ
;
2974 io
.uio_procp
= (struct proc
*)0;
2977 _FREE((caddr_t
)cookies
, M_TEMP
);
2980 if (error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, procp
)) {
2981 FREE((caddr_t
)rbuf
, M_TEMP
);
2982 nfsm_reply(NFSX_V3POSTOPATTR
);
2983 nfsm_srvpostop_attr(getret
, &at
);
2986 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
2987 off
= (u_quad_t
)io
.uio_offset
;
2988 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2989 VOP_UNLOCK(vp
, 0, procp
);
2991 * See nfsrv_readdir comment above on this
2993 if ((ncookies
!= 0) && !cookies
&& !error
)
2994 error
= NFSERR_PERM
;
3001 _FREE((caddr_t
)cookies
, M_TEMP
);
3002 _FREE((caddr_t
)rbuf
, M_TEMP
);
3003 nfsm_reply(NFSX_V3POSTOPATTR
);
3004 nfsm_srvpostop_attr(getret
, &at
);
3008 siz
-= io
.uio_resid
;
3011 * If nothing read, return eof
3016 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+
3018 nfsm_srvpostop_attr(getret
, &at
);
3019 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
3020 txdr_hyper(&at
.va_filerev
, tl
);
3024 FREE((caddr_t
)cookies
, M_TEMP
);
3025 FREE((caddr_t
)rbuf
, M_TEMP
);
3031 * Check for degenerate cases of nothing useful read.
3032 * If so go try again
3036 dp
= (struct dirent
*)cpos
;
3040 * For some reason FreeBSD's ufs_readdir() chooses to back the
3041 * directory offset up to a block boundary, so it is necessary to
3042 * skip over the records that preceed the requested offset. This
3043 * requires the assumption that file offset cookies monotonically
3046 while (cpos
< cend
&& ncookies
> 0 &&
3047 (dp
->d_fileno
== 0 || ((u_quad_t
)(*cookiep
)) <= toff
)) {
3049 while (dp
->d_fileno
== 0 && cpos
< cend
&& ncookies
> 0) {
3051 cpos
+= dp
->d_reclen
;
3052 dp
= (struct dirent
*)cpos
;
3056 if (cpos
>= cend
|| ncookies
== 0) {
3063 * Probe one of the directory entries to see if the filesystem
3064 * supports VGET. See later comment for VFS_VGET changes.
3066 if (vp
->v_tag
== VT_UFS
)
3067 file
= (void *) dp
->d_fileno
;
3069 file
= &dp
->d_fileno
;
3072 if (error
= VFS_VGET(vp
->v_mount
, file
, &nvp
)) {
3073 if (error
== EOPNOTSUPP
) /* let others get passed back */
3074 error
= NFSERR_NOTSUPP
;
3076 _FREE((caddr_t
)cookies
, M_TEMP
);
3077 _FREE((caddr_t
)rbuf
, M_TEMP
);
3078 nfsm_reply(NFSX_V3POSTOPATTR
);
3079 nfsm_srvpostop_attr(getret
, &at
);
3084 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3086 nfsm_srvpostop_attr(getret
, &at
);
3087 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3088 txdr_hyper(&at
.va_filerev
, tl
);
3091 be
= bp
+ M_TRAILINGSPACE(mp
);
3093 /* Loop through the records and build reply */
3094 while (cpos
< cend
&& ncookies
> 0) {
3095 if (dp
->d_fileno
!= 0) {
3096 nlen
= dp
->d_namlen
;
3097 rem
= nfsm_rndup(nlen
)-nlen
;
3100 * Got to get the vnode for lookup per entry.
3101 * HFS+/volfs and others use address of file identifier to VGET
3102 * UFS, nullfs, umapfs use inode (u_int32_t)
3103 * until they are consistent, we must differentiate now.
3104 * UFS is the only one of the latter class that is exported.
3105 * Note this will be pulled out as we resolve the VGET issue
3106 * of which it should use u_in32_t or addresses.
3109 if (vp
->v_tag
== VT_UFS
)
3110 file
= (void *) dp
->d_fileno
;
3112 file
= &dp
->d_fileno
;
3114 if (VFS_VGET(vp
->v_mount
, file
, &nvp
))
3116 bzero((caddr_t
)nfhp
, NFSX_V3FH
);
3118 nvp
->v_mount
->mnt_stat
.f_fsid
;
3119 if (VFS_VPTOFH(nvp
, &nfhp
->fh_fid
)) {
3123 if (VOP_GETATTR(nvp
, vap
, cred
, procp
)) {
3130 * If either the dircount or maxcount will be
3131 * exceeded, get out now. Both of these lengths
3132 * are calculated conservatively, including all
3135 len
+= (8 * NFSX_UNSIGNED
+ nlen
+ rem
+ NFSX_V3FH
+
3137 dirlen
+= (6 * NFSX_UNSIGNED
+ nlen
+ rem
);
3138 if (len
> cnt
|| dirlen
> fullsiz
) {
3144 * Build the directory record xdr from
3147 fp
= (struct nfs_fattr
*)&fl
.fl_fattr
;
3148 nfsm_srvfillattr(vap
, fp
);
3149 fl
.fl_fhsize
= txdr_unsigned(NFSX_V3FH
);
3150 fl
.fl_fhok
= nfs_true
;
3151 fl
.fl_postopok
= nfs_true
;
3152 fl
.fl_off
.nfsuquad
[0] = 0;
3153 fl
.fl_off
.nfsuquad
[1] = txdr_unsigned(*cookiep
);
3157 bp
+= NFSX_UNSIGNED
;
3160 bp
+= NFSX_UNSIGNED
;
3162 *tl
= txdr_unsigned(dp
->d_fileno
);
3163 bp
+= NFSX_UNSIGNED
;
3165 *tl
= txdr_unsigned(nlen
);
3166 bp
+= NFSX_UNSIGNED
;
3168 /* And loop around copying the name */
3173 if ((bp
+ xfer
) > be
)
3177 bcopy(cp
, bp
, tsiz
);
3183 /* And null pad to a long boundary */
3184 for (i
= 0; i
< rem
; i
++)
3188 * Now copy the flrep structure out.
3190 xfer
= sizeof (struct flrep
);
3194 if ((bp
+ xfer
) > be
)
3198 bcopy(cp
, bp
, tsiz
);
3206 cpos
+= dp
->d_reclen
;
3207 dp
= (struct dirent
*)cpos
;
3214 bp
+= NFSX_UNSIGNED
;
3220 bp
+= NFSX_UNSIGNED
;
3223 mp
->m_len
= bp
- mtod(mp
, caddr_t
);
3225 mp
->m_len
+= bp
- bpos
;
3226 FREE((caddr_t
)cookies
, M_TEMP
);
3227 FREE((caddr_t
)rbuf
, M_TEMP
);
3232 * nfs commit service
3235 nfsrv_commit(nfsd
, slp
, procp
, mrq
)
3236 struct nfsrv_descript
*nfsd
;
3237 struct nfssvc_sock
*slp
;
3241 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3242 struct mbuf
*nam
= nfsd
->nd_nam
;
3243 caddr_t dpos
= nfsd
->nd_dpos
;
3244 struct ucred
*cred
= &nfsd
->nd_cr
;
3245 struct vattr bfor
, aft
;
3249 register u_long
*tl
;
3252 int error
= 0, rdonly
, for_ret
= 1, aft_ret
= 1, cnt
, cache
;
3254 struct mbuf
*mb
, *mb2
, *mreq
;
3261 fhp
= &nfh
.fh_generic
;
3263 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
3266 * XXX At this time VOP_FSYNC() does not accept offset and byte
3267 * count parameters, so these arguments are useless (someday maybe).
3269 fxdr_hyper(tl
, &off
);
3271 cnt
= fxdr_unsigned(int, *tl
);
3272 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3273 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3274 nfsm_reply(2 * NFSX_UNSIGNED
);
3275 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
3278 for_ret
= VOP_GETATTR(vp
, &bfor
, cred
, procp
);
3279 didhold
= ubc_hold(vp
);
3280 error
= VOP_FSYNC(vp
, cred
, MNT_WAIT
, procp
);
3281 aft_ret
= VOP_GETATTR(vp
, &aft
, cred
, procp
);
3282 VOP_UNLOCK(vp
, 0, procp
);
3286 nfsm_reply(NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
3287 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
3289 nfsm_build(tl
, u_long
*, NFSX_V3WRITEVERF
);
3290 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
3291 *tl
= txdr_unsigned(boottime
.tv_usec
);
3298 * nfs statfs service
3301 nfsrv_statfs(nfsd
, slp
, procp
, mrq
)
3302 struct nfsrv_descript
*nfsd
;
3303 struct nfssvc_sock
*slp
;
3307 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3308 struct mbuf
*nam
= nfsd
->nd_nam
;
3309 caddr_t dpos
= nfsd
->nd_dpos
;
3310 struct ucred
*cred
= &nfsd
->nd_cr
;
3311 register struct statfs
*sf
;
3312 register struct nfs_statfs
*sfp
;
3313 register u_long
*tl
;
3316 int error
= 0, rdonly
, cache
, getret
= 1;
3317 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3319 struct mbuf
*mb
, *mb2
, *mreq
;
3324 struct statfs statfs
;
3325 u_quad_t frev
, tval
;
3330 fhp
= &nfh
.fh_generic
;
3332 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3333 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3334 nfsm_reply(NFSX_UNSIGNED
);
3335 nfsm_srvpostop_attr(getret
, &at
);
3339 error
= VFS_STATFS(vp
->v_mount
, sf
, procp
);
3340 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
3342 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_STATFS(v3
));
3344 nfsm_srvpostop_attr(getret
, &at
);
3347 nfsm_build(sfp
, struct nfs_statfs
*, NFSX_STATFS(v3
));
3349 tval
= (u_quad_t
)sf
->f_blocks
;
3350 tval
*= (u_quad_t
)sf
->f_bsize
;
3351 txdr_hyper(&tval
, &sfp
->sf_tbytes
);
3352 tval
= (u_quad_t
)sf
->f_bfree
;
3353 tval
*= (u_quad_t
)sf
->f_bsize
;
3354 txdr_hyper(&tval
, &sfp
->sf_fbytes
);
3355 tval
= (u_quad_t
)sf
->f_bavail
;
3356 tval
*= (u_quad_t
)sf
->f_bsize
;
3357 txdr_hyper(&tval
, &sfp
->sf_abytes
);
3358 sfp
->sf_tfiles
.nfsuquad
[0] = 0;
3359 sfp
->sf_tfiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_files
);
3360 sfp
->sf_ffiles
.nfsuquad
[0] = 0;
3361 sfp
->sf_ffiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3362 sfp
->sf_afiles
.nfsuquad
[0] = 0;
3363 sfp
->sf_afiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3364 sfp
->sf_invarsec
= 0;
3366 sfp
->sf_tsize
= txdr_unsigned(NFS_V2MAXDATA
);
3367 sfp
->sf_bsize
= txdr_unsigned(sf
->f_bsize
);
3368 sfp
->sf_blocks
= txdr_unsigned(sf
->f_blocks
);
3369 sfp
->sf_bfree
= txdr_unsigned(sf
->f_bfree
);
3370 sfp
->sf_bavail
= txdr_unsigned(sf
->f_bavail
);
3376 * nfs fsinfo service
3379 nfsrv_fsinfo(nfsd
, slp
, procp
, mrq
)
3380 struct nfsrv_descript
*nfsd
;
3381 struct nfssvc_sock
*slp
;
3385 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3386 struct mbuf
*nam
= nfsd
->nd_nam
;
3387 caddr_t dpos
= nfsd
->nd_dpos
;
3388 struct ucred
*cred
= &nfsd
->nd_cr
;
3389 register u_long
*tl
;
3390 register struct nfsv3_fsinfo
*sip
;
3393 int error
= 0, rdonly
, cache
, getret
= 1, pref
, max
;
3395 struct mbuf
*mb
, *mb2
, *mreq
;
3405 fhp
= &nfh
.fh_generic
;
3407 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3408 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3409 nfsm_reply(NFSX_UNSIGNED
);
3410 nfsm_srvpostop_attr(getret
, &at
);
3413 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
3415 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
3416 nfsm_srvpostop_attr(getret
, &at
);
3417 nfsm_build(sip
, struct nfsv3_fsinfo
*, NFSX_V3FSINFO
);
3421 * There should be file system VFS OP(s) to get this information.
3422 * For now, assume our usual NFS defaults.
3424 if (slp
->ns_so
->so_type
== SOCK_DGRAM
)
3425 max
= pref
= NFS_MAXDGRAMDATA
;
3427 max
= pref
= NFS_MAXDATA
;
3428 sip
->fs_rtmax
= txdr_unsigned(max
);
3429 sip
->fs_rtpref
= txdr_unsigned(pref
);
3430 sip
->fs_rtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3431 sip
->fs_wtmax
= txdr_unsigned(max
);
3432 sip
->fs_wtpref
= txdr_unsigned(pref
);
3433 sip
->fs_wtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3434 sip
->fs_dtpref
= txdr_unsigned(pref
);
3435 sip
->fs_maxfilesize
.nfsuquad
[0] = 0xffffffff;
3436 sip
->fs_maxfilesize
.nfsuquad
[1] = 0xffffffff;
3437 sip
->fs_timedelta
.nfsv3_sec
= 0;
3438 sip
->fs_timedelta
.nfsv3_nsec
= txdr_unsigned(1);
3439 sip
->fs_properties
= txdr_unsigned(NFSV3FSINFO_LINK
|
3440 NFSV3FSINFO_SYMLINK
| NFSV3FSINFO_HOMOGENEOUS
|
3441 NFSV3FSINFO_CANSETTIME
);
3446 * nfs pathconf service
3449 nfsrv_pathconf(nfsd
, slp
, procp
, mrq
)
3450 struct nfsrv_descript
*nfsd
;
3451 struct nfssvc_sock
*slp
;
3455 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3456 struct mbuf
*nam
= nfsd
->nd_nam
;
3457 caddr_t dpos
= nfsd
->nd_dpos
;
3458 struct ucred
*cred
= &nfsd
->nd_cr
;
3459 register u_long
*tl
;
3460 register struct nfsv3_pathconf
*pc
;
3463 int error
= 0, rdonly
, cache
, getret
= 1, linkmax
, namemax
;
3464 int chownres
, notrunc
, case_sensitive
, case_preserving
;
3466 struct mbuf
*mb
, *mb2
, *mreq
;
3476 fhp
= &nfh
.fh_generic
;
3478 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3479 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3480 nfsm_reply(NFSX_UNSIGNED
);
3481 nfsm_srvpostop_attr(getret
, &at
);
3484 error
= VOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
);
3486 error
= VOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
);
3488 error
= VOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
);
3490 error
= VOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
);
3492 error
= VOP_PATHCONF(vp
, _PC_CASE_SENSITIVE
, &case_sensitive
);
3494 error
= VOP_PATHCONF(vp
, _PC_CASE_PRESERVING
, &case_preserving
);
3495 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
3497 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
3498 nfsm_srvpostop_attr(getret
, &at
);
3501 nfsm_build(pc
, struct nfsv3_pathconf
*, NFSX_V3PATHCONF
);
3503 pc
->pc_linkmax
= txdr_unsigned(linkmax
);
3504 pc
->pc_namemax
= txdr_unsigned(namemax
);
3505 pc
->pc_notrunc
= txdr_unsigned(notrunc
);
3506 pc
->pc_chownrestricted
= txdr_unsigned(chownres
);
3507 pc
->pc_caseinsensitive
= txdr_unsigned(!case_sensitive
);
3508 pc
->pc_casepreserving
= txdr_unsigned(case_preserving
);
3514 * Null operation, used by clients to ping server
3518 nfsrv_null(nfsd
, slp
, procp
, mrq
)
3519 struct nfsrv_descript
*nfsd
;
3520 struct nfssvc_sock
*slp
;
3524 struct mbuf
*mrep
= nfsd
->nd_mrep
;
3526 int error
= NFSERR_RETVOID
, cache
;
3527 struct mbuf
*mb
, *mreq
;
3538 * No operation, used for obsolete procedures
3542 nfsrv_noop(nfsd
, slp
, procp
, mrq
)
3543 struct nfsrv_descript
*nfsd
;
3544 struct nfssvc_sock
*slp
;
3548 struct mbuf
*mrep
= nfsd
->nd_mrep
;
3551 struct mbuf
*mb
, *mreq
;
3557 if (nfsd
->nd_repstat
)
3558 error
= nfsd
->nd_repstat
;
3560 error
= EPROCUNAVAIL
;
3566 * Perform access checking for vnodes obtained from file handles that would
3567 * refer to files already opened by a Unix client. You cannot just use
3568 * vn_writechk() and VOP_ACCESS() for two reasons.
3569 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3570 * 2 - The owner is to be given access irrespective of mode bits so that
3571 * processes that chmod after opening a file don't break. I don't like
3572 * this because it opens a security hole, but since the nfs server opens
3573 * a security hole the size of a barn door anyhow, what the heck.
3575 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
3576 * will return EPERM instead of EACCESS. EPERM is always an error.
3580 nfsrv_access(vp
, flags
, cred
, rdonly
, p
, override
)
3581 register struct vnode
*vp
;
3583 register struct ucred
*cred
;
3590 if (flags
& VWRITE
) {
3591 /* Just vn_writechk() changed to check rdonly */
3593 * Disallow write attempts on read-only file systems;
3594 * unless the file is a socket or a block or character
3595 * device resident on the file system.
3597 if (rdonly
|| (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
3598 switch (vp
->v_type
) {
3599 case VREG
: case VDIR
: case VLNK
: case VCPLX
:
3604 * If there's shared text associated with
3605 * the inode, we can't allow writing.
3607 if (vp
->v_flag
& VTEXT
)
3610 if ((error
= VOP_GETATTR(vp
, &vattr
, cred
, p
)))
3612 error
= VOP_ACCESS(vp
, flags
, cred
, p
);
3614 * Allow certain operations for the owner (reads and writes
3615 * on files that are already open). Picking up from FreeBSD.
3617 if (override
&& error
== EACCES
&& cred
->cr_uid
== vattr
.va_uid
)
3621 #endif /* NFS_NOSERVER */