2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#)nfs_serv.c 8.8 (Berkeley) 7/31/95
37 * $FreeBSD: src/sys/nfs/nfs_serv.c,v 1.93.2.6 2002/12/29 18:19:53 dillon Exp $
38 * $DragonFly: src/sys/vfs/nfs/nfs_serv.c,v 1.46.4.2 2008/09/25 02:20:53 dillon Exp $
42 * nfs version 2 and 3 server calls to vnode ops
43 * - these routines generally have 3 phases
44 * 1 - break down and validate rpc request in mbuf list
45 * 2 - do the vnode ops for the request
46 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
47 * 3 - build the rpc reply in an mbuf list
49 * - do not mix the phases, since the nfsm_?? macros can return failures
50 * on a bad rpc or similar and do not do any vrele() or vput()'s
52 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
53 * error number iff error != 0 whereas
54 * returning an error from the server function implies a fatal error
55 * such as a badly constructed rpc request that should be dropped without
57 * For Version 3, nfsm_reply() does not return for the error case, since
58 * most version 3 rpcs return more than the status for error cases.
61 * Warning: always pay careful attention to resource cleanup on return
62 * and note that nfsm_*() macros can terminate a procedure on certain
66 #include <sys/param.h>
67 #include <sys/systm.h>
69 #include <sys/nlookup.h>
70 #include <sys/namei.h>
71 #include <sys/unistd.h>
72 #include <sys/vnode.h>
73 #include <sys/mount.h>
74 #include <sys/socket.h>
75 #include <sys/socketvar.h>
76 #include <sys/malloc.h>
78 #include <sys/dirent.h>
80 #include <sys/kernel.h>
81 #include <sys/sysctl.h>
85 #include <vm/vm_extern.h>
86 #include <vm/vm_zone.h>
87 #include <vm/vm_object.h>
91 #include <sys/thread2.h>
97 #include "nfsm_subs.h"
100 #define nfsdbprintf(info) kprintf info
102 #define nfsdbprintf(info)
105 #define MAX_COMMIT_COUNT (1024 * 1024)
107 #define NUM_HEURISTIC 1017
108 #define NHUSE_INIT 64
110 #define NHUSE_MAX 2048
112 static struct nfsheur
{
113 struct vnode
*nh_vp
; /* vp to match (unreferenced pointer) */
114 off_t nh_nextr
; /* next offset for sequential detection */
115 int nh_use
; /* use count for selection */
116 int nh_seqcount
; /* heuristic */
117 } nfsheur
[NUM_HEURISTIC
];
119 nfstype nfsv3_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFSOCK
,
122 nfstype nfsv2_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFNON
,
125 extern u_int32_t nfs_xdrneg1
;
126 extern u_int32_t nfs_false
, nfs_true
;
127 extern enum vtype nv3tov_type
[8];
128 extern struct nfsstats nfsstats
;
130 int nfsrvw_procrastinate
= NFS_GATHERDELAY
* 1000;
131 int nfsrvw_procrastinate_v3
= 0;
133 static struct timespec nfsver
;
135 SYSCTL_DECL(_vfs_nfs
);
138 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, async
, CTLFLAG_RW
, &nfs_async
, 0, "");
139 static int nfs_commit_blks
;
140 static int nfs_commit_miss
;
141 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, commit_blks
, CTLFLAG_RW
, &nfs_commit_blks
, 0, "");
142 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, commit_miss
, CTLFLAG_RW
, &nfs_commit_miss
, 0, "");
144 static int nfsrv_access (struct mount
*, struct vnode
*, int,
145 struct ucred
*, int, struct thread
*, int);
146 static void nfsrvw_coalesce (struct nfsrv_descript
*,
147 struct nfsrv_descript
*);
150 * nfs v3 access service
153 nfsrv3_access(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
154 struct thread
*td
, struct mbuf
**mrq
)
156 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
157 struct sockaddr
*nam
= nfsd
->nd_nam
;
158 caddr_t dpos
= nfsd
->nd_dpos
;
159 struct ucred
*cred
= &nfsd
->nd_cr
;
160 struct vnode
*vp
= NULL
;
161 struct mount
*mp
= NULL
;
167 int error
= 0, rdonly
, getret
;
169 struct mbuf
*mb
, *mreq
, *mb2
;
170 struct vattr vattr
, *vap
= &vattr
;
171 u_long testmode
, nfsmode
;
173 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
174 fhp
= &nfh
.fh_generic
;
176 nfsm_dissect(tl
, u_int32_t
*, NFSX_UNSIGNED
);
177 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
, &rdonly
,
178 (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
180 nfsm_reply(NFSX_UNSIGNED
);
181 nfsm_srvpostop_attr(1, (struct vattr
*)0);
185 nfsmode
= fxdr_unsigned(u_int32_t
, *tl
);
186 if ((nfsmode
& NFSV3ACCESS_READ
) &&
187 nfsrv_access(mp
, vp
, VREAD
, cred
, rdonly
, td
, 0))
188 nfsmode
&= ~NFSV3ACCESS_READ
;
189 if (vp
->v_type
== VDIR
)
190 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
|
193 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
);
194 if ((nfsmode
& testmode
) &&
195 nfsrv_access(mp
, vp
, VWRITE
, cred
, rdonly
, td
, 0))
196 nfsmode
&= ~testmode
;
197 if (vp
->v_type
== VDIR
)
198 testmode
= NFSV3ACCESS_LOOKUP
;
200 testmode
= NFSV3ACCESS_EXECUTE
;
201 if ((nfsmode
& testmode
) &&
202 nfsrv_access(mp
, vp
, VEXEC
, cred
, rdonly
, td
, 0))
203 nfsmode
&= ~testmode
;
204 getret
= VOP_GETATTR(vp
, vap
);
207 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED
);
208 nfsm_srvpostop_attr(getret
, vap
);
209 nfsm_build(tl
, u_int32_t
*, NFSX_UNSIGNED
);
210 *tl
= txdr_unsigned(nfsmode
);
218 * nfs getattr service
221 nfsrv_getattr(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
222 struct thread
*td
, struct mbuf
**mrq
)
224 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
225 struct sockaddr
*nam
= nfsd
->nd_nam
;
226 caddr_t dpos
= nfsd
->nd_dpos
;
227 struct ucred
*cred
= &nfsd
->nd_cr
;
228 struct nfs_fattr
*fp
;
230 struct vattr
*vap
= &va
;
231 struct vnode
*vp
= NULL
;
232 struct mount
*mp
= NULL
;
238 int error
= 0, rdonly
;
240 struct mbuf
*mb
, *mb2
, *mreq
;
242 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
243 fhp
= &nfh
.fh_generic
;
245 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
246 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
252 error
= VOP_GETATTR(vp
, vap
);
255 nfsm_reply(NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
260 nfsm_build(fp
, struct nfs_fattr
*, NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
261 nfsm_srvfillattr(vap
, fp
);
271 * nfs setattr service
274 nfsrv_setattr(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
275 struct thread
*td
, struct mbuf
**mrq
)
277 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
278 struct sockaddr
*nam
= nfsd
->nd_nam
;
279 caddr_t dpos
= nfsd
->nd_dpos
;
280 struct ucred
*cred
= &nfsd
->nd_cr
;
281 struct vattr va
, preat
;
282 struct vattr
*vap
= &va
;
283 struct nfsv2_sattr
*sp
;
284 struct nfs_fattr
*fp
;
285 struct vnode
*vp
= NULL
;
286 struct mount
*mp
= NULL
;
292 int error
= 0, rdonly
, preat_ret
= 1, postat_ret
= 1;
293 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), gcheck
= 0;
295 struct mbuf
*mb
, *mb2
, *mreq
;
296 struct timespec guard
;
298 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
299 fhp
= &nfh
.fh_generic
;
304 nfsm_dissect(tl
, u_int32_t
*, NFSX_UNSIGNED
);
305 gcheck
= fxdr_unsigned(int, *tl
);
307 nfsm_dissect(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
308 fxdr_nfsv3time(tl
, &guard
);
311 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
313 * Nah nah nah nah na nah
314 * There is a bug in the Sun client that puts 0xffff in the mode
315 * field of sattr when it should put in 0xffffffff. The u_short
316 * doesn't sign extend.
317 * --> check the low order 2 bytes for 0xffff
319 if ((fxdr_unsigned(int, sp
->sa_mode
) & 0xffff) != 0xffff)
320 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
321 if (sp
->sa_uid
!= nfs_xdrneg1
)
322 vap
->va_uid
= fxdr_unsigned(uid_t
, sp
->sa_uid
);
323 if (sp
->sa_gid
!= nfs_xdrneg1
)
324 vap
->va_gid
= fxdr_unsigned(gid_t
, sp
->sa_gid
);
325 if (sp
->sa_size
!= nfs_xdrneg1
)
326 vap
->va_size
= fxdr_unsigned(u_quad_t
, sp
->sa_size
);
327 if (sp
->sa_atime
.nfsv2_sec
!= nfs_xdrneg1
) {
329 fxdr_nfsv2time(&sp
->sa_atime
, &vap
->va_atime
);
331 vap
->va_atime
.tv_sec
=
332 fxdr_unsigned(int32_t, sp
->sa_atime
.nfsv2_sec
);
333 vap
->va_atime
.tv_nsec
= 0;
336 if (sp
->sa_mtime
.nfsv2_sec
!= nfs_xdrneg1
)
337 fxdr_nfsv2time(&sp
->sa_mtime
, &vap
->va_mtime
);
342 * Now that we have all the fields, lets do it.
344 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
, &rdonly
,
345 (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
347 nfsm_reply(2 * NFSX_UNSIGNED
);
348 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
354 * vp now an active resource, pay careful attention to cleanup
358 error
= preat_ret
= VOP_GETATTR(vp
, &preat
);
359 if (!error
&& gcheck
&&
360 (preat
.va_ctime
.tv_sec
!= guard
.tv_sec
||
361 preat
.va_ctime
.tv_nsec
!= guard
.tv_nsec
))
362 error
= NFSERR_NOT_SYNC
;
366 nfsm_reply(NFSX_WCCDATA(v3
));
367 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
374 * If the size is being changed write acces is required, otherwise
375 * just check for a read only file system.
377 if (vap
->va_size
== ((u_quad_t
)((quad_t
) -1))) {
378 if (rdonly
|| (mp
->mnt_flag
& MNT_RDONLY
)) {
383 if (vp
->v_type
== VDIR
) {
386 } else if ((error
= nfsrv_access(mp
, vp
, VWRITE
, cred
, rdonly
,
391 error
= VOP_SETATTR(vp
, vap
, cred
);
392 postat_ret
= VOP_GETATTR(vp
, vap
);
398 nfsm_reply(NFSX_WCCORFATTR(v3
));
400 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, vap
);
404 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
405 nfsm_srvfillattr(vap
, fp
);
419 nfsrv_lookup(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
420 struct thread
*td
, struct mbuf
**mrq
)
422 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
423 struct sockaddr
*nam
= nfsd
->nd_nam
;
424 caddr_t dpos
= nfsd
->nd_dpos
;
425 struct ucred
*cred
= &nfsd
->nd_cr
;
426 struct nfs_fattr
*fp
;
427 struct nlookupdata nd
;
437 int error
= 0, len
, dirattr_ret
= 1;
438 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), pubflag
;
440 struct mbuf
*mb
, *mb2
, *mreq
;
441 struct vattr va
, dirattr
, *vap
= &va
;
443 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
448 fhp
= &nfh
.fh_generic
;
450 nfsm_srvnamesiz(len
);
452 pubflag
= nfs_ispublicfh(fhp
);
454 error
= nfs_namei(&nd
, cred
, NAMEI_LOOKUP
, NULL
, &vp
,
455 fhp
, len
, slp
, nam
, &md
, &dpos
,
456 &dirp
, td
, (nfsd
->nd_flag
& ND_KERBAUTH
), pubflag
);
459 * namei failure, only dirp to cleanup. Clear out garbarge from
460 * structure in case macros jump to nfsmout.
466 dirattr_ret
= VOP_GETATTR(dirp
, &dirattr
);
470 nfsm_reply(NFSX_POSTOPATTR(v3
));
471 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
477 * Locate index file for public filehandle
479 * error is 0 on entry and 0 on exit from this block.
483 if (vp
->v_type
== VDIR
&& nfs_pub
.np_index
!= NULL
) {
485 * Setup call to lookup() to see if we can find
486 * the index file. Arguably, this doesn't belong
487 * in a kernel.. Ugh. If an error occurs, do not
488 * try to install an index file and then clear the
491 * When we replace nd with ind and redirect ndp,
492 * maintenance of ni_startdir and ni_vp shift to
493 * ind and we have to clean them up in the old nd.
494 * However, the cnd resource continues to be maintained
495 * via the original nd. Confused? You aren't alone!
498 cache_copy(&nd
.nl_nch
, &nch
);
500 error
= nlookup_init_raw(&nd
, nfs_pub
.np_index
,
501 UIO_SYSSPACE
, 0, cred
, &nch
);
504 error
= nlookup(&nd
);
508 * Found an index file. Get rid of
509 * the old references. transfer vp and
510 * load up the new vp. Fortunately we do
511 * not have to deal with dvp, that would be
518 error
= cache_vget(&nd
.nl_nch
, nd
.nl_cred
,
520 KKASSERT(error
== 0);
525 * If the public filehandle was used, check that this lookup
526 * didn't result in a filehandle outside the publicly exported
527 * filesystem. We clear the poor vp here to avoid lockups due
531 if (vp
->v_mount
!= nfs_pub
.np_mount
) {
540 dirattr_ret
= VOP_GETATTR(dirp
, &dirattr
);
546 * Resources at this point:
547 * ndp->ni_vp may not be NULL
552 nfsm_reply(NFSX_POSTOPATTR(v3
));
553 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
559 * Clear out some resources prior to potentially blocking. This
560 * is not as critical as ni_dvp resources in other routines, but
566 * Get underlying attribute, then release remaining resources ( for
567 * the same potential blocking reason ) and reply.
569 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
570 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
572 error
= VOP_GETATTR(vp
, vap
);
576 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPORFATTR(v3
) + NFSX_POSTOPATTR(v3
));
578 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
582 nfsm_srvfhtom(fhp
, v3
);
584 nfsm_srvpostop_attr(0, vap
);
585 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
587 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
588 nfsm_srvfillattr(vap
, fp
);
594 nlookup_done(&nd
); /* may be called twice */
601 * nfs readlink service
604 nfsrv_readlink(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
605 struct thread
*td
, struct mbuf
**mrq
)
607 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
608 struct sockaddr
*nam
= nfsd
->nd_nam
;
609 caddr_t dpos
= nfsd
->nd_dpos
;
610 struct ucred
*cred
= &nfsd
->nd_cr
;
611 struct iovec iv
[(NFS_MAXPATHLEN
+MLEN
-1)/MLEN
];
612 struct iovec
*ivp
= iv
;
616 int error
= 0, rdonly
, i
, tlen
, len
, getret
;
617 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
619 struct mbuf
*mb
, *mb2
, *mp1
, *mp2
, *mp3
, *mreq
;
620 struct vnode
*vp
= NULL
;
621 struct mount
*mp
= NULL
;
625 struct uio io
, *uiop
= &io
;
627 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
629 mp2
= (struct mbuf
*)0;
632 fhp
= &nfh
.fh_generic
;
636 while (len
< NFS_MAXPATHLEN
) {
637 mp1
= m_getcl(MB_WAIT
, MT_DATA
, 0);
638 mp1
->m_len
= MCLBYTES
;
645 if ((len
+ mp1
->m_len
) > NFS_MAXPATHLEN
) {
646 mp1
->m_len
= NFS_MAXPATHLEN
-len
;
647 len
= NFS_MAXPATHLEN
;
650 ivp
->iov_base
= mtod(mp1
, caddr_t
);
651 ivp
->iov_len
= mp1
->m_len
;
656 uiop
->uio_iovcnt
= i
;
657 uiop
->uio_offset
= 0;
658 uiop
->uio_resid
= len
;
659 uiop
->uio_rw
= UIO_READ
;
660 uiop
->uio_segflg
= UIO_SYSSPACE
;
662 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
663 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
665 nfsm_reply(2 * NFSX_UNSIGNED
);
666 nfsm_srvpostop_attr(1, (struct vattr
*)0);
670 if (vp
->v_type
!= VLNK
) {
677 error
= VOP_READLINK(vp
, uiop
, cred
);
679 getret
= VOP_GETATTR(vp
, &attr
);
682 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_UNSIGNED
);
684 nfsm_srvpostop_attr(getret
, &attr
);
690 if (uiop
->uio_resid
> 0) {
691 len
-= uiop
->uio_resid
;
692 tlen
= nfsm_rndup(len
);
693 nfsm_adj(mp3
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
695 nfsm_build(tl
, u_int32_t
*, NFSX_UNSIGNED
);
696 *tl
= txdr_unsigned(len
);
711 nfsrv_read(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
712 struct thread
*td
, struct mbuf
**mrq
)
714 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
715 struct sockaddr
*nam
= nfsd
->nd_nam
;
716 caddr_t dpos
= nfsd
->nd_dpos
;
717 struct ucred
*cred
= &nfsd
->nd_cr
;
721 struct nfs_fattr
*fp
;
726 int error
= 0, rdonly
, cnt
, len
, left
, siz
, tlen
, getret
;
727 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), reqlen
;
729 struct mbuf
*mb
, *mb2
, *mreq
;
731 struct vnode
*vp
= NULL
;
732 struct mount
*mp
= NULL
;
735 struct uio io
, *uiop
= &io
;
736 struct vattr va
, *vap
= &va
;
741 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
742 fhp
= &nfh
.fh_generic
;
745 nfsm_dissect(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
746 off
= fxdr_hyper(tl
);
748 nfsm_dissect(tl
, u_int32_t
*, NFSX_UNSIGNED
);
749 off
= (off_t
)fxdr_unsigned(u_int32_t
, *tl
);
751 nfsm_srvstrsiz(reqlen
, NFS_SRVMAXDATA(nfsd
));
754 * Reference vp. If an error occurs, vp will be invalid, but we
755 * have to NULL it just in case. The macros might goto nfsmout
759 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
760 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
763 nfsm_reply(2 * NFSX_UNSIGNED
);
764 nfsm_srvpostop_attr(1, (struct vattr
*)0);
769 if (vp
->v_type
!= VREG
) {
773 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
776 if ((error
= nfsrv_access(mp
, vp
, VREAD
, cred
, rdonly
, td
, 1)) != 0)
777 error
= nfsrv_access(mp
, vp
, VEXEC
, cred
, rdonly
, td
, 1);
779 getret
= VOP_GETATTR(vp
, vap
);
785 nfsm_reply(NFSX_POSTOPATTR(v3
));
786 nfsm_srvpostop_attr(getret
, vap
);
792 * Calculate byte count to read
795 if (off
>= vap
->va_size
)
797 else if ((off
+ reqlen
) > vap
->va_size
)
798 cnt
= vap
->va_size
- off
;
803 * Calculate seqcount for heuristic
811 * Locate best candidate
814 hi
= ((int)(vm_offset_t
)vp
/ sizeof(struct vnode
)) % NUM_HEURISTIC
;
818 if (nfsheur
[hi
].nh_vp
== vp
) {
822 if (nfsheur
[hi
].nh_use
> 0)
823 --nfsheur
[hi
].nh_use
;
824 hi
= (hi
+ 1) % NUM_HEURISTIC
;
825 if (nfsheur
[hi
].nh_use
< nh
->nh_use
)
829 if (nh
->nh_vp
!= vp
) {
832 nh
->nh_use
= NHUSE_INIT
;
840 * Calculate heuristic
843 if ((off
== 0 && nh
->nh_seqcount
> 0) || off
== nh
->nh_nextr
) {
844 if (++nh
->nh_seqcount
> IO_SEQMAX
)
845 nh
->nh_seqcount
= IO_SEQMAX
;
846 } else if (nh
->nh_seqcount
> 1) {
851 nh
->nh_use
+= NHUSE_INC
;
852 if (nh
->nh_use
> NHUSE_MAX
)
853 nh
->nh_use
= NHUSE_MAX
;
854 ioflag
|= nh
->nh_seqcount
<< IO_SEQSHIFT
;
857 nfsm_reply(NFSX_POSTOPORFATTR(v3
) + 3 * NFSX_UNSIGNED
+nfsm_rndup(cnt
));
859 nfsm_build(tl
, u_int32_t
*, NFSX_V3FATTR
+ 4 * NFSX_UNSIGNED
);
861 fp
= (struct nfs_fattr
*)tl
;
862 tl
+= (NFSX_V3FATTR
/ sizeof (u_int32_t
));
864 nfsm_build(tl
, u_int32_t
*, NFSX_V2FATTR
+ NFSX_UNSIGNED
);
865 fp
= (struct nfs_fattr
*)tl
;
866 tl
+= (NFSX_V2FATTR
/ sizeof (u_int32_t
));
868 len
= left
= nfsm_rndup(cnt
);
871 * Generate the mbuf list with the uio_iov ref. to it.
876 siz
= min(M_TRAILINGSPACE(m
), left
);
882 m
= m_getcl(MB_WAIT
, MT_DATA
, 0);
888 MALLOC(iv
, struct iovec
*, i
* sizeof (struct iovec
),
890 uiop
->uio_iov
= iv2
= iv
;
896 panic("nfsrv_read iov");
897 siz
= min(M_TRAILINGSPACE(m
), left
);
899 iv
->iov_base
= mtod(m
, caddr_t
) + m
->m_len
;
908 uiop
->uio_iovcnt
= i
;
909 uiop
->uio_offset
= off
;
910 uiop
->uio_resid
= len
;
911 uiop
->uio_rw
= UIO_READ
;
912 uiop
->uio_segflg
= UIO_SYSSPACE
;
913 error
= VOP_READ(vp
, uiop
, IO_NODELOCKED
| ioflag
, cred
);
914 off
= uiop
->uio_offset
;
916 FREE((caddr_t
)iv2
, M_TEMP
);
917 if (error
|| (getret
= VOP_GETATTR(vp
, vap
))) {
923 nfsm_reply(NFSX_POSTOPATTR(v3
));
924 nfsm_srvpostop_attr(getret
, vap
);
933 nfsm_srvfillattr(vap
, fp
);
934 tlen
= len
- uiop
->uio_resid
;
935 cnt
= cnt
< tlen
? cnt
: tlen
;
936 tlen
= nfsm_rndup(cnt
);
937 if (len
!= tlen
|| tlen
!= cnt
)
938 nfsm_adj(mb
, len
- tlen
, tlen
- cnt
);
940 *tl
++ = txdr_unsigned(cnt
);
946 *tl
= txdr_unsigned(cnt
);
957 nfsrv_write(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
958 struct thread
*td
, struct mbuf
**mrq
)
960 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
961 struct sockaddr
*nam
= nfsd
->nd_nam
;
962 caddr_t dpos
= nfsd
->nd_dpos
;
963 struct ucred
*cred
= &nfsd
->nd_cr
;
967 struct nfs_fattr
*fp
;
969 struct vattr va
, forat
;
970 struct vattr
*vap
= &va
;
974 int error
= 0, rdonly
, len
, forat_ret
= 1;
975 int ioflags
, aftat_ret
= 1, retlen
, zeroing
, adjust
;
976 int stable
= NFSV3WRITE_FILESYNC
;
977 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
979 struct mbuf
*mb
, *mb2
, *mreq
;
980 struct vnode
*vp
= NULL
;
981 struct mount
*mp
= NULL
;
984 struct uio io
, *uiop
= &io
;
987 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
993 fhp
= &nfh
.fh_generic
;
996 nfsm_dissect(tl
, u_int32_t
*, 5 * NFSX_UNSIGNED
);
997 off
= fxdr_hyper(tl
);
999 stable
= fxdr_unsigned(int, *tl
++);
1001 nfsm_dissect(tl
, u_int32_t
*, 4 * NFSX_UNSIGNED
);
1002 off
= (off_t
)fxdr_unsigned(u_int32_t
, *++tl
);
1005 stable
= NFSV3WRITE_UNSTABLE
;
1007 retlen
= len
= fxdr_unsigned(int32_t, *tl
);
1011 * For NFS Version 2, it is not obvious what a write of zero length
1012 * should do, but I might as well be consistent with Version 3,
1013 * which is to return ok so long as there are no permission problems.
1021 adjust
= dpos
- mtod(mp1
, caddr_t
);
1022 mp1
->m_len
-= adjust
;
1023 if (mp1
->m_len
> 0 && adjust
> 0)
1024 NFSMADV(mp1
, adjust
);
1028 else if (mp1
->m_len
> 0) {
1031 mp1
->m_len
-= (i
- len
);
1040 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1042 nfsm_reply(2 * NFSX_UNSIGNED
);
1043 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1047 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
1048 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
1051 nfsm_reply(2 * NFSX_UNSIGNED
);
1052 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1057 forat_ret
= VOP_GETATTR(vp
, &forat
);
1058 if (vp
->v_type
!= VREG
) {
1062 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
1065 error
= nfsrv_access(mp
, vp
, VWRITE
, cred
, rdonly
, td
, 1);
1070 nfsm_reply(NFSX_WCCDATA(v3
));
1071 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1077 MALLOC(ivp
, struct iovec
*, cnt
* sizeof (struct iovec
), M_TEMP
,
1079 uiop
->uio_iov
= iv
= ivp
;
1080 uiop
->uio_iovcnt
= cnt
;
1083 if (mp1
->m_len
> 0) {
1084 ivp
->iov_base
= mtod(mp1
, caddr_t
);
1085 ivp
->iov_len
= mp1
->m_len
;
1093 * The IO_METASYNC flag indicates that all metadata (and not just
1094 * enough to ensure data integrity) mus be written to stable storage
1096 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1098 if (stable
== NFSV3WRITE_UNSTABLE
)
1099 ioflags
= IO_NODELOCKED
;
1100 else if (stable
== NFSV3WRITE_DATASYNC
)
1101 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1103 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1104 uiop
->uio_resid
= len
;
1105 uiop
->uio_rw
= UIO_WRITE
;
1106 uiop
->uio_segflg
= UIO_SYSSPACE
;
1107 uiop
->uio_td
= NULL
;
1108 uiop
->uio_offset
= off
;
1109 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
1110 nfsstats
.srvvop_writes
++;
1111 FREE((caddr_t
)iv
, M_TEMP
);
1113 aftat_ret
= VOP_GETATTR(vp
, vap
);
1118 nfsm_reply(NFSX_PREOPATTR(v3
) + NFSX_POSTOPORFATTR(v3
) +
1119 2 * NFSX_UNSIGNED
+ NFSX_WRITEVERF(v3
));
1121 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, vap
);
1126 nfsm_build(tl
, u_int32_t
*, 4 * NFSX_UNSIGNED
);
1127 *tl
++ = txdr_unsigned(retlen
);
1129 * If nfs_async is set, then pretend the write was FILESYNC.
1131 if (stable
== NFSV3WRITE_UNSTABLE
&& !nfs_async
)
1132 *tl
++ = txdr_unsigned(stable
);
1134 *tl
++ = txdr_unsigned(NFSV3WRITE_FILESYNC
);
1136 * Actually, there is no need to txdr these fields,
1137 * but it may make the values more human readable,
1138 * for debugging purposes.
1140 if (nfsver
.tv_sec
== 0)
1142 *tl
++ = txdr_unsigned(nfsver
.tv_sec
);
1143 *tl
= txdr_unsigned(nfsver
.tv_nsec
/ 1000);
1145 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1146 nfsm_srvfillattr(vap
, fp
);
1155 * NFS write service with write gathering support. Called when
1156 * nfsrvw_procrastinate > 0.
1157 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1158 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1162 nfsrv_writegather(struct nfsrv_descript
**ndp
, struct nfssvc_sock
*slp
,
1163 struct thread
*td
, struct mbuf
**mrq
)
1166 struct nfsrv_descript
*wp
, *nfsd
, *owp
, *swp
;
1167 struct nfs_fattr
*fp
;
1170 struct nfsrvw_delayhash
*wpp
;
1172 struct vattr va
, forat
;
1176 int error
= 0, rdonly
, len
, forat_ret
= 1;
1177 int ioflags
, aftat_ret
= 1, adjust
, v3
, zeroing
;
1179 struct mbuf
*mb
, *mb2
, *mreq
, *mrep
, *md
, *mp1
;
1180 struct vnode
*vp
= NULL
;
1181 struct mount
*mp
= NULL
;
1182 struct uio io
, *uiop
= &io
;
1185 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
1194 mrep
= nfsd
->nd_mrep
;
1196 dpos
= nfsd
->nd_dpos
;
1197 cred
= &nfsd
->nd_cr
;
1198 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1199 LIST_INIT(&nfsd
->nd_coalesce
);
1200 nfsd
->nd_mreq
= NULL
;
1201 nfsd
->nd_stable
= NFSV3WRITE_FILESYNC
;
1202 cur_usec
= nfs_curusec();
1203 nfsd
->nd_time
= cur_usec
+
1204 (v3
? nfsrvw_procrastinate_v3
: nfsrvw_procrastinate
);
1207 * Now, get the write header..
1209 nfsm_srvmtofh(&nfsd
->nd_fh
);
1211 nfsm_dissect(tl
, u_int32_t
*, 5 * NFSX_UNSIGNED
);
1212 nfsd
->nd_off
= fxdr_hyper(tl
);
1214 nfsd
->nd_stable
= fxdr_unsigned(int, *tl
++);
1216 nfsm_dissect(tl
, u_int32_t
*, 4 * NFSX_UNSIGNED
);
1217 nfsd
->nd_off
= (off_t
)fxdr_unsigned(u_int32_t
, *++tl
);
1220 nfsd
->nd_stable
= NFSV3WRITE_UNSTABLE
;
1222 len
= fxdr_unsigned(int32_t, *tl
);
1224 nfsd
->nd_eoff
= nfsd
->nd_off
+ len
;
1227 * Trim the header out of the mbuf list and trim off any trailing
1228 * junk so that the mbuf list has only the write data.
1236 adjust
= dpos
- mtod(mp1
, caddr_t
);
1237 mp1
->m_len
-= adjust
;
1238 if (mp1
->m_len
> 0 && adjust
> 0)
1239 NFSMADV(mp1
, adjust
);
1246 mp1
->m_len
-= (i
- len
);
1252 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1256 nfsm_writereply(2 * NFSX_UNSIGNED
, v3
);
1258 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1259 nfsd
->nd_mreq
= mreq
;
1260 nfsd
->nd_mrep
= NULL
;
1265 * Add this entry to the hash and time queues.
1269 wp
= slp
->ns_tq
.lh_first
;
1270 while (wp
&& wp
->nd_time
< nfsd
->nd_time
) {
1272 wp
= wp
->nd_tq
.le_next
;
1274 NFS_DPF(WG
, ("Q%03x", nfsd
->nd_retxid
& 0xfff));
1276 LIST_INSERT_AFTER(owp
, nfsd
, nd_tq
);
1278 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1280 if (nfsd
->nd_mrep
) {
1281 wpp
= NWDELAYHASH(slp
, nfsd
->nd_fh
.fh_fid
.fid_data
);
1285 bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1287 wp
= wp
->nd_hash
.le_next
;
1289 while (wp
&& wp
->nd_off
< nfsd
->nd_off
&&
1290 !bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1292 wp
= wp
->nd_hash
.le_next
;
1295 LIST_INSERT_AFTER(owp
, nfsd
, nd_hash
);
1298 * Search the hash list for overlapping entries and
1301 for(; nfsd
&& NFSW_CONTIG(owp
, nfsd
); nfsd
= wp
) {
1302 wp
= nfsd
->nd_hash
.le_next
;
1303 if (NFSW_SAMECRED(owp
, nfsd
))
1304 nfsrvw_coalesce(owp
, nfsd
);
1307 LIST_INSERT_HEAD(wpp
, nfsd
, nd_hash
);
1314 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1315 * and generate the associated reply mbuf list(s).
1318 cur_usec
= nfs_curusec();
1320 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= owp
) {
1321 owp
= nfsd
->nd_tq
.le_next
;
1322 if (nfsd
->nd_time
> cur_usec
)
1326 NFS_DPF(WG
, ("P%03x", nfsd
->nd_retxid
& 0xfff));
1327 LIST_REMOVE(nfsd
, nd_tq
);
1328 LIST_REMOVE(nfsd
, nd_hash
);
1330 mrep
= nfsd
->nd_mrep
;
1331 nfsd
->nd_mrep
= NULL
;
1332 cred
= &nfsd
->nd_cr
;
1333 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1334 forat_ret
= aftat_ret
= 1;
1335 error
= nfsrv_fhtovp(&nfsd
->nd_fh
, 1, &mp
, &vp
, cred
, slp
,
1336 nfsd
->nd_nam
, &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
1339 forat_ret
= VOP_GETATTR(vp
, &forat
);
1340 if (vp
->v_type
!= VREG
) {
1344 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
1350 error
= nfsrv_access(mp
, vp
, VWRITE
, cred
, rdonly
, td
, 1);
1353 if (nfsd
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1354 ioflags
= IO_NODELOCKED
;
1355 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
)
1356 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1358 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1359 uiop
->uio_rw
= UIO_WRITE
;
1360 uiop
->uio_segflg
= UIO_SYSSPACE
;
1361 uiop
->uio_td
= NULL
;
1362 uiop
->uio_offset
= nfsd
->nd_off
;
1363 uiop
->uio_resid
= nfsd
->nd_eoff
- nfsd
->nd_off
;
1364 if (uiop
->uio_resid
> 0) {
1372 uiop
->uio_iovcnt
= i
;
1373 MALLOC(iov
, struct iovec
*, i
* sizeof (struct iovec
),
1375 uiop
->uio_iov
= ivp
= iov
;
1378 if (mp1
->m_len
> 0) {
1379 ivp
->iov_base
= mtod(mp1
, caddr_t
);
1380 ivp
->iov_len
= mp1
->m_len
;
1386 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
1387 nfsstats
.srvvop_writes
++;
1389 FREE((caddr_t
)iov
, M_TEMP
);
1393 aftat_ret
= VOP_GETATTR(vp
, &va
);
1399 * Loop around generating replies for all write rpcs that have
1400 * now been completed.
1404 NFS_DPF(WG
, ("R%03x", nfsd
->nd_retxid
& 0xfff));
1406 nfsm_writereply(NFSX_WCCDATA(v3
), v3
);
1408 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1411 nfsm_writereply(NFSX_PREOPATTR(v3
) +
1412 NFSX_POSTOPORFATTR(v3
) + 2 * NFSX_UNSIGNED
+
1413 NFSX_WRITEVERF(v3
), v3
);
1415 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1416 nfsm_build(tl
, u_int32_t
*, 4 * NFSX_UNSIGNED
);
1417 *tl
++ = txdr_unsigned(nfsd
->nd_len
);
1418 *tl
++ = txdr_unsigned(swp
->nd_stable
);
1420 * Actually, there is no need to txdr these fields,
1421 * but it may make the values more human readable,
1422 * for debugging purposes.
1424 if (nfsver
.tv_sec
== 0)
1426 *tl
++ = txdr_unsigned(nfsver
.tv_sec
);
1427 *tl
= txdr_unsigned(nfsver
.tv_nsec
/ 1000);
1429 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1430 nfsm_srvfillattr(&va
, fp
);
1433 nfsd
->nd_mreq
= mreq
;
1435 panic("nfsrv_write: nd_mrep not free");
1438 * Done. Put it at the head of the timer queue so that
1439 * the final phase can return the reply.
1444 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1446 nfsd
= swp
->nd_coalesce
.lh_first
;
1448 LIST_REMOVE(nfsd
, nd_tq
);
1454 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1461 * Search for a reply to return.
1464 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= nfsd
->nd_tq
.le_next
)
1465 if (nfsd
->nd_mreq
) {
1466 NFS_DPF(WG
, ("X%03x", nfsd
->nd_retxid
& 0xfff));
1467 LIST_REMOVE(nfsd
, nd_tq
);
1468 *mrq
= nfsd
->nd_mreq
;
1477 * Coalesce the write request nfsd into owp. To do this we must:
1478 * - remove nfsd from the queues
1479 * - merge nfsd->nd_mrep into owp->nd_mrep
1480 * - update the nd_eoff and nd_stable for owp
1481 * - put nfsd on owp's nd_coalesce list
1482 * NB: Must be called at splsoftclock().
1485 nfsrvw_coalesce(struct nfsrv_descript
*owp
, struct nfsrv_descript
*nfsd
)
1489 struct nfsrv_descript
*p
;
1491 NFS_DPF(WG
, ("C%03x-%03x",
1492 nfsd
->nd_retxid
& 0xfff, owp
->nd_retxid
& 0xfff));
1493 LIST_REMOVE(nfsd
, nd_hash
);
1494 LIST_REMOVE(nfsd
, nd_tq
);
1495 if (owp
->nd_eoff
< nfsd
->nd_eoff
) {
1496 overlap
= owp
->nd_eoff
- nfsd
->nd_off
;
1498 panic("nfsrv_coalesce: bad off");
1500 m_adj(nfsd
->nd_mrep
, overlap
);
1504 mp1
->m_next
= nfsd
->nd_mrep
;
1505 owp
->nd_eoff
= nfsd
->nd_eoff
;
1507 m_freem(nfsd
->nd_mrep
);
1508 nfsd
->nd_mrep
= NULL
;
1509 if (nfsd
->nd_stable
== NFSV3WRITE_FILESYNC
)
1510 owp
->nd_stable
= NFSV3WRITE_FILESYNC
;
1511 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
&&
1512 owp
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1513 owp
->nd_stable
= NFSV3WRITE_DATASYNC
;
1514 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nfsd
, nd_tq
);
1517 * If nfsd had anything else coalesced into it, transfer them
1518 * to owp, otherwise their replies will never get sent.
1520 for (p
= nfsd
->nd_coalesce
.lh_first
; p
;
1521 p
= nfsd
->nd_coalesce
.lh_first
) {
1522 LIST_REMOVE(p
, nd_tq
);
1523 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1528 * nfs create service
1529 * now does a truncate to 0 length via. setattr if it already exists
1532 nfsrv_create(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
1533 struct thread
*td
, struct mbuf
**mrq
)
1535 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1536 struct sockaddr
*nam
= nfsd
->nd_nam
;
1537 caddr_t dpos
= nfsd
->nd_dpos
;
1538 struct ucred
*cred
= &nfsd
->nd_cr
;
1539 struct nfs_fattr
*fp
;
1540 struct vattr va
, dirfor
, diraft
;
1541 struct vattr
*vap
= &va
;
1542 struct nfsv2_sattr
*sp
;
1544 struct nlookupdata nd
;
1547 int error
= 0, len
, tsize
, dirfor_ret
= 1, diraft_ret
= 1;
1548 udev_t rdev
= NOUDEV
;
1549 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), how
, exclusive_flag
= 0;
1552 struct mbuf
*mb
, *mb2
, *mreq
;
1560 u_char cverf
[NFSX_V3CREATEVERF
];
1562 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
1568 fhp
= &nfh
.fh_generic
;
1570 nfsm_srvnamesiz(len
);
1573 * Call namei and do initial cleanup to get a few things
1574 * out of the way. If we get an initial error we cleanup
1575 * and return here to avoid special-casing the invalid nd
1576 * structure through the rest of the case. dirp may be
1577 * set even if an error occurs, but the nd structure will not
1578 * be valid at all if an error occurs so we have to invalidate it
1579 * prior to calling nfsm_reply ( which might goto nfsmout ).
1581 error
= nfs_namei(&nd
, cred
, NAMEI_CREATE
, &dvp
, &vp
,
1582 fhp
, len
, slp
, nam
, &md
, &dpos
, &dirp
,
1583 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1584 mp
= vfs_getvfs(&fhp
->fh_fsid
);
1588 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
1595 nfsm_reply(NFSX_WCCDATA(v3
));
1596 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1602 * No error. Continue. State:
1605 * vp may be valid or NULL if the target does not
1609 * The error state is set through the code and we may also do some
1610 * opportunistic releasing of vnodes to avoid holding locks through
1611 * NFS I/O. The cleanup at the end is a catch-all
1616 nfsm_dissect(tl
, u_int32_t
*, NFSX_UNSIGNED
);
1617 how
= fxdr_unsigned(int, *tl
);
1619 case NFSV3CREATE_GUARDED
:
1625 case NFSV3CREATE_UNCHECKED
:
1628 case NFSV3CREATE_EXCLUSIVE
:
1629 nfsm_dissect(cp
, caddr_t
, NFSX_V3CREATEVERF
);
1630 bcopy(cp
, cverf
, NFSX_V3CREATEVERF
);
1634 vap
->va_type
= VREG
;
1636 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1637 vap
->va_type
= IFTOVT(fxdr_unsigned(u_int32_t
, sp
->sa_mode
));
1638 if (vap
->va_type
== VNON
)
1639 vap
->va_type
= VREG
;
1640 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
1641 switch (vap
->va_type
) {
1643 tsize
= fxdr_unsigned(int32_t, sp
->sa_size
);
1645 vap
->va_size
= (u_quad_t
)tsize
;
1650 rdev
= fxdr_unsigned(long, sp
->sa_size
);
1658 * Iff doesn't exist, create it
1659 * otherwise just truncate to 0 length
1660 * should I set the mode too ?
1662 * The only possible error we can have at this point is EEXIST.
1663 * nd.ni_vp will also be non-NULL in that case.
1666 if (vap
->va_mode
== (mode_t
)VNOVAL
)
1668 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1670 error
= VOP_NCREATE(&nd
.nl_nch
, dvp
, &vp
,
1675 if (exclusive_flag
) {
1678 bcopy(cverf
, (caddr_t
)&vap
->va_atime
,
1680 error
= VOP_SETATTR(vp
, vap
, cred
);
1684 vap
->va_type
== VCHR
||
1685 vap
->va_type
== VBLK
||
1686 vap
->va_type
== VFIFO
1689 * Handle SysV FIFO node special cases. All other
1690 * devices require super user to access.
1692 if (vap
->va_type
== VCHR
&& rdev
== 0xffffffff)
1693 vap
->va_type
= VFIFO
;
1694 if (vap
->va_type
!= VFIFO
&&
1695 (error
= suser_cred(cred
, 0))) {
1698 vap
->va_rmajor
= umajor(rdev
);
1699 vap
->va_rminor
= uminor(rdev
);
1702 error
= VOP_NMKNOD(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
);
1709 * XXX what is this junk supposed to do ?
1716 * release dvp prior to lookup
1724 * Even though LOCKPARENT was cleared, ni_dvp may
1727 nd
.ni_cnd
.cn_nameiop
= NAMEI_LOOKUP
;
1728 nd
.ni_cnd
.cn_flags
&= ~(CNP_LOCKPARENT
);
1729 nd
.ni_cnd
.cn_td
= td
;
1730 nd
.ni_cnd
.cn_cred
= cred
;
1732 error
= lookup(&nd
);
1737 /* fall through on certain errors */
1739 nfsrv_object_create(nd
.ni_vp
);
1740 if (nd
.ni_cnd
.cn_flags
& CNP_ISSYMLINK
) {
1749 if (vap
->va_size
!= -1) {
1750 error
= nfsrv_access(mp
, vp
, VWRITE
, cred
,
1751 (nd
.nl_flags
& NLC_NFS_RDONLY
), td
, 0);
1753 tempsize
= vap
->va_size
;
1755 vap
->va_size
= tempsize
;
1756 error
= VOP_SETATTR(vp
, vap
, cred
);
1762 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
1763 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1765 error
= VOP_GETATTR(vp
, vap
);
1768 if (exclusive_flag
&& !error
&&
1769 bcmp(cverf
, (caddr_t
)&vap
->va_atime
, NFSX_V3CREATEVERF
))
1771 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
1775 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_FATTR(v3
) + NFSX_WCCDATA(v3
));
1778 nfsm_srvpostop_fh(fhp
);
1779 nfsm_srvpostop_attr(0, vap
);
1781 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1784 nfsm_srvfhtom(fhp
, v3
);
1785 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1786 nfsm_srvfillattr(vap
, fp
);
1811 * nfs v3 mknod service
1814 nfsrv_mknod(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
1815 struct thread
*td
, struct mbuf
**mrq
)
1817 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1818 struct sockaddr
*nam
= nfsd
->nd_nam
;
1819 caddr_t dpos
= nfsd
->nd_dpos
;
1820 struct ucred
*cred
= &nfsd
->nd_cr
;
1821 struct vattr va
, dirfor
, diraft
;
1822 struct vattr
*vap
= &va
;
1824 struct nlookupdata nd
;
1827 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
1830 struct mbuf
*mb
, *mb2
, *mreq
;
1837 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
1843 fhp
= &nfh
.fh_generic
;
1845 nfsm_srvnamesiz(len
);
1848 * Handle nfs_namei() call. If an error occurs, the nd structure
1849 * is not valid. However, nfsm_*() routines may still jump to
1853 error
= nfs_namei(&nd
, cred
, NAMEI_CREATE
, &dvp
, &vp
,
1854 fhp
, len
, slp
, nam
, &md
, &dpos
, &dirp
,
1855 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1857 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
1859 nfsm_reply(NFSX_WCCDATA(1));
1860 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1864 nfsm_dissect(tl
, u_int32_t
*, NFSX_UNSIGNED
);
1865 vtyp
= nfsv3tov_type(*tl
);
1866 if (vtyp
!= VCHR
&& vtyp
!= VBLK
&& vtyp
!= VSOCK
&& vtyp
!= VFIFO
) {
1867 error
= NFSERR_BADTYPE
;
1872 if (vtyp
== VCHR
|| vtyp
== VBLK
) {
1873 nfsm_dissect(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
1874 vap
->va_rmajor
= fxdr_unsigned(u_int32_t
, *tl
++);
1875 vap
->va_rminor
= fxdr_unsigned(u_int32_t
, *tl
);
1879 * Iff doesn't exist, create it.
1885 vap
->va_type
= vtyp
;
1886 if (vap
->va_mode
== (mode_t
)VNOVAL
)
1888 if (vtyp
== VSOCK
) {
1890 error
= VOP_NCREATE(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
);
1894 if (vtyp
!= VFIFO
&& (error
= suser_cred(cred
, 0)))
1898 error
= VOP_NMKNOD(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
);
1906 * send response, cleanup, return.
1918 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
1919 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1921 error
= VOP_GETATTR(vp
, vap
);
1927 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
1932 nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
1934 nfsm_srvpostop_fh(fhp
);
1935 nfsm_srvpostop_attr(0, vap
);
1937 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1955 * nfs remove service
1958 nfsrv_remove(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
1959 struct thread
*td
, struct mbuf
**mrq
)
1961 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1962 struct sockaddr
*nam
= nfsd
->nd_nam
;
1963 caddr_t dpos
= nfsd
->nd_dpos
;
1964 struct ucred
*cred
= &nfsd
->nd_cr
;
1965 struct nlookupdata nd
;
1969 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
1970 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1972 struct mbuf
*mb
, *mreq
;
1976 struct vattr dirfor
, diraft
;
1980 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
1986 fhp
= &nfh
.fh_generic
;
1988 nfsm_srvnamesiz(len
);
1990 error
= nfs_namei(&nd
, cred
, NAMEI_DELETE
, &dvp
, &vp
,
1991 fhp
, len
, slp
, nam
, &md
, &dpos
, &dirp
,
1992 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1995 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
1998 if (vp
->v_type
== VDIR
) {
1999 error
= EPERM
; /* POSIX */
2003 * The root of a mounted filesystem cannot be deleted.
2005 if (vp
->v_flag
& VROOT
) {
2017 error
= VOP_NREMOVE(&nd
.nl_nch
, dvp
, nd
.nl_cred
);
2023 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2024 nfsm_reply(NFSX_WCCDATA(v3
));
2026 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2045 * nfs rename service
2048 nfsrv_rename(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2049 struct thread
*td
, struct mbuf
**mrq
)
2051 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2052 struct sockaddr
*nam
= nfsd
->nd_nam
;
2053 caddr_t dpos
= nfsd
->nd_dpos
;
2054 struct ucred
*cred
= &nfsd
->nd_cr
;
2058 int error
= 0, len
, len2
, fdirfor_ret
= 1, fdiraft_ret
= 1;
2059 int tdirfor_ret
= 1, tdiraft_ret
= 1;
2060 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2062 struct mbuf
*mb
, *mreq
;
2063 struct nlookupdata fromnd
, tond
;
2064 struct vnode
*fvp
, *fdirp
, *fdvp
;
2065 struct vnode
*tvp
, *tdirp
, *tdvp
;
2066 struct namecache
*ncp
;
2067 struct vattr fdirfor
, fdiraft
, tdirfor
, tdiraft
;
2069 fhandle_t
*ffhp
, *tfhp
;
2072 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2074 fvp
= (struct vnode
*)0;
2076 ffhp
= &fnfh
.fh_generic
;
2077 tfhp
= &tnfh
.fh_generic
;
2080 * Clear fields incase goto nfsmout occurs from macro.
2083 nlookup_zero(&fromnd
);
2084 nlookup_zero(&tond
);
2088 nfsm_srvmtofh(ffhp
);
2089 nfsm_srvnamesiz(len
);
2091 * Remember our original uid so that we can reset cr_uid before
2092 * the second nfs_namei() call, in case it is remapped.
2094 saved_uid
= cred
->cr_uid
;
2095 error
= nfs_namei(&fromnd
, cred
, NAMEI_DELETE
, NULL
, NULL
,
2096 ffhp
, len
, slp
, nam
, &md
, &dpos
, &fdirp
,
2097 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2100 fdirfor_ret
= VOP_GETATTR(fdirp
, &fdirfor
);
2103 nfsm_reply(2 * NFSX_WCCDATA(v3
));
2104 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
2105 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
2111 * We have to unlock the from ncp before we can safely lookup
2114 KKASSERT(fromnd
.nl_flags
& NLC_NCPISLOCKED
);
2115 cache_unlock(&fromnd
.nl_nch
);
2116 fromnd
.nl_flags
&= ~NLC_NCPISLOCKED
;
2117 nfsm_srvmtofh(tfhp
);
2118 nfsm_strsiz(len2
, NFS_MAXNAMLEN
);
2119 cred
->cr_uid
= saved_uid
;
2121 error
= nfs_namei(&tond
, cred
, NAMEI_RENAME
, NULL
, NULL
,
2122 tfhp
, len2
, slp
, nam
, &md
, &dpos
, &tdirp
,
2123 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2126 tdirfor_ret
= VOP_GETATTR(tdirp
, &tdirfor
);
2134 if (cache_lock_nonblock(&fromnd
.nl_nch
) == 0) {
2135 cache_resolve(&fromnd
.nl_nch
, fromnd
.nl_cred
);
2136 } else if (fromnd
.nl_nch
.ncp
> tond
.nl_nch
.ncp
) {
2137 cache_lock(&fromnd
.nl_nch
);
2138 cache_resolve(&fromnd
.nl_nch
, fromnd
.nl_cred
);
2140 cache_unlock(&tond
.nl_nch
);
2141 cache_lock(&fromnd
.nl_nch
);
2142 cache_resolve(&fromnd
.nl_nch
, fromnd
.nl_cred
);
2143 cache_lock(&tond
.nl_nch
);
2144 cache_resolve(&tond
.nl_nch
, tond
.nl_cred
);
2146 fromnd
.nl_flags
|= NLC_NCPISLOCKED
;
2148 fvp
= fromnd
.nl_nch
.ncp
->nc_vp
;
2149 tvp
= tond
.nl_nch
.ncp
->nc_vp
;
2152 * Set fdvp and tdvp. We haven't done all the topology checks
2153 * so these can wind up NULL (e.g. if either fvp or tvp is a mount
2154 * point). If we get through the checks these will be guarenteed
2157 * Holding the children ncp's should be sufficient to prevent
2158 * fdvp and tdvp ripouts.
2160 if (fromnd
.nl_nch
.ncp
->nc_parent
)
2161 fdvp
= fromnd
.nl_nch
.ncp
->nc_parent
->nc_vp
;
2164 if (tond
.nl_nch
.ncp
->nc_parent
)
2165 tdvp
= tond
.nl_nch
.ncp
->nc_parent
->nc_vp
;
2170 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2176 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2183 if (tvp
->v_type
== VDIR
&& (tond
.nl_nch
.ncp
->nc_flag
& NCF_ISMOUNTPT
)) {
2191 if (fvp
->v_type
== VDIR
&& (fromnd
.nl_nch
.ncp
->nc_flag
& NCF_ISMOUNTPT
)) {
2198 if (fromnd
.nl_nch
.mount
!= tond
.nl_nch
.mount
) {
2205 if (fromnd
.nl_nch
.ncp
== tond
.nl_nch
.ncp
->nc_parent
) {
2213 * You cannot rename a source into itself or a subdirectory of itself.
2214 * We check this by travsering the target directory upwards looking
2215 * for a match against the source.
2218 for (ncp
= tond
.nl_nch
.ncp
; ncp
; ncp
= ncp
->nc_parent
) {
2219 if (fromnd
.nl_nch
.ncp
== ncp
) {
2227 * If source is the same as the destination (that is the
2228 * same vnode with the same name in the same directory),
2229 * then there is nothing to do.
2231 if (fromnd
.nl_nch
.ncp
== tond
.nl_nch
.ncp
)
2236 * The VOP_NRENAME function releases all vnode references &
2237 * locks prior to returning so we need to clear the pointers
2238 * to bypass cleanup code later on.
2240 error
= VOP_NRENAME(&fromnd
.nl_nch
, &tond
.nl_nch
,
2241 fdvp
, tdvp
, tond
.nl_cred
);
2250 fdiraft_ret
= VOP_GETATTR(fdirp
, &fdiraft
);
2252 tdiraft_ret
= VOP_GETATTR(tdirp
, &tdiraft
);
2253 nfsm_reply(2 * NFSX_WCCDATA(v3
));
2255 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
2256 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
2264 nlookup_done(&tond
);
2267 nlookup_done(&fromnd
);
2275 nfsrv_link(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2276 struct thread
*td
, struct mbuf
**mrq
)
2278 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2279 struct sockaddr
*nam
= nfsd
->nd_nam
;
2280 caddr_t dpos
= nfsd
->nd_dpos
;
2281 struct ucred
*cred
= &nfsd
->nd_cr
;
2282 struct nlookupdata nd
;
2286 int error
= 0, rdonly
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2287 int getret
= 1, v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2289 struct mbuf
*mb
, *mreq
;
2296 struct vattr dirfor
, diraft
, at
;
2298 fhandle_t
*fhp
, *dfhp
;
2300 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2302 dirp
= dvp
= vp
= xp
= NULL
;
2305 fhp
= &nfh
.fh_generic
;
2306 dfhp
= &dnfh
.fh_generic
;
2308 nfsm_srvmtofh(dfhp
);
2309 nfsm_srvnamesiz(len
);
2311 error
= nfsrv_fhtovp(fhp
, FALSE
, &xmp
, &xp
, cred
, slp
, nam
,
2312 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
2314 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2315 nfsm_srvpostop_attr(getret
, &at
);
2316 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2321 if (xp
->v_type
== VDIR
) {
2322 error
= EPERM
; /* POSIX */
2326 error
= nfs_namei(&nd
, cred
, NAMEI_CREATE
, &dvp
, &vp
,
2327 dfhp
, len
, slp
, nam
, &md
, &dpos
, &dirp
,
2328 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2331 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2340 if (xp
->v_mount
!= dvp
->v_mount
)
2345 error
= VOP_NLINK(&nd
.nl_nch
, dvp
, xp
, nd
.nl_cred
);
2353 getret
= VOP_GETATTR(xp
, &at
);
2355 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2356 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2358 nfsm_srvpostop_attr(getret
, &at
);
2359 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2382 * nfs symbolic link service
2385 nfsrv_symlink(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2386 struct thread
*td
, struct mbuf
**mrq
)
2388 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2389 struct sockaddr
*nam
= nfsd
->nd_nam
;
2390 caddr_t dpos
= nfsd
->nd_dpos
;
2391 struct ucred
*cred
= &nfsd
->nd_cr
;
2392 struct vattr va
, dirfor
, diraft
;
2393 struct nlookupdata nd
;
2394 struct vattr
*vap
= &va
;
2397 struct nfsv2_sattr
*sp
;
2398 char *bpos
, *pathcp
= (char *)0, *cp2
;
2401 int error
= 0, len
, len2
, dirfor_ret
= 1, diraft_ret
= 1;
2402 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2403 struct mbuf
*mb
, *mreq
, *mb2
;
2410 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2416 fhp
= &nfh
.fh_generic
;
2418 nfsm_srvnamesiz(len
);
2420 error
= nfs_namei(&nd
, cred
, NAMEI_CREATE
, &dvp
, &vp
,
2421 fhp
, len
, slp
, nam
, &md
, &dpos
, &dirp
,
2422 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2425 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2433 nfsm_strsiz(len2
, NFS_MAXPATHLEN
);
2434 MALLOC(pathcp
, caddr_t
, len2
+ 1, M_TEMP
, M_WAITOK
);
2435 iv
.iov_base
= pathcp
;
2437 io
.uio_resid
= len2
;
2441 io
.uio_segflg
= UIO_SYSSPACE
;
2442 io
.uio_rw
= UIO_READ
;
2444 nfsm_mtouio(&io
, len2
);
2446 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2447 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
2449 *(pathcp
+ len2
) = '\0';
2455 if (vap
->va_mode
== (mode_t
)VNOVAL
)
2459 error
= VOP_NSYMLINK(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
, pathcp
);
2463 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
2464 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
2466 error
= VOP_GETATTR(vp
, vap
);
2481 FREE(pathcp
, M_TEMP
);
2485 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2489 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2492 nfsm_srvpostop_fh(fhp
);
2493 nfsm_srvpostop_attr(0, vap
);
2495 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2507 FREE(pathcp
, M_TEMP
);
2515 nfsrv_mkdir(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2516 struct thread
*td
, struct mbuf
**mrq
)
2518 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2519 struct sockaddr
*nam
= nfsd
->nd_nam
;
2520 caddr_t dpos
= nfsd
->nd_dpos
;
2521 struct ucred
*cred
= &nfsd
->nd_cr
;
2522 struct vattr va
, dirfor
, diraft
;
2523 struct vattr
*vap
= &va
;
2524 struct nfs_fattr
*fp
;
2525 struct nlookupdata nd
;
2530 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2531 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2533 struct mbuf
*mb
, *mb2
, *mreq
;
2540 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2546 fhp
= &nfh
.fh_generic
;
2548 nfsm_srvnamesiz(len
);
2550 error
= nfs_namei(&nd
, cred
, NAMEI_CREATE
, &dvp
, &vp
,
2551 fhp
, len
, slp
, nam
, &md
, &dpos
, &dirp
,
2552 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2555 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2558 nfsm_reply(NFSX_WCCDATA(v3
));
2559 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2567 nfsm_dissect(tl
, u_int32_t
*, NFSX_UNSIGNED
);
2568 vap
->va_mode
= nfstov_mode(*tl
++);
2572 * At this point nd.ni_dvp is referenced and exclusively locked and
2573 * nd.ni_vp, if it exists, is referenced but not locked.
2576 vap
->va_type
= VDIR
;
2583 * Issue mkdir op. Since SAVESTART is not set, the pathname
2584 * component is freed by the VOP call. This will fill-in
2585 * nd.ni_vp, reference, and exclusively lock it.
2587 if (vap
->va_mode
== (mode_t
)VNOVAL
)
2590 error
= VOP_NMKDIR(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
);
2595 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
2596 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
2598 error
= VOP_GETATTR(vp
, vap
);
2602 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2603 nfsm_reply(NFSX_SRVFH(v3
) + NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2606 nfsm_srvpostop_fh(fhp
);
2607 nfsm_srvpostop_attr(0, vap
);
2609 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2611 nfsm_srvfhtom(fhp
, v3
);
2612 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
2613 nfsm_srvfillattr(vap
, fp
);
2637 nfsrv_rmdir(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2638 struct thread
*td
, struct mbuf
**mrq
)
2640 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2641 struct sockaddr
*nam
= nfsd
->nd_nam
;
2642 caddr_t dpos
= nfsd
->nd_dpos
;
2643 struct ucred
*cred
= &nfsd
->nd_cr
;
2647 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2648 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2650 struct mbuf
*mb
, *mreq
;
2654 struct vattr dirfor
, diraft
;
2657 struct nlookupdata nd
;
2659 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2665 fhp
= &nfh
.fh_generic
;
2667 nfsm_srvnamesiz(len
);
2669 error
= nfs_namei(&nd
, cred
, NAMEI_DELETE
, &dvp
, &vp
,
2670 fhp
, len
, slp
, nam
, &md
, &dpos
, &dirp
,
2671 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2674 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2677 nfsm_reply(NFSX_WCCDATA(v3
));
2678 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2682 if (vp
->v_type
!= VDIR
) {
2688 * The root of a mounted filesystem cannot be deleted.
2690 if (vp
->v_flag
& VROOT
)
2694 * Issue or abort op. Since SAVESTART is not set, path name
2695 * component is freed by the VOP after either.
2702 error
= VOP_NRMDIR(&nd
.nl_nch
, dvp
, nd
.nl_cred
);
2709 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2710 nfsm_reply(NFSX_WCCDATA(v3
));
2712 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2733 * nfs readdir service
2734 * - mallocs what it thinks is enough to read
2735 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2736 * - calls VOP_READDIR()
2737 * - loops around building the reply
2738 * if the output generated exceeds count break out of loop
2739 * The nfsm_clget macro is used here so that the reply will be packed
2740 * tightly in mbuf clusters.
2741 * - it only knows that it has encountered eof when the VOP_READDIR()
2743 * - as such one readdir rpc will return eof false although you are there
2744 * and then the next will return eof
2745 * - it trims out records with d_fileno == 0
2746 * this doesn't matter for Unix clients, but they might confuse clients
2748 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2749 * than requested, but this may not apply to all filesystems. For
2750 * example, client NFS does not { although it is never remote mounted
2752 * The alternate call nfsrv_readdirplus() does lookups as well.
2753 * PS: The NFS protocol spec. does not clarify what the "count" byte
2754 * argument is a count of.. just name strings and file id's or the
2755 * entire reply rpc or ...
2756 * I tried just file name and id sizes and it confused the Sun client,
2757 * so I am using the full rpc size now. The "paranoia.." comment refers
2758 * to including the status longwords that are not a part of the dir.
2759 * "entry" structures, but are in the rpc.
2763 u_int32_t fl_postopok
;
2764 u_int32_t fl_fattr
[NFSX_V3FATTR
/ sizeof (u_int32_t
)];
2766 u_int32_t fl_fhsize
;
2767 u_int32_t fl_nfh
[NFSX_V3FH
/ sizeof (u_int32_t
)];
2771 nfsrv_readdir(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2772 struct thread
*td
, struct mbuf
**mrq
)
2774 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2775 struct sockaddr
*nam
= nfsd
->nd_nam
;
2776 caddr_t dpos
= nfsd
->nd_dpos
;
2777 struct ucred
*cred
= &nfsd
->nd_cr
;
2784 struct mbuf
*mb
, *mb2
, *mreq
, *mp1
, *mp2
;
2785 char *cpos
, *cend
, *cp2
, *rbuf
;
2786 struct vnode
*vp
= NULL
;
2787 struct mount
*mp
= NULL
;
2793 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2794 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, ncookies
;
2795 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2796 u_quad_t off
, toff
, verf
;
2797 off_t
*cookies
= NULL
, *cookiep
;
2799 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2800 fhp
= &nfh
.fh_generic
;
2803 nfsm_dissect(tl
, u_int32_t
*, 5 * NFSX_UNSIGNED
);
2804 toff
= fxdr_hyper(tl
);
2806 verf
= fxdr_hyper(tl
);
2809 nfsm_dissect(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
2810 toff
= fxdr_unsigned(u_quad_t
, *tl
++);
2811 verf
= 0; /* shut up gcc */
2814 cnt
= fxdr_unsigned(int, *tl
);
2815 siz
= ((cnt
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
2816 xfer
= NFS_SRVMAXDATA(nfsd
);
2822 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
2823 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
2824 if (!error
&& vp
->v_type
!= VDIR
) {
2830 nfsm_reply(NFSX_UNSIGNED
);
2831 nfsm_srvpostop_attr(getret
, &at
);
2837 * Obtain lock on vnode for this section of the code
2841 error
= getret
= VOP_GETATTR(vp
, &at
);
2844 * XXX This check may be too strict for Solaris 2.5 clients.
2846 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
2847 error
= NFSERR_BAD_COOKIE
;
2851 error
= nfsrv_access(mp
, vp
, VEXEC
, cred
, rdonly
, td
, 0);
2855 nfsm_reply(NFSX_POSTOPATTR(v3
));
2856 nfsm_srvpostop_attr(getret
, &at
);
2863 * end section. Allocate rbuf and continue
2865 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
2868 iv
.iov_len
= fullsiz
;
2871 io
.uio_offset
= (off_t
)off
;
2872 io
.uio_resid
= fullsiz
;
2873 io
.uio_segflg
= UIO_SYSSPACE
;
2874 io
.uio_rw
= UIO_READ
;
2878 kfree((caddr_t
)cookies
, M_TEMP
);
2881 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
2882 off
= (off_t
)io
.uio_offset
;
2883 if (!cookies
&& !error
)
2884 error
= NFSERR_PERM
;
2886 getret
= VOP_GETATTR(vp
, &at
);
2893 kfree((caddr_t
)rbuf
, M_TEMP
);
2895 kfree((caddr_t
)cookies
, M_TEMP
);
2896 nfsm_reply(NFSX_POSTOPATTR(v3
));
2897 nfsm_srvpostop_attr(getret
, &at
);
2902 siz
-= io
.uio_resid
;
2905 * If nothing read, return eof
2911 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) +
2914 nfsm_srvpostop_attr(getret
, &at
);
2915 nfsm_build(tl
, u_int32_t
*, 4 * NFSX_UNSIGNED
);
2916 txdr_hyper(at
.va_filerev
, tl
);
2919 nfsm_build(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
2922 FREE((caddr_t
)rbuf
, M_TEMP
);
2923 FREE((caddr_t
)cookies
, M_TEMP
);
2930 * Check for degenerate cases of nothing useful read.
2931 * If so go try again
2935 dp
= (struct dirent
*)cpos
;
2938 * For some reason FreeBSD's ufs_readdir() chooses to back the
2939 * directory offset up to a block boundary, so it is necessary to
2940 * skip over the records that preceed the requested offset. This
2941 * requires the assumption that file offset cookies monotonically
2944 while (cpos
< cend
&& ncookies
> 0 &&
2945 (dp
->d_ino
== 0 || dp
->d_type
== DT_WHT
||
2946 ((u_quad_t
)(*cookiep
)) <= toff
)) {
2947 dp
= _DIRENT_NEXT(dp
);
2952 if (cpos
>= cend
|| ncookies
== 0) {
2958 len
= 3 * NFSX_UNSIGNED
; /* paranoia, probably can be 0 */
2959 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) + siz
);
2961 nfsm_srvpostop_attr(getret
, &at
);
2962 nfsm_build(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
2963 txdr_hyper(at
.va_filerev
, tl
);
2967 be
= bp
+ M_TRAILINGSPACE(mp1
);
2969 /* Loop through the records and build reply */
2970 while (cpos
< cend
&& ncookies
> 0) {
2971 if (dp
->d_ino
!= 0 && dp
->d_type
!= DT_WHT
) {
2972 nlen
= dp
->d_namlen
;
2973 rem
= nfsm_rndup(nlen
) - nlen
;
2974 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
2976 len
+= 2 * NFSX_UNSIGNED
;
2982 * Build the directory record xdr from
2985 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
2987 bp
+= NFSX_UNSIGNED
;
2989 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
2991 bp
+= NFSX_UNSIGNED
;
2993 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
2994 *tl
= txdr_unsigned(dp
->d_ino
);
2995 bp
+= NFSX_UNSIGNED
;
2996 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
2997 *tl
= txdr_unsigned(nlen
);
2998 bp
+= NFSX_UNSIGNED
;
3000 /* And loop around copying the name */
3004 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3009 bcopy(cp
, bp
, tsiz
);
3015 /* And null pad to a int32_t boundary */
3016 for (i
= 0; i
< rem
; i
++)
3018 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3020 /* Finish off the record */
3022 *tl
= txdr_unsigned(*cookiep
>> 32);
3023 bp
+= NFSX_UNSIGNED
;
3024 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3026 *tl
= txdr_unsigned(*cookiep
);
3027 bp
+= NFSX_UNSIGNED
;
3029 dp
= _DIRENT_NEXT(dp
);
3036 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3038 bp
+= NFSX_UNSIGNED
;
3039 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3044 bp
+= NFSX_UNSIGNED
;
3047 mp1
->m_len
= bp
- mtod(mp1
, caddr_t
);
3049 mp1
->m_len
+= bp
- bpos
;
3050 FREE((caddr_t
)rbuf
, M_TEMP
);
3051 FREE((caddr_t
)cookies
, M_TEMP
);
3060 nfsrv_readdirplus(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3061 struct thread
*td
, struct mbuf
**mrq
)
3063 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3064 struct sockaddr
*nam
= nfsd
->nd_nam
;
3065 caddr_t dpos
= nfsd
->nd_dpos
;
3066 struct ucred
*cred
= &nfsd
->nd_cr
;
3073 struct mbuf
*mb
, *mb2
, *mreq
, *mp1
, *mp2
;
3074 char *cpos
, *cend
, *cp2
, *rbuf
;
3075 struct vnode
*vp
= NULL
, *nvp
;
3076 struct mount
*mp
= NULL
;
3079 fhandle_t
*fhp
, *nfhp
= (fhandle_t
*)fl
.fl_nfh
;
3082 struct vattr va
, at
, *vap
= &va
;
3083 struct nfs_fattr
*fp
;
3084 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
3085 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, dirlen
, ncookies
;
3086 u_quad_t off
, toff
, verf
;
3087 off_t
*cookies
= NULL
, *cookiep
; /* needs to be int64_t or off_t */
3089 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3090 fhp
= &nfh
.fh_generic
;
3092 nfsm_dissect(tl
, u_int32_t
*, 6 * NFSX_UNSIGNED
);
3093 toff
= fxdr_hyper(tl
);
3095 verf
= fxdr_hyper(tl
);
3097 siz
= fxdr_unsigned(int, *tl
++);
3098 cnt
= fxdr_unsigned(int, *tl
);
3100 siz
= ((siz
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
3101 xfer
= NFS_SRVMAXDATA(nfsd
);
3107 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3108 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3109 if (!error
&& vp
->v_type
!= VDIR
) {
3115 nfsm_reply(NFSX_UNSIGNED
);
3116 nfsm_srvpostop_attr(getret
, &at
);
3120 error
= getret
= VOP_GETATTR(vp
, &at
);
3123 * XXX This check may be too strict for Solaris 2.5 clients.
3125 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
3126 error
= NFSERR_BAD_COOKIE
;
3129 error
= nfsrv_access(mp
, vp
, VEXEC
, cred
, rdonly
, td
, 0);
3134 nfsm_reply(NFSX_V3POSTOPATTR
);
3135 nfsm_srvpostop_attr(getret
, &at
);
3140 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
3143 iv
.iov_len
= fullsiz
;
3146 io
.uio_offset
= (off_t
)off
;
3147 io
.uio_resid
= fullsiz
;
3148 io
.uio_segflg
= UIO_SYSSPACE
;
3149 io
.uio_rw
= UIO_READ
;
3153 kfree((caddr_t
)cookies
, M_TEMP
);
3156 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
3157 off
= (u_quad_t
)io
.uio_offset
;
3158 getret
= VOP_GETATTR(vp
, &at
);
3159 if (!cookies
&& !error
)
3160 error
= NFSERR_PERM
;
3167 kfree((caddr_t
)cookies
, M_TEMP
);
3168 kfree((caddr_t
)rbuf
, M_TEMP
);
3169 nfsm_reply(NFSX_V3POSTOPATTR
);
3170 nfsm_srvpostop_attr(getret
, &at
);
3175 siz
-= io
.uio_resid
;
3178 * If nothing read, return eof
3184 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+
3186 nfsm_srvpostop_attr(getret
, &at
);
3187 nfsm_build(tl
, u_int32_t
*, 4 * NFSX_UNSIGNED
);
3188 txdr_hyper(at
.va_filerev
, tl
);
3192 FREE((caddr_t
)cookies
, M_TEMP
);
3193 FREE((caddr_t
)rbuf
, M_TEMP
);
3200 * Check for degenerate cases of nothing useful read.
3201 * If so go try again
3205 dp
= (struct dirent
*)cpos
;
3208 * For some reason FreeBSD's ufs_readdir() chooses to back the
3209 * directory offset up to a block boundary, so it is necessary to
3210 * skip over the records that preceed the requested offset. This
3211 * requires the assumption that file offset cookies monotonically
3214 while (cpos
< cend
&& ncookies
> 0 &&
3215 (dp
->d_ino
== 0 || dp
->d_type
== DT_WHT
||
3216 ((u_quad_t
)(*cookiep
)) <= toff
)) {
3217 dp
= _DIRENT_NEXT(dp
);
3222 if (cpos
>= cend
|| ncookies
== 0) {
3229 * Probe one of the directory entries to see if the filesystem
3232 if (VFS_VGET(vp
->v_mount
, dp
->d_ino
, &nvp
) == EOPNOTSUPP
) {
3233 error
= NFSERR_NOTSUPP
;
3236 kfree((caddr_t
)cookies
, M_TEMP
);
3237 kfree((caddr_t
)rbuf
, M_TEMP
);
3238 nfsm_reply(NFSX_V3POSTOPATTR
);
3239 nfsm_srvpostop_attr(getret
, &at
);
3248 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
3250 nfsm_srvpostop_attr(getret
, &at
);
3251 nfsm_build(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
3252 txdr_hyper(at
.va_filerev
, tl
);
3255 be
= bp
+ M_TRAILINGSPACE(mp1
);
3257 /* Loop through the records and build reply */
3258 while (cpos
< cend
&& ncookies
> 0) {
3259 if (dp
->d_ino
!= 0 && dp
->d_type
!= DT_WHT
) {
3260 nlen
= dp
->d_namlen
;
3261 rem
= nfsm_rndup(nlen
)-nlen
;
3264 * For readdir_and_lookup get the vnode using
3267 if (VFS_VGET(vp
->v_mount
, dp
->d_ino
, &nvp
))
3269 bzero((caddr_t
)nfhp
, NFSX_V3FH
);
3270 nfhp
->fh_fsid
= fhp
->fh_fsid
;
3271 if (VFS_VPTOFH(nvp
, &nfhp
->fh_fid
)) {
3276 if (VOP_GETATTR(nvp
, vap
)) {
3285 * If either the dircount or maxcount will be
3286 * exceeded, get out now. Both of these lengths
3287 * are calculated conservatively, including all
3290 len
+= (8 * NFSX_UNSIGNED
+ nlen
+ rem
+ NFSX_V3FH
+
3292 dirlen
+= (6 * NFSX_UNSIGNED
+ nlen
+ rem
);
3293 if (len
> cnt
|| dirlen
> fullsiz
) {
3299 * Build the directory record xdr from
3302 fp
= (struct nfs_fattr
*)&fl
.fl_fattr
;
3303 nfsm_srvfillattr(vap
, fp
);
3304 fl
.fl_fhsize
= txdr_unsigned(NFSX_V3FH
);
3305 fl
.fl_fhok
= nfs_true
;
3306 fl
.fl_postopok
= nfs_true
;
3307 fl
.fl_off
.nfsuquad
[0] = txdr_unsigned(*cookiep
>> 32);
3308 fl
.fl_off
.nfsuquad
[1] = txdr_unsigned(*cookiep
);
3310 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3312 bp
+= NFSX_UNSIGNED
;
3313 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3315 bp
+= NFSX_UNSIGNED
;
3316 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3317 *tl
= txdr_unsigned(dp
->d_ino
);
3318 bp
+= NFSX_UNSIGNED
;
3319 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3320 *tl
= txdr_unsigned(nlen
);
3321 bp
+= NFSX_UNSIGNED
;
3323 /* And loop around copying the name */
3327 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3328 if ((bp
+ xfer
) > be
)
3332 bcopy(cp
, bp
, tsiz
);
3338 /* And null pad to a int32_t boundary */
3339 for (i
= 0; i
< rem
; i
++)
3343 * Now copy the flrep structure out.
3345 xfer
= sizeof (struct flrep
);
3348 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3349 if ((bp
+ xfer
) > be
)
3353 bcopy(cp
, bp
, tsiz
);
3361 dp
= _DIRENT_NEXT(dp
);
3368 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3370 bp
+= NFSX_UNSIGNED
;
3371 nfsm_clget(mp1
, mp2
, mb
, bp
, be
, tl
);
3376 bp
+= NFSX_UNSIGNED
;
3379 mp1
->m_len
= bp
- mtod(mp1
, caddr_t
);
3381 mp1
->m_len
+= bp
- bpos
;
3382 FREE((caddr_t
)cookies
, M_TEMP
);
3383 FREE((caddr_t
)rbuf
, M_TEMP
);
3391 * nfs commit service
3394 nfsrv_commit(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3395 struct thread
*td
, struct mbuf
**mrq
)
3397 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3398 struct sockaddr
*nam
= nfsd
->nd_nam
;
3399 caddr_t dpos
= nfsd
->nd_dpos
;
3400 struct ucred
*cred
= &nfsd
->nd_cr
;
3401 struct vattr bfor
, aft
;
3402 struct vnode
*vp
= NULL
;
3403 struct mount
*mp
= NULL
;
3409 int error
= 0, rdonly
, for_ret
= 1, aft_ret
= 1, cnt
;
3411 struct mbuf
*mb
, *mb2
, *mreq
;
3414 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3415 fhp
= &nfh
.fh_generic
;
3417 nfsm_dissect(tl
, u_int32_t
*, 3 * NFSX_UNSIGNED
);
3420 * XXX At this time VOP_FSYNC() does not accept offset and byte
3421 * count parameters, so these arguments are useless (someday maybe).
3423 off
= fxdr_hyper(tl
);
3425 cnt
= fxdr_unsigned(int, *tl
);
3426 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3427 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3429 nfsm_reply(2 * NFSX_UNSIGNED
);
3430 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
3434 for_ret
= VOP_GETATTR(vp
, &bfor
);
3436 if (cnt
> MAX_COMMIT_COUNT
) {
3438 * Give up and do the whole thing
3441 (vp
->v_object
->flags
& OBJ_MIGHTBEDIRTY
)) {
3442 vm_object_page_clean(vp
->v_object
, 0, 0, OBJPC_SYNC
);
3444 error
= VOP_FSYNC(vp
, MNT_WAIT
);
3447 * Locate and synchronously write any buffers that fall
3448 * into the requested range. Note: we are assuming that
3449 * f_iosize is a power of 2.
3451 int iosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
3452 int iomask
= iosize
- 1;
3456 * Align to iosize boundry, super-align to page boundry.
3459 cnt
+= off
& iomask
;
3460 off
&= ~(u_quad_t
)iomask
;
3462 if (off
& PAGE_MASK
) {
3463 cnt
+= off
& PAGE_MASK
;
3464 off
&= ~(u_quad_t
)PAGE_MASK
;
3469 (vp
->v_object
->flags
& OBJ_MIGHTBEDIRTY
)) {
3470 vm_object_page_clean(vp
->v_object
, off
/ PAGE_SIZE
, (cnt
+ PAGE_MASK
) / PAGE_SIZE
, OBJPC_SYNC
);
3478 * If we have a buffer and it is marked B_DELWRI we
3479 * have to lock and write it. Otherwise the prior
3480 * write is assumed to have already been committed.
3482 if ((bp
= findblk(vp
, loffset
)) != NULL
&& (bp
->b_flags
& B_DELWRI
)) {
3483 if (BUF_LOCK(bp
, LK_EXCLUSIVE
| LK_NOWAIT
)) {
3484 if (BUF_LOCK(bp
, LK_EXCLUSIVE
| LK_SLEEPFAIL
) == 0)
3486 continue; /* retry */
3489 bp
->b_flags
&= ~B_ASYNC
;
3502 aft_ret
= VOP_GETATTR(vp
, &aft
);
3505 nfsm_reply(NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
3506 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
3508 nfsm_build(tl
, u_int32_t
*, NFSX_V3WRITEVERF
);
3509 if (nfsver
.tv_sec
== 0)
3511 *tl
++ = txdr_unsigned(nfsver
.tv_sec
);
3512 *tl
= txdr_unsigned(nfsver
.tv_nsec
/ 1000);
3523 * nfs statfs service
3526 nfsrv_statfs(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3527 struct thread
*td
, struct mbuf
**mrq
)
3529 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3530 struct sockaddr
*nam
= nfsd
->nd_nam
;
3531 caddr_t dpos
= nfsd
->nd_dpos
;
3532 struct ucred
*cred
= &nfsd
->nd_cr
;
3534 struct nfs_statfs
*sfp
;
3538 int error
= 0, rdonly
, getret
= 1;
3539 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3541 struct mbuf
*mb
, *mb2
, *mreq
;
3542 struct vnode
*vp
= NULL
;
3543 struct mount
*mp
= NULL
;
3547 struct statfs statfs
;
3550 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3551 fhp
= &nfh
.fh_generic
;
3553 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3554 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3556 nfsm_reply(NFSX_UNSIGNED
);
3557 nfsm_srvpostop_attr(getret
, &at
);
3562 error
= VFS_STATFS(vp
->v_mount
, sf
, proc0
.p_ucred
);
3563 getret
= VOP_GETATTR(vp
, &at
);
3566 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_STATFS(v3
));
3568 nfsm_srvpostop_attr(getret
, &at
);
3573 nfsm_build(sfp
, struct nfs_statfs
*, NFSX_STATFS(v3
));
3575 tval
= (u_quad_t
)sf
->f_blocks
;
3576 tval
*= (u_quad_t
)sf
->f_bsize
;
3577 txdr_hyper(tval
, &sfp
->sf_tbytes
);
3578 tval
= (u_quad_t
)sf
->f_bfree
;
3579 tval
*= (u_quad_t
)sf
->f_bsize
;
3580 txdr_hyper(tval
, &sfp
->sf_fbytes
);
3581 tval
= (u_quad_t
)sf
->f_bavail
;
3582 tval
*= (u_quad_t
)sf
->f_bsize
;
3583 txdr_hyper(tval
, &sfp
->sf_abytes
);
3584 sfp
->sf_tfiles
.nfsuquad
[0] = 0;
3585 sfp
->sf_tfiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_files
);
3586 sfp
->sf_ffiles
.nfsuquad
[0] = 0;
3587 sfp
->sf_ffiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3588 sfp
->sf_afiles
.nfsuquad
[0] = 0;
3589 sfp
->sf_afiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3590 sfp
->sf_invarsec
= 0;
3592 sfp
->sf_tsize
= txdr_unsigned(NFS_MAXDGRAMDATA
);
3593 sfp
->sf_bsize
= txdr_unsigned(sf
->f_bsize
);
3594 sfp
->sf_blocks
= txdr_unsigned(sf
->f_blocks
);
3595 sfp
->sf_bfree
= txdr_unsigned(sf
->f_bfree
);
3596 sfp
->sf_bavail
= txdr_unsigned(sf
->f_bavail
);
3605 * nfs fsinfo service
3608 nfsrv_fsinfo(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3609 struct thread
*td
, struct mbuf
**mrq
)
3611 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3612 struct sockaddr
*nam
= nfsd
->nd_nam
;
3613 caddr_t dpos
= nfsd
->nd_dpos
;
3614 struct ucred
*cred
= &nfsd
->nd_cr
;
3616 struct nfsv3_fsinfo
*sip
;
3619 int error
= 0, rdonly
, getret
= 1, pref
;
3621 struct mbuf
*mb
, *mb2
, *mreq
;
3622 struct vnode
*vp
= NULL
;
3623 struct mount
*mp
= NULL
;
3630 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3631 fhp
= &nfh
.fh_generic
;
3633 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3634 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3636 nfsm_reply(NFSX_UNSIGNED
);
3637 nfsm_srvpostop_attr(getret
, &at
);
3642 /* XXX Try to make a guess on the max file size. */
3643 VFS_STATFS(vp
->v_mount
, &sb
, proc0
.p_ucred
);
3644 maxfsize
= (u_quad_t
)0x80000000 * sb
.f_bsize
- 1;
3646 getret
= VOP_GETATTR(vp
, &at
);
3649 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
3650 nfsm_srvpostop_attr(getret
, &at
);
3651 nfsm_build(sip
, struct nfsv3_fsinfo
*, NFSX_V3FSINFO
);
3655 * There should be file system VFS OP(s) to get this information.
3656 * For now, assume ufs.
3658 if (slp
->ns_so
->so_type
== SOCK_DGRAM
)
3659 pref
= NFS_MAXDGRAMDATA
;
3662 sip
->fs_rtmax
= txdr_unsigned(NFS_MAXDATA
);
3663 sip
->fs_rtpref
= txdr_unsigned(pref
);
3664 sip
->fs_rtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3665 sip
->fs_wtmax
= txdr_unsigned(NFS_MAXDATA
);
3666 sip
->fs_wtpref
= txdr_unsigned(pref
);
3667 sip
->fs_wtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3668 sip
->fs_dtpref
= txdr_unsigned(pref
);
3669 txdr_hyper(maxfsize
, &sip
->fs_maxfilesize
);
3670 sip
->fs_timedelta
.nfsv3_sec
= 0;
3671 sip
->fs_timedelta
.nfsv3_nsec
= txdr_unsigned(1);
3672 sip
->fs_properties
= txdr_unsigned(NFSV3FSINFO_LINK
|
3673 NFSV3FSINFO_SYMLINK
| NFSV3FSINFO_HOMOGENEOUS
|
3674 NFSV3FSINFO_CANSETTIME
);
3682 * nfs pathconf service
3685 nfsrv_pathconf(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3686 struct thread
*td
, struct mbuf
**mrq
)
3688 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3689 struct sockaddr
*nam
= nfsd
->nd_nam
;
3690 caddr_t dpos
= nfsd
->nd_dpos
;
3691 struct ucred
*cred
= &nfsd
->nd_cr
;
3693 struct nfsv3_pathconf
*pc
;
3696 int error
= 0, rdonly
, getret
= 1;
3697 register_t linkmax
, namemax
, chownres
, notrunc
;
3699 struct mbuf
*mb
, *mb2
, *mreq
;
3700 struct vnode
*vp
= NULL
;
3701 struct mount
*mp
= NULL
;
3706 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3707 fhp
= &nfh
.fh_generic
;
3709 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3710 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3712 nfsm_reply(NFSX_UNSIGNED
);
3713 nfsm_srvpostop_attr(getret
, &at
);
3717 error
= VOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
);
3719 error
= VOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
);
3721 error
= VOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
);
3723 error
= VOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
);
3724 getret
= VOP_GETATTR(vp
, &at
);
3727 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
3728 nfsm_srvpostop_attr(getret
, &at
);
3733 nfsm_build(pc
, struct nfsv3_pathconf
*, NFSX_V3PATHCONF
);
3735 pc
->pc_linkmax
= txdr_unsigned(linkmax
);
3736 pc
->pc_namemax
= txdr_unsigned(namemax
);
3737 pc
->pc_notrunc
= txdr_unsigned(notrunc
);
3738 pc
->pc_chownrestricted
= txdr_unsigned(chownres
);
3741 * These should probably be supported by VOP_PATHCONF(), but
3742 * until msdosfs is exportable (why would you want to?), the
3743 * Unix defaults should be ok.
3745 pc
->pc_caseinsensitive
= nfs_false
;
3746 pc
->pc_casepreserving
= nfs_true
;
3754 * Null operation, used by clients to ping server
3758 nfsrv_null(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3759 struct thread
*td
, struct mbuf
**mrq
)
3761 struct mbuf
*mrep
= nfsd
->nd_mrep
;
3763 int error
= NFSERR_RETVOID
;
3764 struct mbuf
*mb
, *mreq
;
3766 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3772 * No operation, used for obsolete procedures
3776 nfsrv_noop(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3777 struct thread
*td
, struct mbuf
**mrq
)
3779 struct mbuf
*mrep
= nfsd
->nd_mrep
;
3782 struct mbuf
*mb
, *mreq
;
3784 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3785 if (nfsd
->nd_repstat
)
3786 error
= nfsd
->nd_repstat
;
3788 error
= EPROCUNAVAIL
;
3795 * Perform access checking for vnodes obtained from file handles that would
3796 * refer to files already opened by a Unix client. You cannot just use
3797 * vn_writechk() and VOP_ACCESS() for two reasons.
3798 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3799 * 2 - The owner is to be given access irrespective of mode bits for some
3800 * operations, so that processes that chmod after opening a file don't
3801 * break. I don't like this because it opens a security hole, but since
3802 * the nfs server opens a security hole the size of a barn door anyhow,
3805 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
3806 * will return EPERM instead of EACCESS. EPERM is always an error.
3809 nfsrv_access(struct mount
*mp
, struct vnode
*vp
, int flags
, struct ucred
*cred
,
3810 int rdonly
, struct thread
*td
, int override
)
3815 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3816 if (flags
& VWRITE
) {
3817 /* Just vn_writechk() changed to check rdonly */
3819 * Disallow write attempts on read-only file systems;
3820 * unless the file is a socket or a block or character
3821 * device resident on the file system.
3824 ((mp
->mnt_flag
| vp
->v_mount
->mnt_flag
) & MNT_RDONLY
)) {
3825 switch (vp
->v_type
) {
3835 * If there's shared text associated with
3836 * the inode, we can't allow writing.
3838 if (vp
->v_flag
& VTEXT
)
3841 error
= VOP_GETATTR(vp
, &vattr
);
3844 error
= VOP_ACCESS(vp
, flags
, cred
);
3846 * Allow certain operations for the owner (reads and writes
3847 * on files that are already open).
3849 if (override
&& error
== EACCES
&& cred
->cr_uid
== vattr
.va_uid
)
3853 #endif /* NFS_NOSERVER */