]>
git.saurik.com Git - apple/xnu.git/blob - bsd/nfs/nfs_serv.c
2 * Copyright (c) 2000-2004 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>
100 #include <sys/vmparam.h>
101 #include <machine/spl.h>
103 #include <nfs/nfsproto.h>
104 #include <nfs/rpcv2.h>
106 #include <nfs/xdr_subs.h>
107 #include <nfs/nfsm_subs.h>
108 #include <nfs/nqnfs.h>
110 nfstype nfsv3_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFSOCK
,
113 nfstype nfsv2_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFNON
,
116 extern u_long nfs_xdrneg1
;
117 extern u_long nfs_false
, nfs_true
;
118 extern enum vtype nv3tov_type
[8];
119 extern struct nfsstats nfsstats
;
121 int nfsrvw_procrastinate
= NFS_GATHERDELAY
* 1000;
122 int nfsrvw_procrastinate_v3
= 0;
126 /* XXX CSM 11/25/97 Upgrade sysctl.h someday */
127 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, async
, CTLFLAG_RW
, &nfs_async
, 0, "");
130 static int nfsrv_access
__P((struct vnode
*,int,struct ucred
*,int,
131 struct proc
*, int));
132 static void nfsrvw_coalesce
__P((struct nfsrv_descript
*,
133 struct nfsrv_descript
*));
136 * nfs v3 access service
139 nfsrv3_access(nfsd
, slp
, procp
, mrq
)
140 struct nfsrv_descript
*nfsd
;
141 struct nfssvc_sock
*slp
;
145 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
146 struct mbuf
*nam
= nfsd
->nd_nam
;
147 caddr_t dpos
= nfsd
->nd_dpos
;
148 struct ucred
*cred
= &nfsd
->nd_cr
;
155 int error
= 0, rdonly
, cache
, getret
;
157 struct mbuf
*mb
, *mreq
, *mb2
;
158 struct vattr vattr
, *vap
= &vattr
;
159 u_long testmode
, nfsmode
;
165 fhp
= &nfh
.fh_generic
;
167 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
168 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
169 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
170 nfsm_reply(NFSX_UNSIGNED
);
171 nfsm_srvpostop_attr(1, (struct vattr
*)0);
174 nfsmode
= fxdr_unsigned(u_long
, *tl
);
175 if ((nfsmode
& NFSV3ACCESS_READ
) &&
176 nfsrv_access(vp
, VREAD
, cred
, rdonly
, procp
, 0))
177 nfsmode
&= ~NFSV3ACCESS_READ
;
178 if (vp
->v_type
== VDIR
)
179 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
|
182 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
);
183 if ((nfsmode
& testmode
) &&
184 nfsrv_access(vp
, VWRITE
, cred
, rdonly
, procp
, 0))
185 nfsmode
&= ~testmode
;
186 if (vp
->v_type
== VDIR
)
187 testmode
= NFSV3ACCESS_LOOKUP
;
189 testmode
= NFSV3ACCESS_EXECUTE
;
190 if ((nfsmode
& testmode
) &&
191 nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 0))
192 nfsmode
&= ~testmode
;
193 getret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
195 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED
);
196 nfsm_srvpostop_attr(getret
, vap
);
197 nfsm_build(tl
, u_long
*, NFSX_UNSIGNED
);
198 *tl
= txdr_unsigned(nfsmode
);
203 * nfs getattr service
206 nfsrv_getattr(nfsd
, slp
, procp
, mrq
)
207 struct nfsrv_descript
*nfsd
;
208 struct nfssvc_sock
*slp
;
212 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
213 struct mbuf
*nam
= nfsd
->nd_nam
;
214 caddr_t dpos
= nfsd
->nd_dpos
;
215 struct ucred
*cred
= &nfsd
->nd_cr
;
216 register struct nfs_fattr
*fp
;
218 register struct vattr
*vap
= &va
;
225 int error
= 0, rdonly
, cache
;
227 struct mbuf
*mb
, *mb2
, *mreq
;
230 fhp
= &nfh
.fh_generic
;
232 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
233 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
237 nqsrv_getl(vp
, ND_READ
);
238 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
240 nfsm_reply(NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
243 nfsm_build(fp
, struct nfs_fattr
*, NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
244 nfsm_srvfillattr(vap
, fp
);
249 * nfs setattr service
252 nfsrv_setattr(nfsd
, slp
, procp
, mrq
)
253 struct nfsrv_descript
*nfsd
;
254 struct nfssvc_sock
*slp
;
258 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
259 struct mbuf
*nam
= nfsd
->nd_nam
;
260 caddr_t dpos
= nfsd
->nd_dpos
;
261 struct ucred
*cred
= &nfsd
->nd_cr
;
262 struct vattr va
, preat
;
263 register struct vattr
*vap
= &va
;
264 register struct nfsv2_sattr
*sp
;
265 register struct nfs_fattr
*fp
;
272 int error
= 0, rdonly
, cache
, preat_ret
= 1, postat_ret
= 1;
273 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), gcheck
= 0;
275 struct mbuf
*mb
, *mb2
, *mreq
;
277 struct timespec guard
;
279 fhp
= &nfh
.fh_generic
;
284 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
285 gcheck
= fxdr_unsigned(int, *tl
);
287 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
288 fxdr_nfsv3time(tl
, &guard
);
291 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
293 * Nah nah nah nah na nah
294 * There is a bug in the Sun client that puts 0xffff in the mode
295 * field of sattr when it should put in 0xffffffff. The u_short
296 * doesn't sign extend.
297 * --> check the low order 2 bytes for 0xffff
299 if ((fxdr_unsigned(int, sp
->sa_mode
) & 0xffff) != 0xffff)
300 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
301 if (sp
->sa_uid
!= nfs_xdrneg1
)
302 vap
->va_uid
= fxdr_unsigned(uid_t
, sp
->sa_uid
);
303 if (sp
->sa_gid
!= nfs_xdrneg1
)
304 vap
->va_gid
= fxdr_unsigned(gid_t
, sp
->sa_gid
);
305 if (sp
->sa_size
!= nfs_xdrneg1
)
306 vap
->va_size
= fxdr_unsigned(u_quad_t
, sp
->sa_size
);
307 if (sp
->sa_atime
.nfsv2_sec
!= nfs_xdrneg1
) {
309 fxdr_nfsv2time(&sp
->sa_atime
, &vap
->va_atime
);
311 vap
->va_atime
.tv_sec
=
312 fxdr_unsigned(long, sp
->sa_atime
.nfsv2_sec
);
313 vap
->va_atime
.tv_nsec
= 0;
316 if (sp
->sa_mtime
.nfsv2_sec
!= nfs_xdrneg1
)
317 fxdr_nfsv2time(&sp
->sa_mtime
, &vap
->va_mtime
);
322 * Now that we have all the fields, lets do it.
324 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
325 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
326 nfsm_reply(2 * NFSX_UNSIGNED
);
327 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
330 nqsrv_getl(vp
, ND_WRITE
);
332 error
= preat_ret
= VOP_GETATTR(vp
, &preat
, cred
, procp
);
333 if (!error
&& gcheck
&&
334 (preat
.va_ctime
.tv_sec
!= guard
.tv_sec
||
335 preat
.va_ctime
.tv_nsec
!= guard
.tv_nsec
))
336 error
= NFSERR_NOT_SYNC
;
339 nfsm_reply(NFSX_WCCDATA(v3
));
340 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
346 * If the size is being changed write acces is required, otherwise
347 * just check for a read only file system.
349 if (vap
->va_size
== ((u_quad_t
)((quad_t
) -1))) {
350 if (rdonly
|| (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
355 if (vp
->v_type
== VDIR
) {
358 } else if ((error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
,
362 error
= VOP_SETATTR(vp
, vap
, cred
, procp
);
363 postat_ret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
368 nfsm_reply(NFSX_WCCORFATTR(v3
));
370 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
373 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
374 nfsm_srvfillattr(vap
, fp
);
383 nfsrv_lookup(nfsd
, slp
, procp
, mrq
)
384 struct nfsrv_descript
*nfsd
;
385 struct nfssvc_sock
*slp
;
389 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
390 struct mbuf
*nam
= nfsd
->nd_nam
;
391 caddr_t dpos
= nfsd
->nd_dpos
;
392 struct ucred
*cred
= &nfsd
->nd_cr
;
393 register struct nfs_fattr
*fp
;
394 struct nameidata nd
, *ndp
= &nd
;
396 struct nameidata ind
;
398 struct vnode
*vp
, *dirp
;
405 int error
= 0, cache
, len
, dirattr_ret
= 1;
406 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), pubflag
;
408 struct mbuf
*mb
, *mb2
, *mreq
;
409 struct vattr va
, dirattr
, *vap
= &va
;
412 fhp
= &nfh
.fh_generic
;
414 nfsm_srvnamesiz(len
);
416 pubflag
= nfs_ispublicfh(fhp
);
418 nd
.ni_cnd
.cn_cred
= cred
;
419 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
420 nd
.ni_cnd
.cn_flags
= LOCKLEAF
| SAVESTART
;
421 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
422 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), pubflag
);
424 /* XXX CSM 12/4/97 Revisit when enabling WebNFS */
426 if (!error
&& pubflag
) {
427 if (nd
.ni_vp
->v_type
== VDIR
&& nfs_pub
.np_index
!= NULL
) {
429 * Setup call to lookup() to see if we can find
430 * the index file. Arguably, this doesn't belong
434 VOP_UNLOCK(nd
.ni_vp
, 0, procp
);
435 ind
.ni_pathlen
= strlen(nfs_pub
.np_index
);
436 ind
.ni_cnd
.cn_nameptr
= ind
.ni_cnd
.cn_pnbuf
=
438 ind
.ni_startdir
= nd
.ni_vp
;
439 VREF(ind
.ni_startdir
);
440 error
= lookup(&ind
);
443 * Found an index file. Get rid of
444 * the old references.
449 vrele(nd
.ni_startdir
);
455 * If the public filehandle was used, check that this lookup
456 * didn't result in a filehandle outside the publicly exported
460 if (!error
&& ndp
->ni_vp
->v_mount
!= nfs_pub
.np_mount
) {
469 dirattr_ret
= VOP_GETATTR(dirp
, &dirattr
, cred
,
475 nfsm_reply(NFSX_POSTOPATTR(v3
));
476 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
480 nqsrv_getl(ndp
->ni_startdir
, ND_READ
);
481 vrele(ndp
->ni_startdir
);
482 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
483 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
485 bzero((caddr_t
)fhp
, sizeof(nfh
));
486 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
487 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
489 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
491 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPORFATTR(v3
) + NFSX_POSTOPATTR(v3
));
493 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
496 nfsm_srvfhtom(fhp
, v3
);
498 nfsm_srvpostop_attr(0, vap
);
499 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
501 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
502 nfsm_srvfillattr(vap
, fp
);
508 * nfs readlink service
511 nfsrv_readlink(nfsd
, slp
, procp
, mrq
)
512 struct nfsrv_descript
*nfsd
;
513 struct nfssvc_sock
*slp
;
517 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
518 struct mbuf
*nam
= nfsd
->nd_nam
;
519 caddr_t dpos
= nfsd
->nd_dpos
;
520 struct ucred
*cred
= &nfsd
->nd_cr
;
521 struct iovec iv
[(NFS_MAXPATHLEN
+MLEN
-1)/MLEN
];
522 register struct iovec
*ivp
= iv
;
523 register struct mbuf
*mp
;
527 int error
= 0, rdonly
, cache
, i
, tlen
, len
, getret
;
528 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
530 struct mbuf
*mb
, *mb2
, *mp2
, *mp3
, *mreq
;
535 struct uio io
, *uiop
= &io
;
539 mp2
= mp3
= (struct mbuf
*)0;
541 fhp
= &nfh
.fh_generic
;
545 while (len
< NFS_MAXPATHLEN
) {
546 MGET(mp
, M_WAIT
, MT_DATA
);
548 mp
->m_len
= NFSMSIZ(mp
);
555 if ((len
+mp
->m_len
) > NFS_MAXPATHLEN
) {
556 mp
->m_len
= NFS_MAXPATHLEN
-len
;
557 len
= NFS_MAXPATHLEN
;
560 ivp
->iov_base
= mtod(mp
, caddr_t
);
561 ivp
->iov_len
= mp
->m_len
;
566 uiop
->uio_iovcnt
= i
;
567 uiop
->uio_offset
= 0;
568 uiop
->uio_resid
= len
;
569 uiop
->uio_rw
= UIO_READ
;
570 uiop
->uio_segflg
= UIO_SYSSPACE
;
571 uiop
->uio_procp
= (struct proc
*)0;
572 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
573 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
575 nfsm_reply(2 * NFSX_UNSIGNED
);
576 nfsm_srvpostop_attr(1, (struct vattr
*)0);
579 if (vp
->v_type
!= VLNK
) {
586 nqsrv_getl(vp
, ND_READ
);
587 error
= VOP_READLINK(vp
, uiop
, cred
);
589 getret
= VOP_GETATTR(vp
, &attr
, cred
, procp
);
595 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_UNSIGNED
);
597 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
);
618 nfsrv_read(nfsd
, slp
, procp
, mrq
)
619 struct nfsrv_descript
*nfsd
;
620 struct nfssvc_sock
*slp
;
624 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
625 struct mbuf
*nam
= nfsd
->nd_nam
;
626 caddr_t dpos
= nfsd
->nd_dpos
;
627 struct ucred
*cred
= &nfsd
->nd_cr
;
628 register struct iovec
*iv
;
630 register struct mbuf
*m
;
631 register struct nfs_fattr
*fp
;
636 int error
= 0, rdonly
, cache
, cnt
, len
, left
, siz
, tlen
, getret
;
637 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), reqlen
;
639 struct mbuf
*mb
, *mb2
, *mreq
;
644 struct uio io
, *uiop
= &io
;
645 struct vattr va
, *vap
= &va
;
650 fhp
= &nfh
.fh_generic
;
653 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
654 fxdr_hyper(tl
, &off
);
656 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
657 off
= (off_t
)fxdr_unsigned(u_long
, *tl
);
659 nfsm_srvstrsiz(reqlen
, NFS_SRVMAXDATA(nfsd
));
660 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
661 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
662 nfsm_reply(2 * NFSX_UNSIGNED
);
663 nfsm_srvpostop_attr(1, (struct vattr
*)0);
666 if (vp
->v_type
!= VREG
) {
670 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
673 nqsrv_getl(vp
, ND_READ
);
674 if ((error
= nfsrv_access(vp
, VREAD
, cred
, rdonly
, procp
, 1)))
675 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 1);
677 getret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
682 nfsm_reply(NFSX_POSTOPATTR(v3
));
683 nfsm_srvpostop_attr(getret
, vap
);
686 if (off
>= vap
->va_size
)
688 else if ((off
+ reqlen
) > vap
->va_size
)
689 cnt
= nfsm_rndup(vap
->va_size
- off
);
692 nfsm_reply(NFSX_POSTOPORFATTR(v3
) + 3 * NFSX_UNSIGNED
+nfsm_rndup(cnt
));
694 nfsm_build(tl
, u_long
*, NFSX_V3FATTR
+ 4 * NFSX_UNSIGNED
);
696 fp
= (struct nfs_fattr
*)tl
;
697 tl
+= (NFSX_V3FATTR
/ sizeof (u_long
));
699 nfsm_build(tl
, u_long
*, NFSX_V2FATTR
+ NFSX_UNSIGNED
);
700 fp
= (struct nfs_fattr
*)tl
;
701 tl
+= (NFSX_V2FATTR
/ sizeof (u_long
));
706 * Generate the mbuf list with the uio_iov ref. to it.
711 siz
= min(M_TRAILINGSPACE(m
), left
);
717 MGET(m
, M_WAIT
, MT_DATA
);
724 MALLOC(iv
, struct iovec
*, i
* sizeof (struct iovec
),
726 uiop
->uio_iov
= iv2
= iv
;
732 panic("nfsrv_read iov");
733 siz
= min(M_TRAILINGSPACE(m
), left
);
735 iv
->iov_base
= mtod(m
, caddr_t
) + m
->m_len
;
744 uiop
->uio_iovcnt
= i
;
745 uiop
->uio_offset
= off
;
746 uiop
->uio_resid
= cnt
;
747 uiop
->uio_rw
= UIO_READ
;
748 uiop
->uio_segflg
= UIO_SYSSPACE
;
749 didhold
= ubc_hold(vp
);
750 error
= VOP_READ(vp
, uiop
, IO_NODELOCKED
, cred
);
751 off
= uiop
->uio_offset
;
752 FREE((caddr_t
)iv2
, M_TEMP
);
754 * This may seem a little weird that we drop the whole
755 * successful read if we get an error on the getattr.
756 * The reason is because we've already set up the reply
757 * to have postop attrs and omitting these optional bits
758 * would require shifting all the data in the reply.
760 * It would be more correct if we would simply drop the
761 * postop attrs if the getattr fails. We might be able to
762 * do that easier if we allocated separate mbufs for the data.
764 if (error
|| (getret
= VOP_GETATTR(vp
, vap
, cred
, procp
))) {
765 VOP_UNLOCK(vp
, 0, procp
);
772 nfsm_reply(NFSX_POSTOPATTR(v3
));
773 nfsm_srvpostop_attr(getret
, vap
);
776 VOP_UNLOCK(vp
, 0, procp
);
784 nfsm_srvfillattr(vap
, fp
);
785 len
-= uiop
->uio_resid
;
786 tlen
= nfsm_rndup(len
);
787 if (cnt
!= tlen
|| tlen
!= len
)
788 nfsm_adj(mb
, cnt
- tlen
, tlen
- len
);
790 *tl
++ = txdr_unsigned(len
);
796 *tl
= txdr_unsigned(len
);
804 nfsrv_write(nfsd
, slp
, procp
, mrq
)
805 struct nfsrv_descript
*nfsd
;
806 struct nfssvc_sock
*slp
;
810 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
811 struct mbuf
*nam
= nfsd
->nd_nam
;
812 caddr_t dpos
= nfsd
->nd_dpos
;
813 struct ucred
*cred
= &nfsd
->nd_cr
;
814 register struct iovec
*ivp
;
816 register struct mbuf
*mp
;
817 register struct nfs_fattr
*fp
;
819 struct vattr va
, forat
;
820 register struct vattr
*vap
= &va
;
824 int error
= 0, rdonly
, cache
, len
, forat_ret
= 1;
825 int ioflags
, aftat_ret
= 1, retlen
, zeroing
, adjust
;
826 int stable
= NFSV3WRITE_FILESYNC
;
827 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
829 struct mbuf
*mb
, *mb2
, *mreq
;
833 struct uio io
, *uiop
= &io
;
842 fhp
= &nfh
.fh_generic
;
845 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
846 fxdr_hyper(tl
, &off
);
848 stable
= fxdr_unsigned(int, *tl
++);
850 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
851 off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
854 stable
= NFSV3WRITE_UNSTABLE
;
856 retlen
= len
= fxdr_unsigned(long, *tl
);
860 * For NFS Version 2, it is not obvious what a write of zero length
861 * should do, but I might as well be consistent with Version 3,
862 * which is to return ok so long as there are no permission problems.
870 adjust
= dpos
- mtod(mp
, caddr_t
);
872 if (mp
->m_len
> 0 && adjust
> 0)
877 else if (mp
->m_len
> 0) {
880 mp
->m_len
-= (i
- len
);
889 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
891 nfsm_reply(2 * NFSX_UNSIGNED
);
892 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
895 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
896 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
897 nfsm_reply(2 * NFSX_UNSIGNED
);
898 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
902 forat_ret
= VOP_GETATTR(vp
, &forat
, cred
, procp
);
903 if (vp
->v_type
!= VREG
) {
907 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
910 nqsrv_getl(vp
, ND_WRITE
);
911 error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
, procp
, 1);
915 nfsm_reply(NFSX_WCCDATA(v3
));
916 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
921 MALLOC(ivp
, struct iovec
*, cnt
* sizeof (struct iovec
), M_TEMP
,
923 uiop
->uio_iov
= iv
= ivp
;
924 uiop
->uio_iovcnt
= cnt
;
928 ivp
->iov_base
= mtod(mp
, caddr_t
);
929 ivp
->iov_len
= mp
->m_len
;
937 * The IO_METASYNC flag indicates that all metadata (and not just
938 * enough to ensure data integrity) mus be written to stable storage
940 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
942 if (stable
== NFSV3WRITE_UNSTABLE
)
943 ioflags
= IO_NODELOCKED
;
944 else if (stable
== NFSV3WRITE_DATASYNC
)
945 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
947 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
948 uiop
->uio_resid
= len
;
949 uiop
->uio_rw
= UIO_WRITE
;
950 uiop
->uio_segflg
= UIO_SYSSPACE
;
951 uiop
->uio_procp
= (struct proc
*)0;
952 uiop
->uio_offset
= off
;
953 didhold
= ubc_hold(vp
);
954 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
955 nfsstats
.srvvop_writes
++;
956 FREE((caddr_t
)iv
, M_TEMP
);
958 aftat_ret
= VOP_GETATTR(vp
, vap
, cred
, procp
);
959 VOP_UNLOCK(vp
, 0, procp
);
965 nfsm_reply(NFSX_PREOPATTR(v3
) + NFSX_POSTOPORFATTR(v3
) +
966 2 * NFSX_UNSIGNED
+ NFSX_WRITEVERF(v3
));
968 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
971 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
972 *tl
++ = txdr_unsigned(retlen
);
974 * If nfs_async is set, then pretend the write was FILESYNC.
976 if (stable
== NFSV3WRITE_UNSTABLE
&& !nfs_async
)
977 *tl
++ = txdr_unsigned(stable
);
979 *tl
++ = txdr_unsigned(NFSV3WRITE_FILESYNC
);
981 * Actually, there is no need to txdr these fields,
982 * but it may make the values more human readable,
983 * for debugging purposes.
985 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
986 *tl
= txdr_unsigned(boottime
.tv_usec
);
988 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
989 nfsm_srvfillattr(vap
, fp
);
995 * NFS write service with write gathering support. Called when
996 * nfsrvw_procrastinate > 0.
997 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
998 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1002 nfsrv_writegather(ndp
, slp
, procp
, mrq
)
1003 struct nfsrv_descript
**ndp
;
1004 struct nfssvc_sock
*slp
;
1008 register struct iovec
*ivp
;
1009 register struct mbuf
*mp
;
1010 register struct nfsrv_descript
*wp
, *nfsd
, *owp
, *swp
;
1011 register struct nfs_fattr
*fp
;
1014 struct nfsrvw_delayhash
*wpp
;
1016 struct vattr va
, forat
;
1017 register u_long
*tl
;
1020 int error
= 0, rdonly
, cache
, len
, forat_ret
= 1;
1021 int ioflags
, aftat_ret
= 1, s
, adjust
, v3
, zeroing
;
1023 struct mbuf
*mb
, *mb2
, *mreq
, *mrep
, *md
;
1025 struct uio io
, *uiop
= &io
;
1026 u_quad_t frev
, cur_usec
;
1038 mrep
= nfsd
->nd_mrep
;
1040 dpos
= nfsd
->nd_dpos
;
1041 cred
= &nfsd
->nd_cr
;
1042 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1043 LIST_INIT(&nfsd
->nd_coalesce
);
1044 nfsd
->nd_mreq
= NULL
;
1045 nfsd
->nd_stable
= NFSV3WRITE_FILESYNC
;
1047 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1048 nfsd
->nd_time
= cur_usec
+
1049 (v3
? nfsrvw_procrastinate_v3
: nfsrvw_procrastinate
);
1052 * Now, get the write header..
1054 nfsm_srvmtofh(&nfsd
->nd_fh
);
1056 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
1057 fxdr_hyper(tl
, &nfsd
->nd_off
);
1059 nfsd
->nd_stable
= fxdr_unsigned(int, *tl
++);
1061 nfsm_dissect(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1062 nfsd
->nd_off
= (off_t
)fxdr_unsigned(u_long
, *++tl
);
1065 nfsd
->nd_stable
= NFSV3WRITE_UNSTABLE
;
1067 len
= fxdr_unsigned(long, *tl
);
1069 nfsd
->nd_eoff
= nfsd
->nd_off
+ len
;
1072 * Trim the header out of the mbuf list and trim off any trailing
1073 * junk so that the mbuf list has only the write data.
1081 adjust
= dpos
- mtod(mp
, caddr_t
);
1082 mp
->m_len
-= adjust
;
1083 if (mp
->m_len
> 0 && adjust
> 0)
1084 NFSMADV(mp
, adjust
);
1091 mp
->m_len
-= (i
- len
);
1097 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1102 nfsm_writereply(2 * NFSX_UNSIGNED
, v3
);
1104 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1105 nfsd
->nd_mreq
= mreq
;
1106 nfsd
->nd_mrep
= NULL
;
1111 * Add this entry to the hash and time queues.
1115 wp
= slp
->ns_tq
.lh_first
;
1116 while (wp
&& wp
->nd_time
< nfsd
->nd_time
) {
1118 wp
= wp
->nd_tq
.le_next
;
1120 NFS_DPF(WG
, ("Q%03x", nfsd
->nd_retxid
& 0xfff));
1122 LIST_INSERT_AFTER(owp
, nfsd
, nd_tq
);
1124 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1126 if (nfsd
->nd_mrep
) {
1127 wpp
= NWDELAYHASH(slp
, nfsd
->nd_fh
.fh_fid
.fid_data
);
1131 bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1133 wp
= wp
->nd_hash
.le_next
;
1135 while (wp
&& wp
->nd_off
< nfsd
->nd_off
&&
1136 !bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1138 wp
= wp
->nd_hash
.le_next
;
1141 LIST_INSERT_AFTER(owp
, nfsd
, nd_hash
);
1144 * Search the hash list for overlapping entries and
1147 for(; nfsd
&& NFSW_CONTIG(owp
, nfsd
); nfsd
= wp
) {
1148 wp
= nfsd
->nd_hash
.le_next
;
1149 if (NFSW_SAMECRED(owp
, nfsd
))
1150 nfsrvw_coalesce(owp
, nfsd
);
1153 LIST_INSERT_HEAD(wpp
, nfsd
, nd_hash
);
1160 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1161 * and generate the associated reply mbuf list(s).
1165 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1167 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= owp
) {
1168 owp
= nfsd
->nd_tq
.le_next
;
1169 if (nfsd
->nd_time
> cur_usec
)
1173 NFS_DPF(WG
, ("P%03x", nfsd
->nd_retxid
& 0xfff));
1174 LIST_REMOVE(nfsd
, nd_tq
);
1175 LIST_REMOVE(nfsd
, nd_hash
);
1177 mrep
= nfsd
->nd_mrep
;
1178 nfsd
->nd_mrep
= NULL
;
1179 cred
= &nfsd
->nd_cr
;
1180 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1181 forat_ret
= aftat_ret
= 1;
1182 error
= nfsrv_fhtovp(&nfsd
->nd_fh
, 1, &vp
, cred
, slp
,
1183 nfsd
->nd_nam
, &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
1186 forat_ret
= VOP_GETATTR(vp
, &forat
, cred
, procp
);
1187 if (vp
->v_type
!= VREG
) {
1191 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
1196 nqsrv_getl(vp
, ND_WRITE
);
1197 error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
, procp
, 1);
1200 if (nfsd
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1201 ioflags
= IO_NODELOCKED
;
1202 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
)
1203 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1205 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1206 uiop
->uio_rw
= UIO_WRITE
;
1207 uiop
->uio_segflg
= UIO_SYSSPACE
;
1208 uiop
->uio_procp
= (struct proc
*)0;
1209 uiop
->uio_offset
= nfsd
->nd_off
;
1210 uiop
->uio_resid
= nfsd
->nd_eoff
- nfsd
->nd_off
;
1212 if (uiop
->uio_resid
> 0) {
1220 uiop
->uio_iovcnt
= i
;
1221 MALLOC(iov
, struct iovec
*, i
* sizeof (struct iovec
),
1223 uiop
->uio_iov
= ivp
= iov
;
1226 if (mp
->m_len
> 0) {
1227 ivp
->iov_base
= mtod(mp
, caddr_t
);
1228 ivp
->iov_len
= mp
->m_len
;
1234 didhold
= ubc_hold(vp
);
1235 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
1236 nfsstats
.srvvop_writes
++;
1238 FREE((caddr_t
)iov
, M_TEMP
);
1243 aftat_ret
= VOP_GETATTR(vp
, &va
, cred
, procp
);
1244 VOP_UNLOCK(vp
, 0, procp
);
1251 * Loop around generating replies for all write rpcs that have
1252 * now been completed.
1256 NFS_DPF(WG
, ("R%03x", nfsd
->nd_retxid
& 0xfff));
1258 nfsm_writereply(NFSX_WCCDATA(v3
), v3
);
1260 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1263 nfsm_writereply(NFSX_PREOPATTR(v3
) +
1264 NFSX_POSTOPORFATTR(v3
) + 2 * NFSX_UNSIGNED
+
1265 NFSX_WRITEVERF(v3
), v3
);
1267 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1268 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
1269 *tl
++ = txdr_unsigned(nfsd
->nd_len
);
1270 *tl
++ = txdr_unsigned(swp
->nd_stable
);
1272 * Actually, there is no need to txdr these fields,
1273 * but it may make the values more human readable,
1274 * for debugging purposes.
1276 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
1277 *tl
= txdr_unsigned(boottime
.tv_usec
);
1279 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1280 nfsm_srvfillattr(&va
, fp
);
1283 nfsd
->nd_mreq
= mreq
;
1285 panic("nfsrv_write: nd_mrep not free");
1288 * Done. Put it at the head of the timer queue so that
1289 * the final phase can return the reply.
1294 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1296 nfsd
= swp
->nd_coalesce
.lh_first
;
1298 LIST_REMOVE(nfsd
, nd_tq
);
1304 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1311 * Search for a reply to return.
1314 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= nfsd
->nd_tq
.le_next
)
1315 if (nfsd
->nd_mreq
) {
1316 NFS_DPF(WG
, ("X%03x", nfsd
->nd_retxid
& 0xfff));
1317 LIST_REMOVE(nfsd
, nd_tq
);
1318 *mrq
= nfsd
->nd_mreq
;
1327 * Coalesce the write request nfsd into owp. To do this we must:
1328 * - remove nfsd from the queues
1329 * - merge nfsd->nd_mrep into owp->nd_mrep
1330 * - update the nd_eoff and nd_stable for owp
1331 * - put nfsd on owp's nd_coalesce list
1332 * NB: Must be called at splsoftclock().
1335 nfsrvw_coalesce(owp
, nfsd
)
1336 register struct nfsrv_descript
*owp
;
1337 register struct nfsrv_descript
*nfsd
;
1339 register int overlap
;
1340 register struct mbuf
*mp
;
1341 struct nfsrv_descript
*p
;
1343 NFS_DPF(WG
, ("C%03x-%03x",
1344 nfsd
->nd_retxid
& 0xfff, owp
->nd_retxid
& 0xfff));
1345 LIST_REMOVE(nfsd
, nd_hash
);
1346 LIST_REMOVE(nfsd
, nd_tq
);
1347 if (owp
->nd_eoff
< nfsd
->nd_eoff
) {
1348 overlap
= owp
->nd_eoff
- nfsd
->nd_off
;
1350 panic("nfsrv_coalesce: bad off");
1352 m_adj(nfsd
->nd_mrep
, overlap
);
1356 mp
->m_next
= nfsd
->nd_mrep
;
1357 owp
->nd_eoff
= nfsd
->nd_eoff
;
1359 m_freem(nfsd
->nd_mrep
);
1360 nfsd
->nd_mrep
= NULL
;
1361 if (nfsd
->nd_stable
== NFSV3WRITE_FILESYNC
)
1362 owp
->nd_stable
= NFSV3WRITE_FILESYNC
;
1363 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
&&
1364 owp
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1365 owp
->nd_stable
= NFSV3WRITE_DATASYNC
;
1366 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nfsd
, nd_tq
);
1369 * If nfsd had anything else coalesced into it, transfer them
1370 * to owp, otherwise their replies will never get sent.
1372 for (p
= nfsd
->nd_coalesce
.lh_first
; p
;
1373 p
= nfsd
->nd_coalesce
.lh_first
) {
1374 LIST_REMOVE(p
, nd_tq
);
1375 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1380 * Sort the group list in increasing numerical order.
1381 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1382 * that used to be here.)
1385 nfsrvw_sort(list
, num
)
1386 register gid_t
*list
;
1392 /* Insertion sort. */
1393 for (i
= 1; i
< num
; i
++) {
1395 /* find correct slot for value v, moving others up */
1396 for (j
= i
; --j
>= 0 && v
< list
[j
];)
1397 list
[j
+ 1] = list
[j
];
1403 * copy credentials making sure that the result can be compared with bcmp().
1406 nfsrv_setcred(incred
, outcred
)
1407 register struct ucred
*incred
, *outcred
;
1411 bzero((caddr_t
)outcred
, sizeof (struct ucred
));
1412 outcred
->cr_ref
= 1;
1413 outcred
->cr_uid
= incred
->cr_uid
;
1414 outcred
->cr_ngroups
= incred
->cr_ngroups
;
1415 for (i
= 0; i
< incred
->cr_ngroups
; i
++)
1416 outcred
->cr_groups
[i
] = incred
->cr_groups
[i
];
1417 nfsrvw_sort(outcred
->cr_groups
, outcred
->cr_ngroups
);
1421 * nfs create service
1422 * now does a truncate to 0 length via. setattr if it already exists
1425 nfsrv_create(nfsd
, slp
, procp
, mrq
)
1426 struct nfsrv_descript
*nfsd
;
1427 struct nfssvc_sock
*slp
;
1431 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1432 struct mbuf
*nam
= nfsd
->nd_nam
;
1433 caddr_t dpos
= nfsd
->nd_dpos
;
1434 struct ucred
*cred
= &nfsd
->nd_cr
;
1435 register struct nfs_fattr
*fp
;
1436 struct vattr va
, dirfor
, diraft
;
1437 register struct vattr
*vap
= &va
;
1438 register struct nfsv2_sattr
*sp
;
1439 register u_long
*tl
;
1440 struct nameidata nd
;
1441 register caddr_t cp
;
1444 int error
= 0, rdev
, cache
, len
, tsize
, dirfor_ret
= 1, diraft_ret
= 1;
1445 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), how
, exclusive_flag
= 0;
1447 struct mbuf
*mb
, *mb2
, *mreq
;
1448 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
1451 u_quad_t frev
, tempsize
;
1452 u_char cverf
[NFSX_V3CREATEVERF
];
1457 nd
.ni_cnd
.cn_nameiop
= 0;
1458 fhp
= &nfh
.fh_generic
;
1460 nfsm_srvnamesiz(len
);
1461 nd
.ni_cnd
.cn_cred
= cred
;
1462 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1463 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| SAVESTART
;
1464 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
1465 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1468 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
1472 dirp
= (struct vnode
*)0;
1476 nfsm_reply(NFSX_WCCDATA(v3
));
1477 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1484 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
1485 how
= fxdr_unsigned(int, *tl
);
1487 case NFSV3CREATE_GUARDED
:
1492 case NFSV3CREATE_UNCHECKED
:
1495 case NFSV3CREATE_EXCLUSIVE
:
1496 nfsm_dissect(cp
, caddr_t
, NFSX_V3CREATEVERF
);
1497 bcopy(cp
, cverf
, NFSX_V3CREATEVERF
);
1499 if (nd
.ni_vp
== NULL
)
1503 vap
->va_type
= VREG
;
1505 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1506 vap
->va_type
= IFTOVT(fxdr_unsigned(u_long
, sp
->sa_mode
));
1507 if (vap
->va_type
== VNON
)
1508 vap
->va_type
= VREG
;
1509 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
1510 switch (vap
->va_type
) {
1512 tsize
= fxdr_unsigned(long, sp
->sa_size
);
1514 vap
->va_size
= (u_quad_t
)tsize
;
1519 rdev
= fxdr_unsigned(long, sp
->sa_size
);
1525 * Iff doesn't exist, create it
1526 * otherwise just truncate to 0 length
1527 * should I set the mode too ??
1529 if (nd
.ni_vp
== NULL
) {
1530 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1531 vrele(nd
.ni_startdir
);
1532 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1533 error
= VOP_CREATE(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
);
1535 nfsrv_object_create(nd
.ni_vp
);
1536 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1537 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1538 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1539 if (exclusive_flag
) {
1542 bcopy(cverf
, (caddr_t
)&vap
->va_atime
,
1544 error
= VOP_SETATTR(nd
.ni_vp
, vap
, cred
,
1548 } else if (vap
->va_type
== VCHR
|| vap
->va_type
== VBLK
||
1549 vap
->va_type
== VFIFO
) {
1550 if (vap
->va_type
== VCHR
&& rdev
== 0xffffffff)
1551 vap
->va_type
= VFIFO
;
1552 if (vap
->va_type
!= VFIFO
&&
1553 (error
= suser(cred
, (u_short
*)0))) {
1554 vrele(nd
.ni_startdir
);
1555 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1556 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1557 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1558 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1563 vap
->va_rdev
= (dev_t
)rdev
;
1564 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1565 if ((error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
))) {
1566 vrele(nd
.ni_startdir
);
1569 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1570 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| SAVESTART
);
1571 nd
.ni_cnd
.cn_proc
= procp
;
1572 nd
.ni_cnd
.cn_cred
= cred
;
1573 if ((error
= lookup(&nd
))) {
1574 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1575 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1576 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1579 nfsrv_object_create(nd
.ni_vp
);
1580 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1581 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1582 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1583 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
) {
1586 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1591 vrele(nd
.ni_startdir
);
1592 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1593 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1594 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1595 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1601 vrele(nd
.ni_startdir
);
1602 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1603 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1605 if (nd
.ni_dvp
== vp
)
1609 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1610 if (vap
->va_size
!= -1) {
1611 error
= nfsrv_access(vp
, VWRITE
, cred
,
1612 (nd
.ni_cnd
.cn_flags
& RDONLY
), procp
, 0);
1614 nqsrv_getl(vp
, ND_WRITE
);
1615 tempsize
= vap
->va_size
;
1617 vap
->va_size
= tempsize
;
1618 error
= VOP_SETATTR(vp
, vap
, cred
,
1625 vput(vp
); /* make sure we catch the EEXIST for nfsv3 */
1629 bzero((caddr_t
)fhp
, sizeof(nfh
));
1630 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
1631 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1633 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
1637 if (exclusive_flag
&& !error
&&
1638 bcmp(cverf
, (caddr_t
)&vap
->va_atime
, NFSX_V3CREATEVERF
))
1640 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
1643 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_FATTR(v3
) + NFSX_WCCDATA(v3
));
1646 nfsm_srvpostop_fh(fhp
);
1647 nfsm_srvpostop_attr(0, vap
);
1649 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1651 nfsm_srvfhtom(fhp
, v3
);
1652 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1653 nfsm_srvfillattr(vap
, fp
);
1659 if (nd
.ni_cnd
.cn_nameiop
) {
1660 vrele(nd
.ni_startdir
);
1661 FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1662 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1663 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1665 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1666 if (nd
.ni_dvp
== nd
.ni_vp
)
1676 * nfs v3 mknod service
1679 nfsrv_mknod(nfsd
, slp
, procp
, mrq
)
1680 struct nfsrv_descript
*nfsd
;
1681 struct nfssvc_sock
*slp
;
1685 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1686 struct mbuf
*nam
= nfsd
->nd_nam
;
1687 caddr_t dpos
= nfsd
->nd_dpos
;
1688 struct ucred
*cred
= &nfsd
->nd_cr
;
1689 struct vattr va
, dirfor
, diraft
;
1690 register struct vattr
*vap
= &va
;
1691 register u_long
*tl
;
1692 struct nameidata nd
;
1695 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
1696 u_long major
, minor
;
1699 struct mbuf
*mb
, *mb2
, *mreq
;
1700 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
1705 nd
.ni_cnd
.cn_nameiop
= 0;
1706 fhp
= &nfh
.fh_generic
;
1708 nfsm_srvnamesiz(len
);
1709 nd
.ni_cnd
.cn_cred
= cred
;
1710 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1711 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| SAVESTART
;
1712 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
1713 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1715 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
, procp
);
1717 nfsm_reply(NFSX_WCCDATA(1));
1718 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1723 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
1724 vtyp
= nfsv3tov_type(*tl
);
1725 if (vtyp
!= VCHR
&& vtyp
!= VBLK
&& vtyp
!= VSOCK
&& vtyp
!= VFIFO
) {
1726 vrele(nd
.ni_startdir
);
1727 FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1728 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1729 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1730 error
= NFSERR_BADTYPE
;
1731 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1737 if (vtyp
== VCHR
|| vtyp
== VBLK
) {
1738 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
1739 major
= fxdr_unsigned(u_long
, *tl
++);
1740 minor
= fxdr_unsigned(u_long
, *tl
);
1741 vap
->va_rdev
= makedev(major
, minor
);
1745 * Iff doesn't exist, create it.
1748 vrele(nd
.ni_startdir
);
1749 FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1750 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1751 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1753 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1757 vap
->va_type
= vtyp
;
1758 if (vtyp
== VSOCK
) {
1759 vrele(nd
.ni_startdir
);
1760 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1761 error
= VOP_CREATE(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
);
1763 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
,
1764 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1765 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1767 if (vtyp
!= VFIFO
&& (error
= suser(cred
, (u_short
*)0))) {
1768 vrele(nd
.ni_startdir
);
1769 FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1770 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1771 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1772 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1776 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1777 if ((error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
))) {
1778 vrele(nd
.ni_startdir
);
1781 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
1782 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| SAVESTART
);
1783 nd
.ni_cnd
.cn_proc
= procp
;
1784 nd
.ni_cnd
.cn_cred
= procp
->p_ucred
;
1785 error
= lookup(&nd
);
1786 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1787 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1790 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
) {
1793 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1800 bzero((caddr_t
)fhp
, sizeof(nfh
));
1801 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
1802 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1804 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
1807 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
1809 nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
1811 nfsm_srvpostop_fh(fhp
);
1812 nfsm_srvpostop_attr(0, vap
);
1814 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1819 if (nd
.ni_cnd
.cn_nameiop
) {
1820 vrele(nd
.ni_startdir
);
1821 FREE_ZONE((caddr_t
)nd
.ni_cnd
.cn_pnbuf
,
1822 nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
1823 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
1825 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1826 if (nd
.ni_dvp
== nd
.ni_vp
)
1836 * nfs remove service
1839 nfsrv_remove(nfsd
, slp
, procp
, mrq
)
1840 struct nfsrv_descript
*nfsd
;
1841 struct nfssvc_sock
*slp
;
1845 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1846 struct mbuf
*nam
= nfsd
->nd_nam
;
1847 caddr_t dpos
= nfsd
->nd_dpos
;
1848 struct ucred
*cred
= &nfsd
->nd_cr
;
1849 struct nameidata nd
;
1850 register u_long
*tl
;
1853 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
1854 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1856 struct mbuf
*mb
, *mreq
;
1857 struct vnode
*vp
, *dirp
;
1858 struct vattr dirfor
, diraft
;
1864 vp
= (struct vnode
*)0;
1866 fhp
= &nfh
.fh_generic
;
1868 nfsm_srvnamesiz(len
);
1869 nd
.ni_cnd
.cn_cred
= cred
;
1870 nd
.ni_cnd
.cn_nameiop
= DELETE
;
1871 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1872 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
1873 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1876 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
1883 if (vp
->v_type
== VDIR
) {
1884 error
= EPERM
; /* POSIX */
1888 * The root of a mounted filesystem cannot be deleted.
1890 if (vp
->v_flag
& VROOT
) {
1896 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1897 nqsrv_getl(vp
, ND_WRITE
);
1899 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1902 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1903 if (nd
.ni_dvp
== vp
)
1911 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
1914 nfsm_reply(NFSX_WCCDATA(v3
));
1916 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1923 * nfs rename service
1926 nfsrv_rename(nfsd
, slp
, procp
, mrq
)
1927 struct nfsrv_descript
*nfsd
;
1928 struct nfssvc_sock
*slp
;
1932 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1933 struct mbuf
*nam
= nfsd
->nd_nam
;
1934 caddr_t dpos
= nfsd
->nd_dpos
;
1935 struct ucred
*cred
= &nfsd
->nd_cr
;
1936 register u_long
*tl
;
1939 int error
= 0, cache
, len
, len2
, fdirfor_ret
= 1, fdiraft_ret
= 1;
1940 int tdirfor_ret
= 1, tdiraft_ret
= 1;
1941 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1943 struct mbuf
*mb
, *mreq
;
1944 struct nameidata fromnd
, tond
;
1945 struct vnode
*fvp
, *tvp
, *tdvp
, *fdirp
= (struct vnode
*)0;
1946 struct vnode
*tdirp
= (struct vnode
*)0;
1947 struct vattr fdirfor
, fdiraft
, tdirfor
, tdiraft
;
1949 fhandle_t
*ffhp
, *tfhp
;
1954 fvp
= (struct vnode
*)0;
1956 ffhp
= &fnfh
.fh_generic
;
1957 tfhp
= &tnfh
.fh_generic
;
1958 fromnd
.ni_cnd
.cn_nameiop
= 0;
1959 tond
.ni_cnd
.cn_nameiop
= 0;
1960 nfsm_srvmtofh(ffhp
);
1961 nfsm_srvnamesiz(len
);
1963 * Remember our original uid so that we can reset cr_uid before
1964 * the second nfs_namei() call, in case it is remapped.
1966 saved_uid
= cred
->cr_uid
;
1967 fromnd
.ni_cnd
.cn_cred
= cred
;
1968 fromnd
.ni_cnd
.cn_nameiop
= DELETE
;
1969 fromnd
.ni_cnd
.cn_flags
= WANTPARENT
| SAVESTART
;
1970 error
= nfs_namei(&fromnd
, ffhp
, len
, slp
, nam
, &md
,
1971 &dpos
, &fdirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1974 fdirfor_ret
= VOP_GETATTR(fdirp
, &fdirfor
, cred
,
1978 fdirp
= (struct vnode
*)0;
1982 nfsm_reply(2 * NFSX_WCCDATA(v3
));
1983 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
1984 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
1990 nfsm_srvmtofh(tfhp
);
1991 nfsm_strsiz(len2
, NFS_MAXNAMLEN
);
1992 cred
->cr_uid
= saved_uid
;
1993 tond
.ni_cnd
.cn_cred
= cred
;
1994 tond
.ni_cnd
.cn_nameiop
= RENAME
;
1995 tond
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| NOCACHE
| SAVESTART
;
1996 error
= nfs_namei(&tond
, tfhp
, len2
, slp
, nam
, &md
,
1997 &dpos
, &tdirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2000 tdirfor_ret
= VOP_GETATTR(tdirp
, &tdirfor
, cred
,
2004 tdirp
= (struct vnode
*)0;
2008 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2009 vrele(fromnd
.ni_dvp
);
2016 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2022 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2029 if (tvp
->v_type
== VDIR
&& tvp
->v_mountedhere
) {
2037 if (fvp
->v_type
== VDIR
&& fvp
->v_mountedhere
) {
2044 if (fvp
->v_mount
!= tdvp
->v_mount
) {
2057 * If source is the same as the destination (that is the
2058 * same vnode) then there is nothing to do.
2059 * (fixed to have POSIX semantics - CSM 3/2/98)
2065 nqsrv_getl(fromnd
.ni_dvp
, ND_WRITE
);
2066 nqsrv_getl(tdvp
, ND_WRITE
);
2068 nqsrv_getl(tvp
, ND_WRITE
);
2069 error
= VOP_RENAME(fromnd
.ni_dvp
, fromnd
.ni_vp
, &fromnd
.ni_cnd
,
2070 tond
.ni_dvp
, tond
.ni_vp
, &tond
.ni_cnd
);
2072 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2079 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2080 vrele(fromnd
.ni_dvp
);
2085 vrele(tond
.ni_startdir
);
2086 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2087 tond
.ni_cnd
.cn_flags
&= ~HASBUF
;
2090 fdiraft_ret
= VOP_GETATTR(fdirp
, &fdiraft
, cred
, procp
);
2094 tdiraft_ret
= VOP_GETATTR(tdirp
, &tdiraft
, cred
, procp
);
2097 vrele(fromnd
.ni_startdir
);
2098 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
, fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2099 fromnd
.ni_cnd
.cn_flags
&= ~HASBUF
;
2100 nfsm_reply(2 * NFSX_WCCDATA(v3
));
2102 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
2103 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
2112 if (tond
.ni_cnd
.cn_nameiop
) {
2113 vrele(tond
.ni_startdir
);
2114 FREE_ZONE(tond
.ni_cnd
.cn_pnbuf
, tond
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2115 tond
.ni_cnd
.cn_flags
&= ~HASBUF
;
2117 if (fromnd
.ni_cnd
.cn_nameiop
) {
2118 vrele(fromnd
.ni_startdir
);
2119 FREE_ZONE(fromnd
.ni_cnd
.cn_pnbuf
,
2120 fromnd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2121 fromnd
.ni_cnd
.cn_flags
&= ~HASBUF
;
2122 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2123 vrele(fromnd
.ni_dvp
);
2133 nfsrv_link(nfsd
, slp
, procp
, mrq
)
2134 struct nfsrv_descript
*nfsd
;
2135 struct nfssvc_sock
*slp
;
2139 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2140 struct mbuf
*nam
= nfsd
->nd_nam
;
2141 caddr_t dpos
= nfsd
->nd_dpos
;
2142 struct ucred
*cred
= &nfsd
->nd_cr
;
2143 struct nameidata nd
;
2144 register u_long
*tl
;
2147 int error
= 0, rdonly
, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2148 int getret
= 1, v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2150 struct mbuf
*mb
, *mreq
;
2151 struct vnode
*vp
, *xp
, *dirp
= (struct vnode
*)0;
2152 struct vattr dirfor
, diraft
, at
;
2154 fhandle_t
*fhp
, *dfhp
;
2157 fhp
= &nfh
.fh_generic
;
2158 dfhp
= &dnfh
.fh_generic
;
2160 nfsm_srvmtofh(dfhp
);
2161 nfsm_srvnamesiz(len
);
2162 if ((error
= nfsrv_fhtovp(fhp
, FALSE
, &vp
, cred
, slp
, nam
,
2163 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
2164 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2165 nfsm_srvpostop_attr(getret
, &at
);
2166 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2169 if (vp
->v_type
== VDIR
) {
2170 error
= EPERM
; /* POSIX */
2173 nd
.ni_cnd
.cn_cred
= cred
;
2174 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2175 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2176 error
= nfs_namei(&nd
, dfhp
, len
, slp
, nam
, &md
, &dpos
,
2177 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2180 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2184 dirp
= (struct vnode
*)0;
2195 if (vp
->v_mount
!= xp
->v_mount
)
2199 nqsrv_getl(vp
, ND_WRITE
);
2200 nqsrv_getl(xp
, ND_WRITE
);
2201 error
= VOP_LINK(vp
, nd
.ni_dvp
, &nd
.ni_cnd
);
2203 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2204 if (nd
.ni_dvp
== nd
.ni_vp
)
2213 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2215 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2219 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2221 nfsm_srvpostop_attr(getret
, &at
);
2222 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2229 * nfs symbolic link service
2232 nfsrv_symlink(nfsd
, slp
, procp
, mrq
)
2233 struct nfsrv_descript
*nfsd
;
2234 struct nfssvc_sock
*slp
;
2238 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2239 struct mbuf
*nam
= nfsd
->nd_nam
;
2240 caddr_t dpos
= nfsd
->nd_dpos
;
2241 struct ucred
*cred
= &nfsd
->nd_cr
;
2242 struct vattr va
, dirfor
, diraft
;
2243 struct nameidata nd
;
2244 register struct vattr
*vap
= &va
;
2245 register u_long
*tl
;
2247 struct nfsv2_sattr
*sp
;
2248 char *bpos
, *pathcp
= (char *)0, *cp2
;
2251 int error
= 0, cache
, len
, len2
, dirfor_ret
= 1, diraft_ret
= 1;
2252 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2253 struct mbuf
*mb
, *mreq
, *mb2
;
2254 struct vnode
*dirp
= (struct vnode
*)0;
2259 nd
.ni_cnd
.cn_nameiop
= 0;
2260 fhp
= &nfh
.fh_generic
;
2262 nfsm_srvnamesiz(len
);
2263 nd
.ni_cnd
.cn_cred
= cred
;
2264 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2265 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| SAVESTART
;
2266 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
2267 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2270 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2274 dirp
= (struct vnode
*)0;
2282 nfsm_strsiz(len2
, NFS_MAXPATHLEN
);
2283 MALLOC(pathcp
, caddr_t
, len2
+ 1, M_TEMP
, M_WAITOK
);
2284 iv
.iov_base
= pathcp
;
2286 io
.uio_resid
= len2
;
2290 io
.uio_segflg
= UIO_SYSSPACE
;
2291 io
.uio_rw
= UIO_READ
;
2292 io
.uio_procp
= (struct proc
*)0;
2293 nfsm_mtouio(&io
, len2
);
2295 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2296 vap
->va_mode
= fxdr_unsigned(u_short
, sp
->sa_mode
);
2298 *(pathcp
+ len2
) = '\0';
2300 vrele(nd
.ni_startdir
);
2301 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2302 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
2303 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2304 if (nd
.ni_dvp
== nd
.ni_vp
)
2312 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2313 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
, pathcp
);
2315 vrele(nd
.ni_startdir
);
2318 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
2319 nd
.ni_cnd
.cn_flags
&= ~(LOCKPARENT
| SAVESTART
| FOLLOW
);
2320 nd
.ni_cnd
.cn_flags
|= (NOFOLLOW
| LOCKLEAF
);
2321 nd
.ni_cnd
.cn_proc
= procp
;
2322 nd
.ni_cnd
.cn_cred
= cred
;
2323 error
= lookup(&nd
);
2325 bzero((caddr_t
)fhp
, sizeof(nfh
));
2326 fhp
->fh_fsid
= nd
.ni_vp
->v_mount
->mnt_stat
.f_fsid
;
2327 error
= VFS_VPTOFH(nd
.ni_vp
, &fhp
->fh_fid
);
2329 error
= VOP_GETATTR(nd
.ni_vp
, vap
, cred
,
2334 vrele(nd
.ni_startdir
);
2335 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2336 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
2340 FREE(pathcp
, M_TEMP
);
2342 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2345 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2348 nfsm_srvpostop_fh(fhp
);
2349 nfsm_srvpostop_attr(0, vap
);
2351 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2355 if (nd
.ni_cnd
.cn_nameiop
) {
2356 vrele(nd
.ni_startdir
);
2357 FREE_ZONE(nd
.ni_cnd
.cn_pnbuf
, nd
.ni_cnd
.cn_pnlen
, M_NAMEI
);
2358 nd
.ni_cnd
.cn_flags
&= ~HASBUF
;
2362 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2363 if (nd
.ni_dvp
== nd
.ni_vp
)
2370 FREE(pathcp
, M_TEMP
);
2378 nfsrv_mkdir(nfsd
, slp
, procp
, mrq
)
2379 struct nfsrv_descript
*nfsd
;
2380 struct nfssvc_sock
*slp
;
2384 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2385 struct mbuf
*nam
= nfsd
->nd_nam
;
2386 caddr_t dpos
= nfsd
->nd_dpos
;
2387 struct ucred
*cred
= &nfsd
->nd_cr
;
2388 struct vattr va
, dirfor
, diraft
;
2389 register struct vattr
*vap
= &va
;
2390 register struct nfs_fattr
*fp
;
2391 struct nameidata nd
;
2392 register caddr_t cp
;
2393 register u_long
*tl
;
2396 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2397 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2399 struct mbuf
*mb
, *mb2
, *mreq
;
2400 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
2405 fhp
= &nfh
.fh_generic
;
2407 nfsm_srvnamesiz(len
);
2408 nd
.ni_cnd
.cn_cred
= cred
;
2409 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2410 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2411 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
2412 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2415 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2419 dirp
= (struct vnode
*)0;
2423 nfsm_reply(NFSX_WCCDATA(v3
));
2424 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2433 nfsm_dissect(tl
, u_long
*, NFSX_UNSIGNED
);
2434 vap
->va_mode
= nfstov_mode(*tl
++);
2436 vap
->va_type
= VDIR
;
2439 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2440 if (nd
.ni_dvp
== vp
)
2448 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2449 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, vap
);
2452 bzero((caddr_t
)fhp
, sizeof(nfh
));
2453 fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
2454 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
2456 error
= VOP_GETATTR(vp
, vap
, cred
, procp
);
2461 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2464 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2467 nfsm_srvpostop_fh(fhp
);
2468 nfsm_srvpostop_attr(0, vap
);
2470 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2472 nfsm_srvfhtom(fhp
, v3
);
2473 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
2474 nfsm_srvfillattr(vap
, fp
);
2480 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2481 if (nd
.ni_dvp
== nd
.ni_vp
)
2494 nfsrv_rmdir(nfsd
, slp
, procp
, mrq
)
2495 struct nfsrv_descript
*nfsd
;
2496 struct nfssvc_sock
*slp
;
2500 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2501 struct mbuf
*nam
= nfsd
->nd_nam
;
2502 caddr_t dpos
= nfsd
->nd_dpos
;
2503 struct ucred
*cred
= &nfsd
->nd_cr
;
2504 register u_long
*tl
;
2507 int error
= 0, cache
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2508 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2510 struct mbuf
*mb
, *mreq
;
2511 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
2512 struct vattr dirfor
, diraft
;
2515 struct nameidata nd
;
2518 fhp
= &nfh
.fh_generic
;
2520 nfsm_srvnamesiz(len
);
2521 nd
.ni_cnd
.cn_cred
= cred
;
2522 nd
.ni_cnd
.cn_nameiop
= DELETE
;
2523 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2524 error
= nfs_namei(&nd
, fhp
, len
, slp
, nam
, &md
, &dpos
,
2525 &dirp
, procp
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2528 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
,
2532 dirp
= (struct vnode
*)0;
2536 nfsm_reply(NFSX_WCCDATA(v3
));
2537 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2543 if (vp
->v_type
!= VDIR
) {
2548 * No rmdir "." please.
2550 if (nd
.ni_dvp
== vp
) {
2555 * The root of a mounted filesystem cannot be deleted.
2557 if (vp
->v_flag
& VROOT
)
2561 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2562 nqsrv_getl(vp
, ND_WRITE
);
2563 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2565 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2566 if (nd
.ni_dvp
== nd
.ni_vp
)
2573 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
, procp
);
2576 nfsm_reply(NFSX_WCCDATA(v3
));
2578 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2585 * nfs readdir service
2586 * - mallocs what it thinks is enough to read
2587 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2588 * - calls VOP_READDIR()
2589 * - loops around building the reply
2590 * if the output generated exceeds count break out of loop
2591 * The nfsm_clget macro is used here so that the reply will be packed
2592 * tightly in mbuf clusters.
2593 * - it only knows that it has encountered eof when the VOP_READDIR()
2595 * - as such one readdir rpc will return eof false although you are there
2596 * and then the next will return eof
2597 * - it trims out records with d_fileno == 0
2598 * this doesn't matter for Unix clients, but they might confuse clients
2600 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2601 * than requested, but this may not apply to all filesystems. For
2602 * example, client NFS does not { although it is never remote mounted
2604 * The alternate call nfsrv_readdirplus() does lookups as well.
2605 * PS: The XNFS protocol spec clearly describes what the "count"s arguments
2606 * are supposed to cover. For readdir, the count is the total number of
2607 * bytes included in everything from the directory's postopattr through
2608 * the EOF flag. For readdirplus, the maxcount is the same, and the
2609 * dircount includes all that except for the entry attributes and handles.
2614 u_long fl_fattr
[NFSX_V3FATTR
/ sizeof (u_long
)];
2617 u_long fl_nfh
[NFSX_V3FH
/ sizeof (u_long
)];
2621 nfsrv_readdir(nfsd
, slp
, procp
, mrq
)
2622 struct nfsrv_descript
*nfsd
;
2623 struct nfssvc_sock
*slp
;
2627 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2628 struct mbuf
*nam
= nfsd
->nd_nam
;
2629 caddr_t dpos
= nfsd
->nd_dpos
;
2630 struct ucred
*cred
= &nfsd
->nd_cr
;
2631 register char *bp
, *be
;
2632 register struct mbuf
*mp
;
2633 register struct dirent
*dp
;
2634 register caddr_t cp
;
2635 register u_long
*tl
;
2638 struct mbuf
*mb
, *mb2
, *mreq
, *mp2
;
2639 char *cpos
, *cend
, *cp2
, *rbuf
;
2646 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2647 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, cache
, ncookies
= 0;
2648 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2649 u_quad_t frev
, off
, toff
, verf
;
2650 u_long
*cookies
= NULL
, *cookiep
;
2652 fhp
= &nfh
.fh_generic
;
2655 nfsm_dissect(tl
, u_long
*, 5 * NFSX_UNSIGNED
);
2656 fxdr_hyper(tl
, &toff
);
2658 fxdr_hyper(tl
, &verf
);
2661 nfsm_dissect(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2662 toff
= fxdr_unsigned(u_quad_t
, *tl
++);
2665 cnt
= fxdr_unsigned(int, *tl
);
2666 siz
= ((cnt
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
2667 xfer
= NFS_SRVMAXDATA(nfsd
);
2671 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
2672 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
2673 nfsm_reply(NFSX_UNSIGNED
);
2674 nfsm_srvpostop_attr(getret
, &at
);
2677 nqsrv_getl(vp
, ND_READ
);
2679 error
= getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2680 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
2681 error
= NFSERR_BAD_COOKIE
;
2684 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 0);
2687 nfsm_reply(NFSX_POSTOPATTR(v3
));
2688 nfsm_srvpostop_attr(getret
, &at
);
2691 VOP_UNLOCK(vp
, 0, procp
);
2692 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
2695 iv
.iov_len
= fullsiz
;
2698 io
.uio_offset
= (off_t
)off
;
2699 io
.uio_resid
= fullsiz
;
2700 io
.uio_segflg
= UIO_SYSSPACE
;
2701 io
.uio_rw
= UIO_READ
;
2702 io
.uio_procp
= (struct proc
*)0;
2706 _FREE((caddr_t
)cookies
, M_TEMP
);
2709 if (error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, procp
)) {
2710 FREE((caddr_t
)rbuf
, M_TEMP
);
2711 nfsm_reply(NFSX_POSTOPATTR(v3
));
2712 nfsm_srvpostop_attr(getret
, &at
);
2715 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
2716 off
= (off_t
)io
.uio_offset
;
2718 * We cannot set the error in the case where there are no cookies
2719 * and no error, only, as FreeBSD. In the scenario the client is
2720 * calling us back being told there were "more" entries on last readdir
2721 * return, and we have no more entries, our VOP_READDIR can give
2722 * cookies = NULL and no error. This is due to a zero size to MALLOC
2723 * returning NULL unlike FreeBSD which returns a pointer.
2724 * With FreeBSD it makes sense if the MALLOC failed and you get in that
2725 * bind. For us, we need something more. Thus, we should make sure we
2726 * had some cookies to return, but no pointer and no error for EPERM case.
2727 * Otherwise, go thru normal processing of sending back the eofflag. This check
2728 * is also legit on first call to the routine by client since . and ..
2729 * should be returned. Make same change to nfsrv_readdirplus.
2731 if ((ncookies
!= 0) && !cookies
&& !error
)
2732 error
= NFSERR_PERM
;
2735 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2739 VOP_UNLOCK(vp
, 0, procp
);
2742 _FREE((caddr_t
)rbuf
, M_TEMP
);
2744 _FREE((caddr_t
)cookies
, M_TEMP
);
2745 nfsm_reply(NFSX_POSTOPATTR(v3
));
2746 nfsm_srvpostop_attr(getret
, &at
);
2750 siz
-= io
.uio_resid
;
2753 * If nothing read, return eof
2758 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) +
2761 nfsm_srvpostop_attr(getret
, &at
);
2762 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
2763 txdr_hyper(&at
.va_filerev
, tl
);
2766 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2769 FREE((caddr_t
)rbuf
, M_TEMP
);
2770 FREE((caddr_t
)cookies
, M_TEMP
);
2776 * Check for degenerate cases of nothing useful read.
2777 * If so go try again
2781 dp
= (struct dirent
*)cpos
;
2785 * For some reason FreeBSD's ufs_readdir() chooses to back the
2786 * directory offset up to a block boundary, so it is necessary to
2787 * skip over the records that preceed the requested offset. This
2788 * requires the assumption that file offset cookies monotonically
2791 while (cpos
< cend
&& ncookies
> 0 &&
2792 (dp
->d_fileno
== 0 || ((u_quad_t
)(*cookiep
)) <= toff
)) {
2794 while (dp
->d_fileno
== 0 && cpos
< cend
&& ncookies
> 0) {
2796 cpos
+= dp
->d_reclen
;
2797 dp
= (struct dirent
*)cpos
;
2801 if (cpos
>= cend
|| ncookies
== 0) {
2807 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) + siz
);
2809 len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
2810 nfsm_srvpostop_attr(getret
, &at
);
2811 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
2812 txdr_hyper(&at
.va_filerev
, tl
);
2814 len
= 2 * NFSX_UNSIGNED
;
2817 be
= bp
+ M_TRAILINGSPACE(mp
);
2819 /* Loop through the records and build reply */
2820 while (cpos
< cend
&& ncookies
> 0) {
2821 if (dp
->d_fileno
!= 0) {
2822 nlen
= dp
->d_namlen
;
2823 rem
= nfsm_rndup(nlen
)-nlen
;
2824 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
2826 len
+= 2 * NFSX_UNSIGNED
;
2832 * Build the directory record xdr from
2837 bp
+= NFSX_UNSIGNED
;
2841 bp
+= NFSX_UNSIGNED
;
2844 *tl
= txdr_unsigned(dp
->d_fileno
);
2845 bp
+= NFSX_UNSIGNED
;
2847 *tl
= txdr_unsigned(nlen
);
2848 bp
+= NFSX_UNSIGNED
;
2850 /* And loop around copying the name */
2859 bcopy(cp
, bp
, tsiz
);
2865 /* And null pad to a long boundary */
2866 for (i
= 0; i
< rem
; i
++)
2870 /* Finish off the record */
2873 bp
+= NFSX_UNSIGNED
;
2876 *tl
= txdr_unsigned(*cookiep
);
2877 bp
+= NFSX_UNSIGNED
;
2879 cpos
+= dp
->d_reclen
;
2880 dp
= (struct dirent
*)cpos
;
2887 bp
+= NFSX_UNSIGNED
;
2893 bp
+= NFSX_UNSIGNED
;
2896 mp
->m_len
= bp
- mtod(mp
, caddr_t
);
2898 mp
->m_len
+= bp
- bpos
;
2899 FREE((caddr_t
)rbuf
, M_TEMP
);
2900 FREE((caddr_t
)cookies
, M_TEMP
);
2905 nfsrv_readdirplus(nfsd
, slp
, procp
, mrq
)
2906 struct nfsrv_descript
*nfsd
;
2907 struct nfssvc_sock
*slp
;
2911 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2912 struct mbuf
*nam
= nfsd
->nd_nam
;
2913 caddr_t dpos
= nfsd
->nd_dpos
;
2914 struct ucred
*cred
= &nfsd
->nd_cr
;
2915 register char *bp
, *be
;
2916 register struct mbuf
*mp
;
2917 register struct dirent
*dp
;
2918 register caddr_t cp
;
2919 register u_long
*tl
;
2922 struct mbuf
*mb
, *mb2
, *mreq
, *mp2
;
2923 char *cpos
, *cend
, *cp2
, *rbuf
;
2924 struct vnode
*vp
, *nvp
;
2927 fhandle_t
*fhp
, *nfhp
= (fhandle_t
*)fl
.fl_nfh
;
2930 struct vattr va
, at
, *vap
= &va
;
2931 struct nfs_fattr
*fp
;
2932 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2933 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, cache
, dirlen
, ncookies
= 0;
2934 u_quad_t frev
, off
, toff
, verf
;
2935 u_long
*cookies
= NULL
, *cookiep
;
2938 fhp
= &nfh
.fh_generic
;
2940 nfsm_dissect(tl
, u_long
*, 6 * NFSX_UNSIGNED
);
2941 fxdr_hyper(tl
, &toff
);
2943 fxdr_hyper(tl
, &verf
);
2945 siz
= fxdr_unsigned(int, *tl
++);
2946 cnt
= fxdr_unsigned(int, *tl
);
2948 siz
= ((siz
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
2949 xfer
= NFS_SRVMAXDATA(nfsd
);
2953 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
2954 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
2955 nfsm_reply(NFSX_UNSIGNED
);
2956 nfsm_srvpostop_attr(getret
, &at
);
2959 error
= getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2960 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
2961 error
= NFSERR_BAD_COOKIE
;
2963 nqsrv_getl(vp
, ND_READ
);
2964 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, procp
, 0);
2968 nfsm_reply(NFSX_V3POSTOPATTR
);
2969 nfsm_srvpostop_attr(getret
, &at
);
2972 VOP_UNLOCK(vp
, 0, procp
);
2973 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
2976 iv
.iov_len
= fullsiz
;
2979 io
.uio_offset
= (off_t
)off
;
2980 io
.uio_resid
= fullsiz
;
2981 io
.uio_segflg
= UIO_SYSSPACE
;
2982 io
.uio_rw
= UIO_READ
;
2983 io
.uio_procp
= (struct proc
*)0;
2986 _FREE((caddr_t
)cookies
, M_TEMP
);
2989 if (error
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, procp
)) {
2990 FREE((caddr_t
)rbuf
, M_TEMP
);
2991 nfsm_reply(NFSX_V3POSTOPATTR
);
2992 nfsm_srvpostop_attr(getret
, &at
);
2995 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
2996 off
= (u_quad_t
)io
.uio_offset
;
2997 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
2998 VOP_UNLOCK(vp
, 0, procp
);
3000 * See nfsrv_readdir comment above on this
3002 if ((ncookies
!= 0) && !cookies
&& !error
)
3003 error
= NFSERR_PERM
;
3010 _FREE((caddr_t
)cookies
, M_TEMP
);
3011 _FREE((caddr_t
)rbuf
, M_TEMP
);
3012 nfsm_reply(NFSX_V3POSTOPATTR
);
3013 nfsm_srvpostop_attr(getret
, &at
);
3017 siz
-= io
.uio_resid
;
3020 * If nothing read, return eof
3025 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+
3027 nfsm_srvpostop_attr(getret
, &at
);
3028 nfsm_build(tl
, u_long
*, 4 * NFSX_UNSIGNED
);
3029 txdr_hyper(&at
.va_filerev
, tl
);
3033 FREE((caddr_t
)cookies
, M_TEMP
);
3034 FREE((caddr_t
)rbuf
, M_TEMP
);
3040 * Check for degenerate cases of nothing useful read.
3041 * If so go try again
3045 dp
= (struct dirent
*)cpos
;
3049 * For some reason FreeBSD's ufs_readdir() chooses to back the
3050 * directory offset up to a block boundary, so it is necessary to
3051 * skip over the records that preceed the requested offset. This
3052 * requires the assumption that file offset cookies monotonically
3055 while (cpos
< cend
&& ncookies
> 0 &&
3056 (dp
->d_fileno
== 0 || ((u_quad_t
)(*cookiep
)) <= toff
)) {
3058 while (dp
->d_fileno
== 0 && cpos
< cend
&& ncookies
> 0) {
3060 cpos
+= dp
->d_reclen
;
3061 dp
= (struct dirent
*)cpos
;
3065 if (cpos
>= cend
|| ncookies
== 0) {
3072 * Probe one of the directory entries to see if the filesystem
3073 * supports VGET. See later comment for VFS_VGET changes.
3075 if (vp
->v_tag
== VT_UFS
)
3076 file
= (void *) dp
->d_fileno
;
3078 file
= &dp
->d_fileno
;
3081 if (error
= VFS_VGET(vp
->v_mount
, file
, &nvp
)) {
3082 if (error
== EOPNOTSUPP
) /* let others get passed back */
3083 error
= NFSERR_NOTSUPP
;
3085 _FREE((caddr_t
)cookies
, M_TEMP
);
3086 _FREE((caddr_t
)rbuf
, M_TEMP
);
3087 nfsm_reply(NFSX_V3POSTOPATTR
);
3088 nfsm_srvpostop_attr(getret
, &at
);
3093 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3095 nfsm_srvpostop_attr(getret
, &at
);
3096 nfsm_build(tl
, u_long
*, 2 * NFSX_UNSIGNED
);
3097 txdr_hyper(&at
.va_filerev
, tl
);
3100 be
= bp
+ M_TRAILINGSPACE(mp
);
3102 /* Loop through the records and build reply */
3103 while (cpos
< cend
&& ncookies
> 0) {
3104 if (dp
->d_fileno
!= 0) {
3105 nlen
= dp
->d_namlen
;
3106 rem
= nfsm_rndup(nlen
)-nlen
;
3109 * Got to get the vnode for lookup per entry.
3110 * HFS+/volfs and others use address of file identifier to VGET
3111 * UFS, nullfs, umapfs use inode (u_int32_t)
3112 * until they are consistent, we must differentiate now.
3113 * UFS is the only one of the latter class that is exported.
3114 * Note this will be pulled out as we resolve the VGET issue
3115 * of which it should use u_in32_t or addresses.
3118 if (vp
->v_tag
== VT_UFS
)
3119 file
= (void *) dp
->d_fileno
;
3121 file
= &dp
->d_fileno
;
3123 if (VFS_VGET(vp
->v_mount
, file
, &nvp
))
3125 bzero((caddr_t
)nfhp
, NFSX_V3FH
);
3127 nvp
->v_mount
->mnt_stat
.f_fsid
;
3128 if (VFS_VPTOFH(nvp
, &nfhp
->fh_fid
)) {
3132 if (VOP_GETATTR(nvp
, vap
, cred
, procp
)) {
3139 * If either the dircount or maxcount will be
3140 * exceeded, get out now. Both of these lengths
3141 * are calculated conservatively, including all
3144 len
+= (8 * NFSX_UNSIGNED
+ nlen
+ rem
+ NFSX_V3FH
+
3146 dirlen
+= (6 * NFSX_UNSIGNED
+ nlen
+ rem
);
3147 if (len
> cnt
|| dirlen
> fullsiz
) {
3153 * Build the directory record xdr from
3156 fp
= (struct nfs_fattr
*)&fl
.fl_fattr
;
3157 nfsm_srvfillattr(vap
, fp
);
3158 fl
.fl_fhsize
= txdr_unsigned(NFSX_V3FH
);
3159 fl
.fl_fhok
= nfs_true
;
3160 fl
.fl_postopok
= nfs_true
;
3161 fl
.fl_off
.nfsuquad
[0] = 0;
3162 fl
.fl_off
.nfsuquad
[1] = txdr_unsigned(*cookiep
);
3166 bp
+= NFSX_UNSIGNED
;
3169 bp
+= NFSX_UNSIGNED
;
3171 *tl
= txdr_unsigned(dp
->d_fileno
);
3172 bp
+= NFSX_UNSIGNED
;
3174 *tl
= txdr_unsigned(nlen
);
3175 bp
+= NFSX_UNSIGNED
;
3177 /* And loop around copying the name */
3182 if ((bp
+ xfer
) > be
)
3186 bcopy(cp
, bp
, tsiz
);
3192 /* And null pad to a long boundary */
3193 for (i
= 0; i
< rem
; i
++)
3197 * Now copy the flrep structure out.
3199 xfer
= sizeof (struct flrep
);
3203 if ((bp
+ xfer
) > be
)
3207 bcopy(cp
, bp
, tsiz
);
3215 cpos
+= dp
->d_reclen
;
3216 dp
= (struct dirent
*)cpos
;
3223 bp
+= NFSX_UNSIGNED
;
3229 bp
+= NFSX_UNSIGNED
;
3232 mp
->m_len
= bp
- mtod(mp
, caddr_t
);
3234 mp
->m_len
+= bp
- bpos
;
3235 FREE((caddr_t
)cookies
, M_TEMP
);
3236 FREE((caddr_t
)rbuf
, M_TEMP
);
3241 * nfs commit service
3244 nfsrv_commit(nfsd
, slp
, procp
, mrq
)
3245 struct nfsrv_descript
*nfsd
;
3246 struct nfssvc_sock
*slp
;
3250 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3251 struct mbuf
*nam
= nfsd
->nd_nam
;
3252 caddr_t dpos
= nfsd
->nd_dpos
;
3253 struct ucred
*cred
= &nfsd
->nd_cr
;
3254 struct vattr bfor
, aft
;
3258 register u_long
*tl
;
3261 int error
= 0, rdonly
, for_ret
= 1, aft_ret
= 1, cnt
, cache
;
3263 struct mbuf
*mb
, *mb2
, *mreq
;
3270 fhp
= &nfh
.fh_generic
;
3272 nfsm_dissect(tl
, u_long
*, 3 * NFSX_UNSIGNED
);
3275 * XXX At this time VOP_FSYNC() does not accept offset and byte
3276 * count parameters, so these arguments are useless (someday maybe).
3278 fxdr_hyper(tl
, &off
);
3280 cnt
= fxdr_unsigned(int, *tl
);
3281 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3282 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3283 nfsm_reply(2 * NFSX_UNSIGNED
);
3284 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
3287 for_ret
= VOP_GETATTR(vp
, &bfor
, cred
, procp
);
3288 didhold
= ubc_hold(vp
);
3289 error
= VOP_FSYNC(vp
, cred
, MNT_WAIT
, procp
);
3290 aft_ret
= VOP_GETATTR(vp
, &aft
, cred
, procp
);
3291 VOP_UNLOCK(vp
, 0, procp
);
3295 nfsm_reply(NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
3296 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
3298 nfsm_build(tl
, u_long
*, NFSX_V3WRITEVERF
);
3299 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
3300 *tl
= txdr_unsigned(boottime
.tv_usec
);
3307 * nfs statfs service
3310 nfsrv_statfs(nfsd
, slp
, procp
, mrq
)
3311 struct nfsrv_descript
*nfsd
;
3312 struct nfssvc_sock
*slp
;
3316 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3317 struct mbuf
*nam
= nfsd
->nd_nam
;
3318 caddr_t dpos
= nfsd
->nd_dpos
;
3319 struct ucred
*cred
= &nfsd
->nd_cr
;
3320 register struct statfs
*sf
;
3321 register struct nfs_statfs
*sfp
;
3322 register u_long
*tl
;
3325 int error
= 0, rdonly
, cache
, getret
= 1;
3326 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3328 struct mbuf
*mb
, *mb2
, *mreq
;
3333 struct statfs statfs
;
3334 u_quad_t frev
, tval
;
3339 fhp
= &nfh
.fh_generic
;
3341 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3342 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3343 nfsm_reply(NFSX_UNSIGNED
);
3344 nfsm_srvpostop_attr(getret
, &at
);
3348 error
= VFS_STATFS(vp
->v_mount
, sf
, procp
);
3349 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
3351 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_STATFS(v3
));
3353 nfsm_srvpostop_attr(getret
, &at
);
3356 nfsm_build(sfp
, struct nfs_statfs
*, NFSX_STATFS(v3
));
3358 tval
= (u_quad_t
)(unsigned long)sf
->f_blocks
;
3359 tval
*= (u_quad_t
)(unsigned long)sf
->f_bsize
;
3360 txdr_hyper(&tval
, &sfp
->sf_tbytes
);
3361 tval
= (u_quad_t
)(unsigned long)sf
->f_bfree
;
3362 tval
*= (u_quad_t
)(unsigned long)sf
->f_bsize
;
3363 txdr_hyper(&tval
, &sfp
->sf_fbytes
);
3364 tval
= (u_quad_t
)(unsigned long)sf
->f_bavail
;
3365 tval
*= (u_quad_t
)(unsigned long)sf
->f_bsize
;
3366 txdr_hyper(&tval
, &sfp
->sf_abytes
);
3367 sfp
->sf_tfiles
.nfsuquad
[0] = 0;
3368 sfp
->sf_tfiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_files
);
3369 sfp
->sf_ffiles
.nfsuquad
[0] = 0;
3370 sfp
->sf_ffiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3371 sfp
->sf_afiles
.nfsuquad
[0] = 0;
3372 sfp
->sf_afiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3373 sfp
->sf_invarsec
= 0;
3375 sfp
->sf_tsize
= txdr_unsigned(NFS_V2MAXDATA
);
3376 sfp
->sf_bsize
= txdr_unsigned(sf
->f_bsize
);
3377 sfp
->sf_blocks
= txdr_unsigned(sf
->f_blocks
);
3378 sfp
->sf_bfree
= txdr_unsigned(sf
->f_bfree
);
3379 sfp
->sf_bavail
= txdr_unsigned(sf
->f_bavail
);
3385 * nfs fsinfo service
3388 nfsrv_fsinfo(nfsd
, slp
, procp
, mrq
)
3389 struct nfsrv_descript
*nfsd
;
3390 struct nfssvc_sock
*slp
;
3394 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3395 struct mbuf
*nam
= nfsd
->nd_nam
;
3396 caddr_t dpos
= nfsd
->nd_dpos
;
3397 struct ucred
*cred
= &nfsd
->nd_cr
;
3398 register u_long
*tl
;
3399 register struct nfsv3_fsinfo
*sip
;
3402 int error
= 0, rdonly
, cache
, getret
= 1, pref
, max
;
3404 struct mbuf
*mb
, *mb2
, *mreq
;
3414 fhp
= &nfh
.fh_generic
;
3416 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3417 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3418 nfsm_reply(NFSX_UNSIGNED
);
3419 nfsm_srvpostop_attr(getret
, &at
);
3422 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
3424 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
3425 nfsm_srvpostop_attr(getret
, &at
);
3426 nfsm_build(sip
, struct nfsv3_fsinfo
*, NFSX_V3FSINFO
);
3430 * There should be file system VFS OP(s) to get this information.
3431 * For now, assume our usual NFS defaults.
3433 if (slp
->ns_so
->so_type
== SOCK_DGRAM
)
3434 max
= pref
= NFS_MAXDGRAMDATA
;
3436 max
= pref
= NFS_MAXDATA
;
3437 sip
->fs_rtmax
= txdr_unsigned(max
);
3438 sip
->fs_rtpref
= txdr_unsigned(pref
);
3439 sip
->fs_rtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3440 sip
->fs_wtmax
= txdr_unsigned(max
);
3441 sip
->fs_wtpref
= txdr_unsigned(pref
);
3442 sip
->fs_wtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3443 sip
->fs_dtpref
= txdr_unsigned(pref
);
3444 sip
->fs_maxfilesize
.nfsuquad
[0] = 0xffffffff;
3445 sip
->fs_maxfilesize
.nfsuquad
[1] = 0xffffffff;
3446 sip
->fs_timedelta
.nfsv3_sec
= 0;
3447 sip
->fs_timedelta
.nfsv3_nsec
= txdr_unsigned(1);
3448 sip
->fs_properties
= txdr_unsigned(NFSV3FSINFO_LINK
|
3449 NFSV3FSINFO_SYMLINK
| NFSV3FSINFO_HOMOGENEOUS
|
3450 NFSV3FSINFO_CANSETTIME
);
3455 * nfs pathconf service
3458 nfsrv_pathconf(nfsd
, slp
, procp
, mrq
)
3459 struct nfsrv_descript
*nfsd
;
3460 struct nfssvc_sock
*slp
;
3464 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3465 struct mbuf
*nam
= nfsd
->nd_nam
;
3466 caddr_t dpos
= nfsd
->nd_dpos
;
3467 struct ucred
*cred
= &nfsd
->nd_cr
;
3468 register u_long
*tl
;
3469 register struct nfsv3_pathconf
*pc
;
3472 int error
= 0, rdonly
, cache
, getret
= 1, linkmax
, namemax
;
3473 int chownres
, notrunc
, case_sensitive
, case_preserving
;
3475 struct mbuf
*mb
, *mb2
, *mreq
;
3485 fhp
= &nfh
.fh_generic
;
3487 if ((error
= nfsrv_fhtovp(fhp
, 1, &vp
, cred
, slp
, nam
,
3488 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
))) {
3489 nfsm_reply(NFSX_UNSIGNED
);
3490 nfsm_srvpostop_attr(getret
, &at
);
3493 error
= VOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
);
3495 error
= VOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
);
3497 error
= VOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
);
3499 error
= VOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
);
3501 error
= VOP_PATHCONF(vp
, _PC_CASE_SENSITIVE
, &case_sensitive
);
3503 error
= VOP_PATHCONF(vp
, _PC_CASE_PRESERVING
, &case_preserving
);
3504 getret
= VOP_GETATTR(vp
, &at
, cred
, procp
);
3506 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
3507 nfsm_srvpostop_attr(getret
, &at
);
3510 nfsm_build(pc
, struct nfsv3_pathconf
*, NFSX_V3PATHCONF
);
3512 pc
->pc_linkmax
= txdr_unsigned(linkmax
);
3513 pc
->pc_namemax
= txdr_unsigned(namemax
);
3514 pc
->pc_notrunc
= txdr_unsigned(notrunc
);
3515 pc
->pc_chownrestricted
= txdr_unsigned(chownres
);
3516 pc
->pc_caseinsensitive
= txdr_unsigned(!case_sensitive
);
3517 pc
->pc_casepreserving
= txdr_unsigned(case_preserving
);
3523 * Null operation, used by clients to ping server
3527 nfsrv_null(nfsd
, slp
, procp
, mrq
)
3528 struct nfsrv_descript
*nfsd
;
3529 struct nfssvc_sock
*slp
;
3533 struct mbuf
*mrep
= nfsd
->nd_mrep
;
3535 int error
= NFSERR_RETVOID
, cache
;
3536 struct mbuf
*mb
, *mreq
;
3547 * No operation, used for obsolete procedures
3551 nfsrv_noop(nfsd
, slp
, procp
, mrq
)
3552 struct nfsrv_descript
*nfsd
;
3553 struct nfssvc_sock
*slp
;
3557 struct mbuf
*mrep
= nfsd
->nd_mrep
;
3560 struct mbuf
*mb
, *mreq
;
3566 if (nfsd
->nd_repstat
)
3567 error
= nfsd
->nd_repstat
;
3569 error
= EPROCUNAVAIL
;
3575 * Perform access checking for vnodes obtained from file handles that would
3576 * refer to files already opened by a Unix client. You cannot just use
3577 * vn_writechk() and VOP_ACCESS() for two reasons.
3578 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3579 * 2 - The owner is to be given access irrespective of mode bits so that
3580 * processes that chmod after opening a file don't break. I don't like
3581 * this because it opens a security hole, but since the nfs server opens
3582 * a security hole the size of a barn door anyhow, what the heck.
3584 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
3585 * will return EPERM instead of EACCESS. EPERM is always an error.
3589 nfsrv_access(vp
, flags
, cred
, rdonly
, p
, override
)
3590 register struct vnode
*vp
;
3592 register struct ucred
*cred
;
3599 if (flags
& VWRITE
) {
3600 /* Just vn_writechk() changed to check rdonly */
3602 * Disallow write attempts on read-only file systems;
3603 * unless the file is a socket or a block or character
3604 * device resident on the file system.
3606 if (rdonly
|| (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
3607 switch (vp
->v_type
) {
3608 case VREG
: case VDIR
: case VLNK
: case VCPLX
:
3613 * If there's shared text associated with
3614 * the inode, we can't allow writing.
3616 if (vp
->v_flag
& VTEXT
)
3619 if ((error
= VOP_GETATTR(vp
, &vattr
, cred
, p
)))
3621 error
= VOP_ACCESS(vp
, flags
, cred
, p
);
3623 * Allow certain operations for the owner (reads and writes
3624 * on files that are already open). Picking up from FreeBSD.
3626 if (override
&& error
== EACCES
&& cred
->cr_uid
== vattr
.va_uid
)
3630 #endif /* NFS_NOSERVER */