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.48 2008/09/17 21:44:24 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>
70 #include <sys/nlookup.h>
71 #include <sys/namei.h>
72 #include <sys/unistd.h>
73 #include <sys/vnode.h>
74 #include <sys/mount.h>
75 #include <sys/socket.h>
76 #include <sys/socketvar.h>
77 #include <sys/malloc.h>
79 #include <sys/dirent.h>
81 #include <sys/kernel.h>
82 #include <sys/sysctl.h>
86 #include <vm/vm_extern.h>
87 #include <vm/vm_zone.h>
88 #include <vm/vm_object.h>
92 #include <sys/thread2.h>
98 #include "nfsm_subs.h"
101 #define nfsdbprintf(info) kprintf info
103 #define nfsdbprintf(info)
106 #define MAX_COMMIT_COUNT (1024 * 1024)
108 #define NUM_HEURISTIC 1017
109 #define NHUSE_INIT 64
111 #define NHUSE_MAX 2048
113 static struct nfsheur
{
114 struct vnode
*nh_vp
; /* vp to match (unreferenced pointer) */
115 off_t nh_nextr
; /* next offset for sequential detection */
116 int nh_use
; /* use count for selection */
117 int nh_seqcount
; /* heuristic */
118 } nfsheur
[NUM_HEURISTIC
];
120 nfstype nfsv3_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFSOCK
,
123 nfstype nfsv2_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFNON
,
126 int nfsrvw_procrastinate
= NFS_GATHERDELAY
* 1000;
127 int nfsrvw_procrastinate_v3
= 0;
129 static struct timespec nfsver
;
131 SYSCTL_DECL(_vfs_nfs
);
134 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, async
, CTLFLAG_RW
, &nfs_async
, 0, "");
135 static int nfs_commit_blks
;
136 static int nfs_commit_miss
;
137 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, commit_blks
, CTLFLAG_RW
, &nfs_commit_blks
, 0, "");
138 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, commit_miss
, CTLFLAG_RW
, &nfs_commit_miss
, 0, "");
140 static int nfsrv_access (struct mount
*, struct vnode
*, int,
141 struct ucred
*, int, struct thread
*, int);
142 static void nfsrvw_coalesce (struct nfsrv_descript
*,
143 struct nfsrv_descript
*);
146 * nfs v3 access service
149 nfsrv3_access(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
150 struct thread
*td
, struct mbuf
**mrq
)
152 struct sockaddr
*nam
= nfsd
->nd_nam
;
153 struct ucred
*cred
= &nfsd
->nd_cr
;
154 struct vnode
*vp
= NULL
;
155 struct mount
*mp
= NULL
;
158 int error
= 0, rdonly
, getret
;
159 struct vattr vattr
, *vap
= &vattr
;
160 u_long testmode
, nfsmode
;
161 struct nfsm_info info
;
164 info
.dpos
= nfsd
->nd_dpos
;
165 info
.md
= nfsd
->nd_md
;
166 info
.mrep
= nfsd
->nd_mrep
;
169 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
170 fhp
= &nfh
.fh_generic
;
171 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
172 NULLOUT(tl
= nfsm_dissect(&info
, NFSX_UNSIGNED
));
173 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
, &rdonly
,
174 (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
176 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_UNSIGNED
, &error
));
177 nfsm_srvpostop_attr(&info
, nfsd
, 1, NULL
);
181 nfsmode
= fxdr_unsigned(u_int32_t
, *tl
);
182 if ((nfsmode
& NFSV3ACCESS_READ
) &&
183 nfsrv_access(mp
, vp
, VREAD
, cred
, rdonly
, td
, 0))
184 nfsmode
&= ~NFSV3ACCESS_READ
;
185 if (vp
->v_type
== VDIR
)
186 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
|
189 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
);
190 if ((nfsmode
& testmode
) &&
191 nfsrv_access(mp
, vp
, VWRITE
, cred
, rdonly
, td
, 0))
192 nfsmode
&= ~testmode
;
193 if (vp
->v_type
== VDIR
)
194 testmode
= NFSV3ACCESS_LOOKUP
;
196 testmode
= NFSV3ACCESS_EXECUTE
;
197 if ((nfsmode
& testmode
) &&
198 nfsrv_access(mp
, vp
, VEXEC
, cred
, rdonly
, td
, 0))
199 nfsmode
&= ~testmode
;
200 getret
= VOP_GETATTR(vp
, vap
);
203 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
204 NFSX_POSTOPATTR(1) + NFSX_UNSIGNED
, &error
));
205 nfsm_srvpostop_attr(&info
, nfsd
, getret
, vap
);
206 tl
= nfsm_build(&info
, NFSX_UNSIGNED
);
207 *tl
= txdr_unsigned(nfsmode
);
216 * nfs getattr service
219 nfsrv_getattr(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
220 struct thread
*td
, struct mbuf
**mrq
)
222 struct sockaddr
*nam
= nfsd
->nd_nam
;
223 struct ucred
*cred
= &nfsd
->nd_cr
;
224 struct nfs_fattr
*fp
;
226 struct vattr
*vap
= &va
;
227 struct vnode
*vp
= NULL
;
228 struct mount
*mp
= NULL
;
231 int error
= 0, rdonly
;
232 struct nfsm_info info
;
234 info
.mrep
= nfsd
->nd_mrep
;
235 info
.md
= nfsd
->nd_md
;
236 info
.dpos
= nfsd
->nd_dpos
;
239 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
240 fhp
= &nfh
.fh_generic
;
241 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
242 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
243 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
245 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, 0, &error
));
249 error
= VOP_GETATTR(vp
, vap
);
252 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
253 NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
), &error
));
258 fp
= nfsm_build(&info
, NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
259 nfsm_srvfattr(nfsd
, vap
, fp
);
270 * nfs setattr service
273 nfsrv_setattr(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
274 struct thread
*td
, struct mbuf
**mrq
)
276 struct sockaddr
*nam
= nfsd
->nd_nam
;
277 struct ucred
*cred
= &nfsd
->nd_cr
;
278 struct vattr va
, preat
;
279 struct vattr
*vap
= &va
;
280 struct nfsv2_sattr
*sp
;
281 struct nfs_fattr
*fp
;
282 struct vnode
*vp
= NULL
;
283 struct mount
*mp
= NULL
;
287 int error
= 0, rdonly
, preat_ret
= 1, postat_ret
= 1;
289 struct timespec guard
;
290 struct nfsm_info info
;
292 info
.mrep
= nfsd
->nd_mrep
;
294 info
.md
= nfsd
->nd_md
;
295 info
.dpos
= nfsd
->nd_dpos
;
296 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
298 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
299 fhp
= &nfh
.fh_generic
;
300 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
303 ERROROUT(nfsm_srvsattr(&info
, vap
));
304 NULLOUT(tl
= nfsm_dissect(&info
, NFSX_UNSIGNED
));
305 gcheck
= fxdr_unsigned(int, *tl
);
307 NULLOUT(tl
= nfsm_dissect(&info
, 2 * NFSX_UNSIGNED
));
308 fxdr_nfsv3time(tl
, &guard
);
311 NULLOUT(sp
= nfsm_dissect(&info
, 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 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
348 2 * NFSX_UNSIGNED
, &error
));
349 nfsm_srvwcc_data(&info
, nfsd
, preat_ret
, &preat
,
356 * vp now an active resource, pay careful attention to cleanup
360 error
= preat_ret
= VOP_GETATTR(vp
, &preat
);
361 if (!error
&& gcheck
&&
362 (preat
.va_ctime
.tv_sec
!= guard
.tv_sec
||
363 preat
.va_ctime
.tv_nsec
!= guard
.tv_nsec
))
364 error
= NFSERR_NOT_SYNC
;
368 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
369 NFSX_WCCDATA(info
.v3
), &error
));
370 nfsm_srvwcc_data(&info
, nfsd
, preat_ret
, &preat
,
378 * If the size is being changed write acces is required, otherwise
379 * just check for a read only file system.
381 if (vap
->va_size
== ((u_quad_t
)((quad_t
) -1))) {
382 if (rdonly
|| (mp
->mnt_flag
& MNT_RDONLY
)) {
387 if (vp
->v_type
== VDIR
) {
390 } else if ((error
= nfsrv_access(mp
, vp
, VWRITE
, cred
, rdonly
,
395 error
= VOP_SETATTR(vp
, vap
, cred
);
396 postat_ret
= VOP_GETATTR(vp
, vap
);
402 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
403 NFSX_WCCORFATTR(info
.v3
), &error
));
405 nfsm_srvwcc_data(&info
, nfsd
, preat_ret
, &preat
,
410 fp
= nfsm_build(&info
, NFSX_V2FATTR
);
411 nfsm_srvfattr(nfsd
, vap
, fp
);
426 nfsrv_lookup(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
427 struct thread
*td
, struct mbuf
**mrq
)
429 struct sockaddr
*nam
= nfsd
->nd_nam
;
430 struct ucred
*cred
= &nfsd
->nd_cr
;
431 struct nfs_fattr
*fp
;
432 struct nlookupdata nd
;
438 int error
= 0, len
, dirattr_ret
= 1;
440 struct vattr va
, dirattr
, *vap
= &va
;
441 struct nfsm_info info
;
443 info
.mrep
= nfsd
->nd_mrep
;
445 info
.md
= nfsd
->nd_md
;
446 info
.dpos
= nfsd
->nd_dpos
;
447 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
449 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
454 fhp
= &nfh
.fh_generic
;
455 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
456 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
458 pubflag
= nfs_ispublicfh(fhp
);
460 error
= nfs_namei(&nd
, cred
, 0, NULL
, &vp
,
461 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
,
462 &dirp
, td
, (nfsd
->nd_flag
& ND_KERBAUTH
), pubflag
);
465 * namei failure, only dirp to cleanup. Clear out garbarge from
466 * structure in case macros jump to nfsmout.
472 dirattr_ret
= VOP_GETATTR(dirp
, &dirattr
);
476 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
477 NFSX_POSTOPATTR(info
.v3
), &error
));
478 nfsm_srvpostop_attr(&info
, nfsd
, dirattr_ret
, &dirattr
);
484 * Locate index file for public filehandle
486 * error is 0 on entry and 0 on exit from this block.
490 if (vp
->v_type
== VDIR
&& nfs_pub
.np_index
!= NULL
) {
492 * Setup call to lookup() to see if we can find
493 * the index file. Arguably, this doesn't belong
494 * in a kernel.. Ugh. If an error occurs, do not
495 * try to install an index file and then clear the
498 * When we replace nd with ind and redirect ndp,
499 * maintenance of ni_startdir and ni_vp shift to
500 * ind and we have to clean them up in the old nd.
501 * However, the cnd resource continues to be maintained
502 * via the original nd. Confused? You aren't alone!
505 cache_copy(&nd
.nl_nch
, &nch
);
507 error
= nlookup_init_raw(&nd
, nfs_pub
.np_index
,
508 UIO_SYSSPACE
, 0, cred
, &nch
);
511 error
= nlookup(&nd
);
515 * Found an index file. Get rid of
516 * the old references. transfer vp and
517 * load up the new vp. Fortunately we do
518 * not have to deal with dvp, that would be
525 error
= cache_vget(&nd
.nl_nch
, nd
.nl_cred
,
527 KKASSERT(error
== 0);
532 * If the public filehandle was used, check that this lookup
533 * didn't result in a filehandle outside the publicly exported
534 * filesystem. We clear the poor vp here to avoid lockups due
538 if (vp
->v_mount
!= nfs_pub
.np_mount
) {
547 dirattr_ret
= VOP_GETATTR(dirp
, &dirattr
);
553 * Resources at this point:
554 * ndp->ni_vp may not be NULL
559 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
560 NFSX_POSTOPATTR(info
.v3
), &error
));
561 nfsm_srvpostop_attr(&info
, nfsd
, dirattr_ret
, &dirattr
);
567 * Clear out some resources prior to potentially blocking. This
568 * is not as critical as ni_dvp resources in other routines, but
574 * Get underlying attribute, then release remaining resources ( for
575 * the same potential blocking reason ) and reply.
577 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
578 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
580 error
= VOP_GETATTR(vp
, vap
);
584 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
585 NFSX_SRVFH(info
.v3
) +
586 NFSX_POSTOPORFATTR(info
.v3
) +
587 NFSX_POSTOPATTR(info
.v3
),
590 nfsm_srvpostop_attr(&info
, nfsd
, dirattr_ret
, &dirattr
);
594 nfsm_srvfhtom(&info
, fhp
);
596 nfsm_srvpostop_attr(&info
, nfsd
, 0, vap
);
597 nfsm_srvpostop_attr(&info
, nfsd
, dirattr_ret
, &dirattr
);
599 fp
= nfsm_build(&info
, NFSX_V2FATTR
);
600 nfsm_srvfattr(nfsd
, vap
, fp
);
607 nlookup_done(&nd
); /* may be called twice */
614 * nfs readlink service
617 nfsrv_readlink(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
618 struct thread
*td
, struct mbuf
**mrq
)
620 struct sockaddr
*nam
= nfsd
->nd_nam
;
621 struct ucred
*cred
= &nfsd
->nd_cr
;
622 struct iovec iv
[(NFS_MAXPATHLEN
+MLEN
-1)/MLEN
];
623 struct iovec
*ivp
= iv
;
625 int error
= 0, rdonly
, i
, tlen
, len
, getret
;
626 struct mbuf
*mp1
, *mp2
, *mp3
;
627 struct vnode
*vp
= NULL
;
628 struct mount
*mp
= NULL
;
632 struct uio io
, *uiop
= &io
;
633 struct nfsm_info info
;
635 info
.mrep
= nfsd
->nd_mrep
;
637 info
.md
= nfsd
->nd_md
;
638 info
.dpos
= nfsd
->nd_dpos
;
639 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
641 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
646 fhp
= &nfh
.fh_generic
;
647 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
650 while (len
< NFS_MAXPATHLEN
) {
651 mp1
= m_getcl(MB_WAIT
, MT_DATA
, 0);
652 mp1
->m_len
= MCLBYTES
;
659 if ((len
+ mp1
->m_len
) > NFS_MAXPATHLEN
) {
660 mp1
->m_len
= NFS_MAXPATHLEN
-len
;
661 len
= NFS_MAXPATHLEN
;
664 ivp
->iov_base
= mtod(mp1
, caddr_t
);
665 ivp
->iov_len
= mp1
->m_len
;
670 uiop
->uio_iovcnt
= i
;
671 uiop
->uio_offset
= 0;
672 uiop
->uio_resid
= len
;
673 uiop
->uio_rw
= UIO_READ
;
674 uiop
->uio_segflg
= UIO_SYSSPACE
;
676 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
677 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
679 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
680 2 * NFSX_UNSIGNED
, &error
));
681 nfsm_srvpostop_attr(&info
, nfsd
, 1, NULL
);
685 if (vp
->v_type
!= VLNK
) {
692 error
= VOP_READLINK(vp
, uiop
, cred
);
694 getret
= VOP_GETATTR(vp
, &attr
);
697 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
698 NFSX_POSTOPATTR(info
.v3
) + NFSX_UNSIGNED
,
701 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &attr
);
707 if (uiop
->uio_resid
> 0) {
708 len
-= uiop
->uio_resid
;
709 tlen
= nfsm_rndup(len
);
710 nfsm_adj(mp3
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
712 tl
= nfsm_build(&info
, NFSX_UNSIGNED
);
713 *tl
= txdr_unsigned(len
);
714 info
.mb
->m_next
= mp3
;
729 nfsrv_read(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
730 struct thread
*td
, struct mbuf
**mrq
)
732 struct nfsm_info info
;
733 struct sockaddr
*nam
= nfsd
->nd_nam
;
734 struct ucred
*cred
= &nfsd
->nd_cr
;
738 struct nfs_fattr
*fp
;
742 int error
= 0, rdonly
, cnt
, len
, left
, siz
, tlen
, getret
;
744 struct vnode
*vp
= NULL
;
745 struct mount
*mp
= NULL
;
748 struct uio io
, *uiop
= &io
;
749 struct vattr va
, *vap
= &va
;
754 info
.mrep
= nfsd
->nd_mrep
;
756 info
.md
= nfsd
->nd_md
;
757 info
.dpos
= nfsd
->nd_dpos
;
758 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
760 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
761 fhp
= &nfh
.fh_generic
;
762 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
764 NULLOUT(tl
= nfsm_dissect(&info
, 2 * NFSX_UNSIGNED
));
765 off
= fxdr_hyper(tl
);
767 NULLOUT(tl
= nfsm_dissect(&info
, NFSX_UNSIGNED
));
768 off
= (off_t
)fxdr_unsigned(u_int32_t
, *tl
);
770 NEGREPLYOUT(reqlen
= nfsm_srvstrsiz(&info
,
771 NFS_SRVMAXDATA(nfsd
), &error
));
774 * Reference vp. If an error occurs, vp will be invalid, but we
775 * have to NULL it just in case. The macros might goto nfsmout
779 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
780 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
783 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
784 2 * NFSX_UNSIGNED
, &error
));
785 nfsm_srvpostop_attr(&info
, nfsd
, 1, NULL
);
790 if (vp
->v_type
!= VREG
) {
794 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
797 if ((error
= nfsrv_access(mp
, vp
, VREAD
, cred
, rdonly
, td
, 1)) != 0)
798 error
= nfsrv_access(mp
, vp
, VEXEC
, cred
, rdonly
, td
, 1);
800 getret
= VOP_GETATTR(vp
, vap
);
806 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
807 NFSX_POSTOPATTR(info
.v3
), &error
));
808 nfsm_srvpostop_attr(&info
, nfsd
, getret
, vap
);
814 * Calculate byte count to read
817 if (off
>= vap
->va_size
)
819 else if ((off
+ reqlen
) > vap
->va_size
)
820 cnt
= vap
->va_size
- off
;
825 * Calculate seqcount for heuristic
833 * Locate best candidate
836 hi
= ((int)(vm_offset_t
)vp
/ sizeof(struct vnode
)) % NUM_HEURISTIC
;
840 if (nfsheur
[hi
].nh_vp
== vp
) {
844 if (nfsheur
[hi
].nh_use
> 0)
845 --nfsheur
[hi
].nh_use
;
846 hi
= (hi
+ 1) % NUM_HEURISTIC
;
847 if (nfsheur
[hi
].nh_use
< nh
->nh_use
)
851 if (nh
->nh_vp
!= vp
) {
854 nh
->nh_use
= NHUSE_INIT
;
862 * Calculate heuristic
865 if ((off
== 0 && nh
->nh_seqcount
> 0) || off
== nh
->nh_nextr
) {
866 if (++nh
->nh_seqcount
> IO_SEQMAX
)
867 nh
->nh_seqcount
= IO_SEQMAX
;
868 } else if (nh
->nh_seqcount
> 1) {
873 nh
->nh_use
+= NHUSE_INC
;
874 if (nh
->nh_use
> NHUSE_MAX
)
875 nh
->nh_use
= NHUSE_MAX
;
876 ioflag
|= nh
->nh_seqcount
<< IO_SEQSHIFT
;
879 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
880 NFSX_POSTOPORFATTR(info
.v3
) +
881 3 * NFSX_UNSIGNED
+ nfsm_rndup(cnt
),
884 tl
= nfsm_build(&info
, NFSX_V3FATTR
+ 4 * NFSX_UNSIGNED
);
886 fp
= (struct nfs_fattr
*)tl
;
887 tl
+= (NFSX_V3FATTR
/ sizeof (u_int32_t
));
889 tl
= nfsm_build(&info
, NFSX_V2FATTR
+ NFSX_UNSIGNED
);
890 fp
= (struct nfs_fattr
*)tl
;
891 tl
+= (NFSX_V2FATTR
/ sizeof (u_int32_t
));
893 len
= left
= nfsm_rndup(cnt
);
896 * Generate the mbuf list with the uio_iov ref. to it.
901 siz
= min(M_TRAILINGSPACE(m
), left
);
907 m
= m_getcl(MB_WAIT
, MT_DATA
, 0);
913 MALLOC(iv
, struct iovec
*, i
* sizeof (struct iovec
),
915 uiop
->uio_iov
= iv2
= iv
;
921 panic("nfsrv_read iov");
922 siz
= min(M_TRAILINGSPACE(m
), left
);
924 iv
->iov_base
= mtod(m
, caddr_t
) + m
->m_len
;
933 uiop
->uio_iovcnt
= i
;
934 uiop
->uio_offset
= off
;
935 uiop
->uio_resid
= len
;
936 uiop
->uio_rw
= UIO_READ
;
937 uiop
->uio_segflg
= UIO_SYSSPACE
;
938 error
= VOP_READ(vp
, uiop
, IO_NODELOCKED
| ioflag
, cred
);
939 off
= uiop
->uio_offset
;
941 FREE((caddr_t
)iv2
, M_TEMP
);
942 if (error
|| (getret
= VOP_GETATTR(vp
, vap
))) {
949 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
950 NFSX_POSTOPATTR(info
.v3
),
952 nfsm_srvpostop_attr(&info
, nfsd
, getret
, vap
);
961 nfsm_srvfattr(nfsd
, vap
, fp
);
962 tlen
= len
- uiop
->uio_resid
;
963 cnt
= cnt
< tlen
? cnt
: tlen
;
964 tlen
= nfsm_rndup(cnt
);
965 if (len
!= tlen
|| tlen
!= cnt
)
966 nfsm_adj(info
.mb
, len
- tlen
, tlen
- cnt
);
968 *tl
++ = txdr_unsigned(cnt
);
974 *tl
= txdr_unsigned(cnt
);
986 nfsrv_write(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
987 struct thread
*td
, struct mbuf
**mrq
)
989 struct sockaddr
*nam
= nfsd
->nd_nam
;
990 struct ucred
*cred
= &nfsd
->nd_cr
;
994 struct nfs_fattr
*fp
;
996 struct vattr va
, forat
;
997 struct vattr
*vap
= &va
;
999 int error
= 0, rdonly
, len
, forat_ret
= 1;
1000 int ioflags
, aftat_ret
= 1, retlen
, zeroing
, adjust
;
1001 int stable
= NFSV3WRITE_FILESYNC
;
1002 struct vnode
*vp
= NULL
;
1003 struct mount
*mp
= NULL
;
1006 struct uio io
, *uiop
= &io
;
1007 struct nfsm_info info
;
1010 info
.mrep
= nfsd
->nd_mrep
;
1012 info
.md
= nfsd
->nd_md
;
1013 info
.dpos
= nfsd
->nd_dpos
;
1014 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1016 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
1017 if (info
.mrep
== NULL
) {
1021 fhp
= &nfh
.fh_generic
;
1022 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
1024 NULLOUT(tl
= nfsm_dissect(&info
, 5 * NFSX_UNSIGNED
));
1025 off
= fxdr_hyper(tl
);
1027 stable
= fxdr_unsigned(int, *tl
++);
1029 NULLOUT(tl
= nfsm_dissect(&info
, 4 * NFSX_UNSIGNED
));
1030 off
= (off_t
)fxdr_unsigned(u_int32_t
, *++tl
);
1033 stable
= NFSV3WRITE_UNSTABLE
;
1035 retlen
= len
= fxdr_unsigned(int32_t, *tl
);
1039 * For NFS Version 2, it is not obvious what a write of zero length
1040 * should do, but I might as well be consistent with Version 3,
1041 * which is to return ok so long as there are no permission problems.
1047 if (mp1
== info
.md
) {
1049 adjust
= info
.dpos
- mtod(mp1
, caddr_t
);
1050 mp1
->m_len
-= adjust
;
1051 if (mp1
->m_len
> 0 && adjust
> 0)
1052 mp1
->m_data
+= adjust
;
1056 else if (mp1
->m_len
> 0) {
1059 mp1
->m_len
-= (i
- len
);
1068 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1070 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1071 2 * NFSX_UNSIGNED
, &error
));
1072 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1077 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
1078 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
1081 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1082 2 * NFSX_UNSIGNED
, &error
));
1083 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1089 forat_ret
= VOP_GETATTR(vp
, &forat
);
1090 if (vp
->v_type
!= VREG
) {
1094 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
1097 error
= nfsrv_access(mp
, vp
, VWRITE
, cred
, rdonly
, td
, 1);
1102 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1103 NFSX_WCCDATA(info
.v3
), &error
));
1104 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1111 MALLOC(ivp
, struct iovec
*, cnt
* sizeof (struct iovec
), M_TEMP
,
1113 uiop
->uio_iov
= iv
= ivp
;
1114 uiop
->uio_iovcnt
= cnt
;
1117 if (mp1
->m_len
> 0) {
1118 ivp
->iov_base
= mtod(mp1
, caddr_t
);
1119 ivp
->iov_len
= mp1
->m_len
;
1127 * The IO_METASYNC flag indicates that all metadata (and not just
1128 * enough to ensure data integrity) mus be written to stable storage
1130 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1132 if (stable
== NFSV3WRITE_UNSTABLE
)
1133 ioflags
= IO_NODELOCKED
;
1134 else if (stable
== NFSV3WRITE_DATASYNC
)
1135 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1137 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1138 uiop
->uio_resid
= len
;
1139 uiop
->uio_rw
= UIO_WRITE
;
1140 uiop
->uio_segflg
= UIO_SYSSPACE
;
1141 uiop
->uio_td
= NULL
;
1142 uiop
->uio_offset
= off
;
1143 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
1144 nfsstats
.srvvop_writes
++;
1145 FREE((caddr_t
)iv
, M_TEMP
);
1147 aftat_ret
= VOP_GETATTR(vp
, vap
);
1152 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1153 NFSX_PREOPATTR(info
.v3
) +
1154 NFSX_POSTOPORFATTR(info
.v3
) +
1155 2 * NFSX_UNSIGNED
+ NFSX_WRITEVERF(info
.v3
),
1158 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1164 tl
= nfsm_build(&info
, 4 * NFSX_UNSIGNED
);
1165 *tl
++ = txdr_unsigned(retlen
);
1167 * If nfs_async is set, then pretend the write was FILESYNC.
1169 if (stable
== NFSV3WRITE_UNSTABLE
&& !nfs_async
)
1170 *tl
++ = txdr_unsigned(stable
);
1172 *tl
++ = txdr_unsigned(NFSV3WRITE_FILESYNC
);
1174 * Actually, there is no need to txdr these fields,
1175 * but it may make the values more human readable,
1176 * for debugging purposes.
1178 if (nfsver
.tv_sec
== 0)
1180 *tl
++ = txdr_unsigned(nfsver
.tv_sec
);
1181 *tl
= txdr_unsigned(nfsver
.tv_nsec
/ 1000);
1183 fp
= nfsm_build(&info
, NFSX_V2FATTR
);
1184 nfsm_srvfattr(nfsd
, vap
, fp
);
1194 * NFS write service with write gathering support. Called when
1195 * nfsrvw_procrastinate > 0.
1196 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1197 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1201 nfsrv_writegather(struct nfsrv_descript
**ndp
, struct nfssvc_sock
*slp
,
1202 struct thread
*td
, struct mbuf
**mrq
)
1205 struct nfsrv_descript
*wp
, *nfsd
, *owp
, *swp
;
1206 struct nfs_fattr
*fp
;
1209 struct nfsrvw_delayhash
*wpp
;
1211 struct vattr va
, forat
;
1213 int error
= 0, rdonly
, len
, forat_ret
= 1;
1214 int ioflags
, aftat_ret
= 1, adjust
, zeroing
;
1216 struct vnode
*vp
= NULL
;
1217 struct mount
*mp
= NULL
;
1218 struct uio io
, *uiop
= &io
;
1220 struct nfsm_info info
;
1224 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
1233 info
.mrep
= nfsd
->nd_mrep
;
1235 info
.md
= nfsd
->nd_md
;
1236 info
.dpos
= nfsd
->nd_dpos
;
1237 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1238 cred
= &nfsd
->nd_cr
;
1239 LIST_INIT(&nfsd
->nd_coalesce
);
1240 nfsd
->nd_mreq
= NULL
;
1241 nfsd
->nd_stable
= NFSV3WRITE_FILESYNC
;
1242 cur_usec
= nfs_curusec();
1243 nfsd
->nd_time
= cur_usec
+
1244 (info
.v3
? nfsrvw_procrastinate_v3
: nfsrvw_procrastinate
);
1247 * Now, get the write header..
1249 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, &nfsd
->nd_fh
, &error
));
1251 NULLOUT(tl
= nfsm_dissect(&info
, 5 * NFSX_UNSIGNED
));
1252 nfsd
->nd_off
= fxdr_hyper(tl
);
1254 nfsd
->nd_stable
= fxdr_unsigned(int, *tl
++);
1256 NULLOUT(tl
= nfsm_dissect(&info
, 4 * NFSX_UNSIGNED
));
1257 nfsd
->nd_off
= (off_t
)fxdr_unsigned(u_int32_t
, *++tl
);
1260 nfsd
->nd_stable
= NFSV3WRITE_UNSTABLE
;
1262 len
= fxdr_unsigned(int32_t, *tl
);
1264 nfsd
->nd_eoff
= nfsd
->nd_off
+ len
;
1267 * Trim the header out of the mbuf list and trim off any trailing
1268 * junk so that the mbuf list has only the write data.
1274 if (mp1
== info
.md
) {
1276 adjust
= info
.dpos
- mtod(mp1
, caddr_t
);
1277 mp1
->m_len
-= adjust
;
1278 if (mp1
->m_len
> 0 && adjust
> 0)
1279 mp1
->m_data
+= adjust
;
1286 mp1
->m_len
-= (i
- len
);
1292 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1297 nfsm_writereply(&info
, nfsd
, slp
, error
, 2 * NFSX_UNSIGNED
);
1299 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1302 nfsd
->nd_mreq
= info
.mreq
;
1303 nfsd
->nd_mrep
= NULL
;
1308 * Add this entry to the hash and time queues.
1312 wp
= slp
->ns_tq
.lh_first
;
1313 while (wp
&& wp
->nd_time
< nfsd
->nd_time
) {
1315 wp
= wp
->nd_tq
.le_next
;
1317 NFS_DPF(WG
, ("Q%03x", nfsd
->nd_retxid
& 0xfff));
1319 LIST_INSERT_AFTER(owp
, nfsd
, nd_tq
);
1321 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1323 if (nfsd
->nd_mrep
) {
1324 wpp
= NWDELAYHASH(slp
, nfsd
->nd_fh
.fh_fid
.fid_data
);
1328 bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1330 wp
= wp
->nd_hash
.le_next
;
1332 while (wp
&& wp
->nd_off
< nfsd
->nd_off
&&
1333 !bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1335 wp
= wp
->nd_hash
.le_next
;
1338 LIST_INSERT_AFTER(owp
, nfsd
, nd_hash
);
1341 * Search the hash list for overlapping entries and
1344 for(; nfsd
&& NFSW_CONTIG(owp
, nfsd
); nfsd
= wp
) {
1345 wp
= nfsd
->nd_hash
.le_next
;
1346 if (NFSW_SAMECRED(owp
, nfsd
))
1347 nfsrvw_coalesce(owp
, nfsd
);
1350 LIST_INSERT_HEAD(wpp
, nfsd
, nd_hash
);
1357 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1358 * and generate the associated reply mbuf list(s).
1361 cur_usec
= nfs_curusec();
1363 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= owp
) {
1364 owp
= nfsd
->nd_tq
.le_next
;
1365 if (nfsd
->nd_time
> cur_usec
)
1369 NFS_DPF(WG
, ("P%03x", nfsd
->nd_retxid
& 0xfff));
1370 LIST_REMOVE(nfsd
, nd_tq
);
1371 LIST_REMOVE(nfsd
, nd_hash
);
1373 info
.mrep
= nfsd
->nd_mrep
;
1374 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1375 nfsd
->nd_mrep
= NULL
;
1376 cred
= &nfsd
->nd_cr
;
1377 forat_ret
= aftat_ret
= 1;
1378 error
= nfsrv_fhtovp(&nfsd
->nd_fh
, 1, &mp
, &vp
, cred
, slp
,
1379 nfsd
->nd_nam
, &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
1382 forat_ret
= VOP_GETATTR(vp
, &forat
);
1383 if (vp
->v_type
!= VREG
) {
1387 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
1393 error
= nfsrv_access(mp
, vp
, VWRITE
, cred
, rdonly
, td
, 1);
1396 if (nfsd
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1397 ioflags
= IO_NODELOCKED
;
1398 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
)
1399 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1401 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1402 uiop
->uio_rw
= UIO_WRITE
;
1403 uiop
->uio_segflg
= UIO_SYSSPACE
;
1404 uiop
->uio_td
= NULL
;
1405 uiop
->uio_offset
= nfsd
->nd_off
;
1406 uiop
->uio_resid
= nfsd
->nd_eoff
- nfsd
->nd_off
;
1407 if (uiop
->uio_resid
> 0) {
1415 uiop
->uio_iovcnt
= i
;
1416 MALLOC(iov
, struct iovec
*, i
* sizeof (struct iovec
),
1418 uiop
->uio_iov
= ivp
= iov
;
1421 if (mp1
->m_len
> 0) {
1422 ivp
->iov_base
= mtod(mp1
, caddr_t
);
1423 ivp
->iov_len
= mp1
->m_len
;
1429 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
1430 nfsstats
.srvvop_writes
++;
1432 FREE((caddr_t
)iov
, M_TEMP
);
1437 aftat_ret
= VOP_GETATTR(vp
, &va
);
1443 * Loop around generating replies for all write rpcs that have
1444 * now been completed.
1448 NFS_DPF(WG
, ("R%03x", nfsd
->nd_retxid
& 0xfff));
1450 nfsm_writereply(&info
, nfsd
, slp
, error
,
1451 NFSX_WCCDATA(info
.v3
));
1453 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1457 nfsm_writereply(&info
, nfsd
, slp
, error
,
1458 NFSX_PREOPATTR(info
.v3
) +
1459 NFSX_POSTOPORFATTR(info
.v3
) +
1461 NFSX_WRITEVERF(info
.v3
));
1463 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1465 tl
= nfsm_build(&info
, 4 * NFSX_UNSIGNED
);
1466 *tl
++ = txdr_unsigned(nfsd
->nd_len
);
1467 *tl
++ = txdr_unsigned(swp
->nd_stable
);
1469 * Actually, there is no need to txdr these fields,
1470 * but it may make the values more human readable,
1471 * for debugging purposes.
1473 if (nfsver
.tv_sec
== 0)
1475 *tl
++ = txdr_unsigned(nfsver
.tv_sec
);
1476 *tl
= txdr_unsigned(nfsver
.tv_nsec
/ 1000);
1478 fp
= nfsm_build(&info
, NFSX_V2FATTR
);
1479 nfsm_srvfattr(nfsd
, &va
, fp
);
1482 nfsd
->nd_mreq
= info
.mreq
;
1484 panic("nfsrv_write: nd_mrep not free");
1487 * Done. Put it at the head of the timer queue so that
1488 * the final phase can return the reply.
1493 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1495 nfsd
= swp
->nd_coalesce
.lh_first
;
1497 LIST_REMOVE(nfsd
, nd_tq
);
1503 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1510 * Search for a reply to return.
1513 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= nfsd
->nd_tq
.le_next
)
1514 if (nfsd
->nd_mreq
) {
1515 NFS_DPF(WG
, ("X%03x", nfsd
->nd_retxid
& 0xfff));
1516 LIST_REMOVE(nfsd
, nd_tq
);
1517 *mrq
= nfsd
->nd_mreq
;
1527 * Coalesce the write request nfsd into owp. To do this we must:
1528 * - remove nfsd from the queues
1529 * - merge nfsd->nd_mrep into owp->nd_mrep
1530 * - update the nd_eoff and nd_stable for owp
1531 * - put nfsd on owp's nd_coalesce list
1532 * NB: Must be called at splsoftclock().
1535 nfsrvw_coalesce(struct nfsrv_descript
*owp
, struct nfsrv_descript
*nfsd
)
1539 struct nfsrv_descript
*p
;
1541 NFS_DPF(WG
, ("C%03x-%03x",
1542 nfsd
->nd_retxid
& 0xfff, owp
->nd_retxid
& 0xfff));
1543 LIST_REMOVE(nfsd
, nd_hash
);
1544 LIST_REMOVE(nfsd
, nd_tq
);
1545 if (owp
->nd_eoff
< nfsd
->nd_eoff
) {
1546 overlap
= owp
->nd_eoff
- nfsd
->nd_off
;
1548 panic("nfsrv_coalesce: bad off");
1550 m_adj(nfsd
->nd_mrep
, overlap
);
1554 mp1
->m_next
= nfsd
->nd_mrep
;
1555 owp
->nd_eoff
= nfsd
->nd_eoff
;
1557 m_freem(nfsd
->nd_mrep
);
1558 nfsd
->nd_mrep
= NULL
;
1559 if (nfsd
->nd_stable
== NFSV3WRITE_FILESYNC
)
1560 owp
->nd_stable
= NFSV3WRITE_FILESYNC
;
1561 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
&&
1562 owp
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1563 owp
->nd_stable
= NFSV3WRITE_DATASYNC
;
1564 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nfsd
, nd_tq
);
1567 * If nfsd had anything else coalesced into it, transfer them
1568 * to owp, otherwise their replies will never get sent.
1570 for (p
= nfsd
->nd_coalesce
.lh_first
; p
;
1571 p
= nfsd
->nd_coalesce
.lh_first
) {
1572 LIST_REMOVE(p
, nd_tq
);
1573 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1578 * nfs create service
1579 * now does a truncate to 0 length via. setattr if it already exists
1582 nfsrv_create(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
1583 struct thread
*td
, struct mbuf
**mrq
)
1585 struct sockaddr
*nam
= nfsd
->nd_nam
;
1586 struct ucred
*cred
= &nfsd
->nd_cr
;
1587 struct nfs_fattr
*fp
;
1588 struct vattr va
, dirfor
, diraft
;
1589 struct vattr
*vap
= &va
;
1590 struct nfsv2_sattr
*sp
;
1592 struct nlookupdata nd
;
1593 int error
= 0, len
, tsize
, dirfor_ret
= 1, diraft_ret
= 1;
1594 udev_t rdev
= NOUDEV
;
1596 int how
, exclusive_flag
= 0;
1604 u_char cverf
[NFSX_V3CREATEVERF
];
1605 struct nfsm_info info
;
1607 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
1613 info
.mrep
= nfsd
->nd_mrep
;
1615 info
.md
= nfsd
->nd_md
;
1616 info
.dpos
= nfsd
->nd_dpos
;
1617 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1619 fhp
= &nfh
.fh_generic
;
1620 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
1621 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
1624 * Call namei and do initial cleanup to get a few things
1625 * out of the way. If we get an initial error we cleanup
1626 * and return here to avoid special-casing the invalid nd
1627 * structure through the rest of the case. dirp may be
1628 * set even if an error occurs, but the nd structure will not
1629 * be valid at all if an error occurs so we have to invalidate it
1630 * prior to calling nfsm_reply ( which might goto nfsmout ).
1632 error
= nfs_namei(&nd
, cred
, NLC_CREATE
, &dvp
, &vp
,
1633 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
1634 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1635 mp
= vfs_getvfs(&fhp
->fh_fsid
);
1639 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
1646 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1647 NFSX_WCCDATA(info
.v3
), &error
));
1648 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
1649 diraft_ret
, &diraft
);
1655 * No error. Continue. State:
1658 * vp may be valid or NULL if the target does not
1662 * The error state is set through the code and we may also do some
1663 * opportunistic releasing of vnodes to avoid holding locks through
1664 * NFS I/O. The cleanup at the end is a catch-all
1669 NULLOUT(tl
= nfsm_dissect(&info
, NFSX_UNSIGNED
));
1670 how
= fxdr_unsigned(int, *tl
);
1672 case NFSV3CREATE_GUARDED
:
1678 case NFSV3CREATE_UNCHECKED
:
1679 ERROROUT(nfsm_srvsattr(&info
, vap
));
1681 case NFSV3CREATE_EXCLUSIVE
:
1682 NULLOUT(cp
= nfsm_dissect(&info
, NFSX_V3CREATEVERF
));
1683 bcopy(cp
, cverf
, NFSX_V3CREATEVERF
);
1687 vap
->va_type
= VREG
;
1689 NULLOUT(sp
= nfsm_dissect(&info
, NFSX_V2SATTR
));
1690 vap
->va_type
= IFTOVT(fxdr_unsigned(u_int32_t
, sp
->sa_mode
));
1691 if (vap
->va_type
== VNON
)
1692 vap
->va_type
= VREG
;
1693 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
1694 switch (vap
->va_type
) {
1696 tsize
= fxdr_unsigned(int32_t, sp
->sa_size
);
1698 vap
->va_size
= (u_quad_t
)tsize
;
1703 rdev
= fxdr_unsigned(long, sp
->sa_size
);
1711 * Iff doesn't exist, create it
1712 * otherwise just truncate to 0 length
1713 * should I set the mode too ?
1715 * The only possible error we can have at this point is EEXIST.
1716 * nd.ni_vp will also be non-NULL in that case.
1719 if (vap
->va_mode
== (mode_t
)VNOVAL
)
1721 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1723 error
= VOP_NCREATE(&nd
.nl_nch
, dvp
, &vp
,
1728 if (exclusive_flag
) {
1731 bcopy(cverf
, (caddr_t
)&vap
->va_atime
,
1733 error
= VOP_SETATTR(vp
, vap
, cred
);
1737 vap
->va_type
== VCHR
||
1738 vap
->va_type
== VBLK
||
1739 vap
->va_type
== VFIFO
1742 * Handle SysV FIFO node special cases. All other
1743 * devices require super user to access.
1745 if (vap
->va_type
== VCHR
&& rdev
== 0xffffffff)
1746 vap
->va_type
= VFIFO
;
1747 if (vap
->va_type
!= VFIFO
&&
1748 (error
= priv_check_cred(cred
, PRIV_ROOT
, 0))) {
1751 vap
->va_rmajor
= umajor(rdev
);
1752 vap
->va_rminor
= uminor(rdev
);
1755 error
= VOP_NMKNOD(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
);
1762 * XXX what is this junk supposed to do ?
1769 * release dvp prior to lookup
1777 * Even though LOCKPARENT was cleared, ni_dvp may
1780 nd
.ni_cnd
.cn_nameiop
= NAMEI_LOOKUP
;
1781 nd
.ni_cnd
.cn_flags
&= ~(CNP_LOCKPARENT
);
1782 nd
.ni_cnd
.cn_td
= td
;
1783 nd
.ni_cnd
.cn_cred
= cred
;
1785 error
= lookup(&nd
);
1789 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1791 /* fall through on certain errors */
1793 nfsrv_object_create(nd
.ni_vp
);
1794 if (nd
.ni_cnd
.cn_flags
& CNP_ISSYMLINK
) {
1803 if (vap
->va_size
!= -1) {
1804 error
= nfsrv_access(mp
, vp
, VWRITE
, cred
,
1805 (nd
.nl_flags
& NLC_NFS_RDONLY
), td
, 0);
1807 tempsize
= vap
->va_size
;
1809 vap
->va_size
= tempsize
;
1810 error
= VOP_SETATTR(vp
, vap
, cred
);
1816 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
1817 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1819 error
= VOP_GETATTR(vp
, vap
);
1822 if (exclusive_flag
&& !error
&&
1823 bcmp(cverf
, (caddr_t
)&vap
->va_atime
, NFSX_V3CREATEVERF
))
1825 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
1829 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1830 NFSX_SRVFH(info
.v3
) + NFSX_FATTR(info
.v3
) +
1831 NFSX_WCCDATA(info
.v3
),
1835 nfsm_srvpostop_fh(&info
, fhp
);
1836 nfsm_srvpostop_attr(&info
, nfsd
, 0, vap
);
1838 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
1839 diraft_ret
, &diraft
);
1842 nfsm_srvfhtom(&info
, fhp
);
1843 fp
= nfsm_build(&info
, NFSX_V2FATTR
);
1844 nfsm_srvfattr(nfsd
, vap
, fp
);
1849 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, 0, &error
));
1870 * nfs v3 mknod service
1873 nfsrv_mknod(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
1874 struct thread
*td
, struct mbuf
**mrq
)
1876 struct sockaddr
*nam
= nfsd
->nd_nam
;
1877 struct ucred
*cred
= &nfsd
->nd_cr
;
1878 struct vattr va
, dirfor
, diraft
;
1879 struct vattr
*vap
= &va
;
1881 struct nlookupdata nd
;
1882 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
1889 struct nfsm_info info
;
1891 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
1897 info
.mrep
= nfsd
->nd_mrep
;
1899 info
.md
= nfsd
->nd_md
;
1900 info
.dpos
= nfsd
->nd_dpos
;
1902 fhp
= &nfh
.fh_generic
;
1903 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
1904 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
1907 * Handle nfs_namei() call. If an error occurs, the nd structure
1908 * is not valid. However, nfsm_*() routines may still jump to
1912 error
= nfs_namei(&nd
, cred
, NLC_CREATE
, &dvp
, &vp
,
1913 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
1914 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1916 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
1918 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1919 NFSX_WCCDATA(1), &error
));
1920 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
1921 diraft_ret
, &diraft
);
1925 NULLOUT(tl
= nfsm_dissect(&info
, NFSX_UNSIGNED
));
1926 vtyp
= nfsv3tov_type(*tl
);
1927 if (vtyp
!= VCHR
&& vtyp
!= VBLK
&& vtyp
!= VSOCK
&& vtyp
!= VFIFO
) {
1928 error
= NFSERR_BADTYPE
;
1932 ERROROUT(nfsm_srvsattr(&info
, vap
));
1933 if (vtyp
== VCHR
|| vtyp
== VBLK
) {
1934 NULLOUT(tl
= nfsm_dissect(&info
, 2 * NFSX_UNSIGNED
));
1935 vap
->va_rmajor
= fxdr_unsigned(u_int32_t
, *tl
++);
1936 vap
->va_rminor
= fxdr_unsigned(u_int32_t
, *tl
);
1940 * Iff doesn't exist, create it.
1946 vap
->va_type
= vtyp
;
1947 if (vap
->va_mode
== (mode_t
)VNOVAL
)
1949 if (vtyp
== VSOCK
) {
1951 error
= VOP_NCREATE(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
);
1955 if (vtyp
!= VFIFO
&& (error
= priv_check_cred(cred
, PRIV_ROOT
, 0)))
1959 error
= VOP_NMKNOD(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
);
1967 * send response, cleanup, return.
1979 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
1980 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1982 error
= VOP_GETATTR(vp
, vap
);
1988 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
1993 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1994 NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) +
1995 NFSX_WCCDATA(1), &error
));
1997 nfsm_srvpostop_fh(&info
, fhp
);
1998 nfsm_srvpostop_attr(&info
, nfsd
, 0, vap
);
2000 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2001 diraft_ret
, &diraft
);
2021 * nfs remove service
2024 nfsrv_remove(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2025 struct thread
*td
, struct mbuf
**mrq
)
2027 struct sockaddr
*nam
= nfsd
->nd_nam
;
2028 struct ucred
*cred
= &nfsd
->nd_cr
;
2029 struct nlookupdata nd
;
2030 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2034 struct vattr dirfor
, diraft
;
2037 struct nfsm_info info
;
2039 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2045 info
.mrep
= nfsd
->nd_mrep
;
2047 info
.md
= nfsd
->nd_md
;
2048 info
.dpos
= nfsd
->nd_dpos
;
2049 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2051 fhp
= &nfh
.fh_generic
;
2052 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
2053 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
2055 error
= nfs_namei(&nd
, cred
, NLC_DELETE
, &dvp
, &vp
,
2056 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
2057 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2060 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2063 if (vp
->v_type
== VDIR
) {
2064 error
= EPERM
; /* POSIX */
2068 * The root of a mounted filesystem cannot be deleted.
2070 if (vp
->v_flag
& VROOT
) {
2082 error
= VOP_NREMOVE(&nd
.nl_nch
, dvp
, nd
.nl_cred
);
2087 if (dirp
&& info
.v3
)
2088 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2089 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_WCCDATA(info
.v3
), &error
));
2091 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2092 diraft_ret
, &diraft
);
2112 * nfs rename service
2115 nfsrv_rename(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2116 struct thread
*td
, struct mbuf
**mrq
)
2118 struct sockaddr
*nam
= nfsd
->nd_nam
;
2119 struct ucred
*cred
= &nfsd
->nd_cr
;
2120 int error
= 0, len
, len2
, fdirfor_ret
= 1, fdiraft_ret
= 1;
2121 int tdirfor_ret
= 1, tdiraft_ret
= 1;
2122 struct nlookupdata fromnd
, tond
;
2123 struct vnode
*fvp
, *fdirp
, *fdvp
;
2124 struct vnode
*tvp
, *tdirp
, *tdvp
;
2125 struct namecache
*ncp
;
2126 struct vattr fdirfor
, fdiraft
, tdirfor
, tdiraft
;
2128 fhandle_t
*ffhp
, *tfhp
;
2130 struct nfsm_info info
;
2132 info
.mrep
= nfsd
->nd_mrep
;
2134 info
.md
= nfsd
->nd_md
;
2135 info
.dpos
= nfsd
->nd_dpos
;
2136 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2138 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2142 ffhp
= &fnfh
.fh_generic
;
2143 tfhp
= &tnfh
.fh_generic
;
2146 * Clear fields incase goto nfsmout occurs from macro.
2149 nlookup_zero(&fromnd
);
2150 nlookup_zero(&tond
);
2154 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, ffhp
, &error
));
2155 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
2158 * Remember our original uid so that we can reset cr_uid before
2159 * the second nfs_namei() call, in case it is remapped.
2161 saved_uid
= cred
->cr_uid
;
2162 error
= nfs_namei(&fromnd
, cred
, NLC_RENAME_SRC
,
2164 ffhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &fdirp
,
2165 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2168 fdirfor_ret
= VOP_GETATTR(fdirp
, &fdirfor
);
2171 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2172 2 * NFSX_WCCDATA(info
.v3
), &error
));
2173 nfsm_srvwcc_data(&info
, nfsd
, fdirfor_ret
, &fdirfor
,
2174 fdiraft_ret
, &fdiraft
);
2175 nfsm_srvwcc_data(&info
, nfsd
, tdirfor_ret
, &tdirfor
,
2176 tdiraft_ret
, &tdiraft
);
2182 * We have to unlock the from ncp before we can safely lookup
2185 KKASSERT(fromnd
.nl_flags
& NLC_NCPISLOCKED
);
2186 cache_unlock(&fromnd
.nl_nch
);
2187 fromnd
.nl_flags
&= ~NLC_NCPISLOCKED
;
2188 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, tfhp
, &error
));
2189 NEGATIVEOUT(len2
= nfsm_strsiz(&info
, NFS_MAXNAMLEN
));
2190 cred
->cr_uid
= saved_uid
;
2192 error
= nfs_namei(&tond
, cred
, NLC_RENAME_DST
, NULL
, NULL
,
2193 tfhp
, len2
, slp
, nam
, &info
.md
, &info
.dpos
, &tdirp
,
2194 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2197 tdirfor_ret
= VOP_GETATTR(tdirp
, &tdirfor
);
2205 if (cache_lock_nonblock(&fromnd
.nl_nch
) == 0) {
2206 cache_resolve(&fromnd
.nl_nch
, fromnd
.nl_cred
);
2207 } else if (fromnd
.nl_nch
.ncp
> tond
.nl_nch
.ncp
) {
2208 cache_lock(&fromnd
.nl_nch
);
2209 cache_resolve(&fromnd
.nl_nch
, fromnd
.nl_cred
);
2211 cache_unlock(&tond
.nl_nch
);
2212 cache_lock(&fromnd
.nl_nch
);
2213 cache_resolve(&fromnd
.nl_nch
, fromnd
.nl_cred
);
2214 cache_lock(&tond
.nl_nch
);
2215 cache_resolve(&tond
.nl_nch
, tond
.nl_cred
);
2217 fromnd
.nl_flags
|= NLC_NCPISLOCKED
;
2219 fvp
= fromnd
.nl_nch
.ncp
->nc_vp
;
2220 tvp
= tond
.nl_nch
.ncp
->nc_vp
;
2223 * Set fdvp and tdvp. We haven't done all the topology checks
2224 * so these can wind up NULL (e.g. if either fvp or tvp is a mount
2225 * point). If we get through the checks these will be guarenteed
2228 * Holding the children ncp's should be sufficient to prevent
2229 * fdvp and tdvp ripouts.
2231 if (fromnd
.nl_nch
.ncp
->nc_parent
)
2232 fdvp
= fromnd
.nl_nch
.ncp
->nc_parent
->nc_vp
;
2235 if (tond
.nl_nch
.ncp
->nc_parent
)
2236 tdvp
= tond
.nl_nch
.ncp
->nc_parent
->nc_vp
;
2241 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2247 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2254 if (tvp
->v_type
== VDIR
&& (tond
.nl_nch
.ncp
->nc_flag
& NCF_ISMOUNTPT
)) {
2262 if (fvp
->v_type
== VDIR
&& (fromnd
.nl_nch
.ncp
->nc_flag
& NCF_ISMOUNTPT
)) {
2269 if (fromnd
.nl_nch
.mount
!= tond
.nl_nch
.mount
) {
2276 if (fromnd
.nl_nch
.ncp
== tond
.nl_nch
.ncp
->nc_parent
) {
2284 * You cannot rename a source into itself or a subdirectory of itself.
2285 * We check this by travsering the target directory upwards looking
2286 * for a match against the source.
2289 for (ncp
= tond
.nl_nch
.ncp
; ncp
; ncp
= ncp
->nc_parent
) {
2290 if (fromnd
.nl_nch
.ncp
== ncp
) {
2298 * If source is the same as the destination (that is the
2299 * same vnode with the same name in the same directory),
2300 * then there is nothing to do.
2302 if (fromnd
.nl_nch
.ncp
== tond
.nl_nch
.ncp
)
2307 * The VOP_NRENAME function releases all vnode references &
2308 * locks prior to returning so we need to clear the pointers
2309 * to bypass cleanup code later on.
2311 error
= VOP_NRENAME(&fromnd
.nl_nch
, &tond
.nl_nch
,
2312 fdvp
, tdvp
, tond
.nl_cred
);
2321 fdiraft_ret
= VOP_GETATTR(fdirp
, &fdiraft
);
2323 tdiraft_ret
= VOP_GETATTR(tdirp
, &tdiraft
);
2324 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2325 2 * NFSX_WCCDATA(info
.v3
), &error
));
2327 nfsm_srvwcc_data(&info
, nfsd
, fdirfor_ret
, &fdirfor
,
2328 fdiraft_ret
, &fdiraft
);
2329 nfsm_srvwcc_data(&info
, nfsd
, tdirfor_ret
, &tdirfor
,
2330 tdiraft_ret
, &tdiraft
);
2339 nlookup_done(&tond
);
2342 nlookup_done(&fromnd
);
2350 nfsrv_link(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2351 struct thread
*td
, struct mbuf
**mrq
)
2353 struct sockaddr
*nam
= nfsd
->nd_nam
;
2354 struct ucred
*cred
= &nfsd
->nd_cr
;
2355 struct nlookupdata nd
;
2356 int error
= 0, rdonly
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2364 struct vattr dirfor
, diraft
, at
;
2366 fhandle_t
*fhp
, *dfhp
;
2367 struct nfsm_info info
;
2369 info
.mrep
= nfsd
->nd_mrep
;
2371 info
.md
= nfsd
->nd_md
;
2372 info
.dpos
= nfsd
->nd_dpos
;
2373 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2375 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2377 dirp
= dvp
= vp
= xp
= NULL
;
2380 fhp
= &nfh
.fh_generic
;
2381 dfhp
= &dnfh
.fh_generic
;
2382 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
2383 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, dfhp
, &error
));
2384 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
2386 error
= nfsrv_fhtovp(fhp
, FALSE
, &xmp
, &xp
, cred
, slp
, nam
,
2387 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
2389 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2390 NFSX_POSTOPATTR(info
.v3
) +
2391 NFSX_WCCDATA(info
.v3
),
2393 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
2394 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2395 diraft_ret
, &diraft
);
2400 if (xp
->v_type
== VDIR
) {
2401 error
= EPERM
; /* POSIX */
2405 error
= nfs_namei(&nd
, cred
, NLC_CREATE
, &dvp
, &vp
,
2406 dfhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
2407 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2410 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2419 if (xp
->v_mount
!= dvp
->v_mount
)
2424 error
= VOP_NLINK(&nd
.nl_nch
, dvp
, xp
, nd
.nl_cred
);
2432 getret
= VOP_GETATTR(xp
, &at
);
2434 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2435 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2436 NFSX_POSTOPATTR(info
.v3
) + NFSX_WCCDATA(info
.v3
),
2439 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
2440 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2441 diraft_ret
, &diraft
);
2465 * nfs symbolic link service
2468 nfsrv_symlink(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2469 struct thread
*td
, struct mbuf
**mrq
)
2471 struct sockaddr
*nam
= nfsd
->nd_nam
;
2472 struct ucred
*cred
= &nfsd
->nd_cr
;
2473 struct vattr va
, dirfor
, diraft
;
2474 struct nlookupdata nd
;
2475 struct vattr
*vap
= &va
;
2476 struct nfsv2_sattr
*sp
;
2477 char *pathcp
= NULL
;
2480 int error
= 0, len
, len2
, dirfor_ret
= 1, diraft_ret
= 1;
2486 struct nfsm_info info
;
2488 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2494 info
.mrep
= nfsd
->nd_mrep
;
2496 info
.md
= nfsd
->nd_md
;
2497 info
.dpos
= nfsd
->nd_dpos
;
2498 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2500 fhp
= &nfh
.fh_generic
;
2501 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
2502 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
2504 error
= nfs_namei(&nd
, cred
, NLC_CREATE
, &dvp
, &vp
,
2505 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
2506 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2509 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2516 ERROROUT(nfsm_srvsattr(&info
, vap
));
2518 NEGATIVEOUT(len2
= nfsm_strsiz(&info
, NFS_MAXPATHLEN
));
2519 MALLOC(pathcp
, caddr_t
, len2
+ 1, M_TEMP
, M_WAITOK
);
2520 iv
.iov_base
= pathcp
;
2522 io
.uio_resid
= len2
;
2526 io
.uio_segflg
= UIO_SYSSPACE
;
2527 io
.uio_rw
= UIO_READ
;
2529 ERROROUT(nfsm_mtouio(&info
, &io
, len2
));
2531 NULLOUT(sp
= nfsm_dissect(&info
, NFSX_V2SATTR
));
2532 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
2534 *(pathcp
+ len2
) = '\0';
2540 if (vap
->va_mode
== (mode_t
)VNOVAL
)
2544 error
= VOP_NSYMLINK(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
, pathcp
);
2548 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
2549 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
2551 error
= VOP_GETATTR(vp
, vap
);
2566 FREE(pathcp
, M_TEMP
);
2570 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2574 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2575 NFSX_SRVFH(info
.v3
) + NFSX_POSTOPATTR(info
.v3
) +
2576 NFSX_WCCDATA(info
.v3
),
2580 nfsm_srvpostop_fh(&info
, fhp
);
2581 nfsm_srvpostop_attr(&info
, nfsd
, 0, vap
);
2583 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2584 diraft_ret
, &diraft
);
2597 FREE(pathcp
, M_TEMP
);
2605 nfsrv_mkdir(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2606 struct thread
*td
, struct mbuf
**mrq
)
2608 struct sockaddr
*nam
= nfsd
->nd_nam
;
2609 struct ucred
*cred
= &nfsd
->nd_cr
;
2610 struct vattr va
, dirfor
, diraft
;
2611 struct vattr
*vap
= &va
;
2612 struct nfs_fattr
*fp
;
2613 struct nlookupdata nd
;
2615 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2621 struct nfsm_info info
;
2623 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2629 info
.dpos
= nfsd
->nd_dpos
;
2630 info
.mrep
= nfsd
->nd_mrep
;
2632 info
.md
= nfsd
->nd_md
;
2633 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2635 fhp
= &nfh
.fh_generic
;
2636 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
2637 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
2639 error
= nfs_namei(&nd
, cred
, NLC_CREATE
, &dvp
, &vp
,
2640 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
2641 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2644 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2647 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2648 NFSX_WCCDATA(info
.v3
), &error
));
2649 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2650 diraft_ret
, &diraft
);
2656 ERROROUT(nfsm_srvsattr(&info
, vap
));
2658 NULLOUT(tl
= nfsm_dissect(&info
, NFSX_UNSIGNED
));
2659 vap
->va_mode
= nfstov_mode(*tl
++);
2663 * At this point nd.ni_dvp is referenced and exclusively locked and
2664 * nd.ni_vp, if it exists, is referenced but not locked.
2667 vap
->va_type
= VDIR
;
2674 * Issue mkdir op. Since SAVESTART is not set, the pathname
2675 * component is freed by the VOP call. This will fill-in
2676 * nd.ni_vp, reference, and exclusively lock it.
2678 if (vap
->va_mode
== (mode_t
)VNOVAL
)
2681 error
= VOP_NMKDIR(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
);
2686 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
2687 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
2689 error
= VOP_GETATTR(vp
, vap
);
2693 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2694 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2695 NFSX_SRVFH(info
.v3
) + NFSX_POSTOPATTR(info
.v3
) +
2696 NFSX_WCCDATA(info
.v3
),
2700 nfsm_srvpostop_fh(&info
, fhp
);
2701 nfsm_srvpostop_attr(&info
, nfsd
, 0, vap
);
2703 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2704 diraft_ret
, &diraft
);
2706 nfsm_srvfhtom(&info
, fhp
);
2707 fp
= nfsm_build(&info
, NFSX_V2FATTR
);
2708 nfsm_srvfattr(nfsd
, vap
, fp
);
2733 nfsrv_rmdir(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2734 struct thread
*td
, struct mbuf
**mrq
)
2736 struct sockaddr
*nam
= nfsd
->nd_nam
;
2737 struct ucred
*cred
= &nfsd
->nd_cr
;
2738 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2742 struct vattr dirfor
, diraft
;
2745 struct nlookupdata nd
;
2746 struct nfsm_info info
;
2748 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2754 info
.mrep
= nfsd
->nd_mrep
;
2756 info
.md
= nfsd
->nd_md
;
2757 info
.dpos
= nfsd
->nd_dpos
;
2758 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2760 fhp
= &nfh
.fh_generic
;
2761 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
2762 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
2764 error
= nfs_namei(&nd
, cred
, NLC_DELETE
, &dvp
, &vp
,
2765 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
2766 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2769 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2772 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2773 NFSX_WCCDATA(info
.v3
), &error
));
2774 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2775 diraft_ret
, &diraft
);
2779 if (vp
->v_type
!= VDIR
) {
2785 * The root of a mounted filesystem cannot be deleted.
2787 if (vp
->v_flag
& VROOT
)
2791 * Issue or abort op. Since SAVESTART is not set, path name
2792 * component is freed by the VOP after either.
2799 error
= VOP_NRMDIR(&nd
.nl_nch
, dvp
, nd
.nl_cred
);
2806 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2807 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_WCCDATA(info
.v3
), &error
));
2809 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2810 diraft_ret
, &diraft
);
2832 * nfs readdir service
2833 * - mallocs what it thinks is enough to read
2834 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2835 * - calls VOP_READDIR()
2836 * - loops around building the reply
2837 * if the output generated exceeds count break out of loop
2838 * The nfsm_clget macro is used here so that the reply will be packed
2839 * tightly in mbuf clusters.
2840 * - it only knows that it has encountered eof when the VOP_READDIR()
2842 * - as such one readdir rpc will return eof false although you are there
2843 * and then the next will return eof
2844 * - it trims out records with d_fileno == 0
2845 * this doesn't matter for Unix clients, but they might confuse clients
2847 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2848 * than requested, but this may not apply to all filesystems. For
2849 * example, client NFS does not { although it is never remote mounted
2851 * The alternate call nfsrv_readdirplus() does lookups as well.
2852 * PS: The NFS protocol spec. does not clarify what the "count" byte
2853 * argument is a count of.. just name strings and file id's or the
2854 * entire reply rpc or ...
2855 * I tried just file name and id sizes and it confused the Sun client,
2856 * so I am using the full rpc size now. The "paranoia.." comment refers
2857 * to including the status longwords that are not a part of the dir.
2858 * "entry" structures, but are in the rpc.
2862 u_int32_t fl_postopok
;
2863 u_int32_t fl_fattr
[NFSX_V3FATTR
/ sizeof (u_int32_t
)];
2865 u_int32_t fl_fhsize
;
2866 u_int32_t fl_nfh
[NFSX_V3FH
/ sizeof (u_int32_t
)];
2870 nfsrv_readdir(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2871 struct thread
*td
, struct mbuf
**mrq
)
2873 struct sockaddr
*nam
= nfsd
->nd_nam
;
2874 struct ucred
*cred
= &nfsd
->nd_cr
;
2879 struct mbuf
*mp1
, *mp2
;
2880 char *cpos
, *cend
, *rbuf
;
2881 struct vnode
*vp
= NULL
;
2882 struct mount
*mp
= NULL
;
2888 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2889 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, ncookies
;
2890 u_quad_t off
, toff
, verf
;
2891 off_t
*cookies
= NULL
, *cookiep
;
2892 struct nfsm_info info
;
2894 info
.mrep
= nfsd
->nd_mrep
;
2896 info
.md
= nfsd
->nd_md
;
2897 info
.dpos
= nfsd
->nd_dpos
;
2898 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2900 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2901 fhp
= &nfh
.fh_generic
;
2902 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
2904 NULLOUT(tl
= nfsm_dissect(&info
, 5 * NFSX_UNSIGNED
));
2905 toff
= fxdr_hyper(tl
);
2907 verf
= fxdr_hyper(tl
);
2910 NULLOUT(tl
= nfsm_dissect(&info
, 2 * NFSX_UNSIGNED
));
2911 toff
= fxdr_unsigned(u_quad_t
, *tl
++);
2912 verf
= 0; /* shut up gcc */
2915 cnt
= fxdr_unsigned(int, *tl
);
2916 siz
= ((cnt
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
2917 xfer
= NFS_SRVMAXDATA(nfsd
);
2923 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
2924 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
2925 if (!error
&& vp
->v_type
!= VDIR
) {
2931 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_UNSIGNED
, &error
));
2932 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
2938 * Obtain lock on vnode for this section of the code
2942 error
= getret
= VOP_GETATTR(vp
, &at
);
2945 * XXX This check may be too strict for Solaris 2.5 clients.
2947 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
2948 error
= NFSERR_BAD_COOKIE
;
2952 error
= nfsrv_access(mp
, vp
, VEXEC
, cred
, rdonly
, td
, 0);
2956 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2957 NFSX_POSTOPATTR(info
.v3
), &error
));
2958 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
2965 * end section. Allocate rbuf and continue
2967 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
2970 iv
.iov_len
= fullsiz
;
2973 io
.uio_offset
= (off_t
)off
;
2974 io
.uio_resid
= fullsiz
;
2975 io
.uio_segflg
= UIO_SYSSPACE
;
2976 io
.uio_rw
= UIO_READ
;
2980 kfree((caddr_t
)cookies
, M_TEMP
);
2983 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
2984 off
= (off_t
)io
.uio_offset
;
2985 if (!cookies
&& !error
)
2986 error
= NFSERR_PERM
;
2988 getret
= VOP_GETATTR(vp
, &at
);
2995 kfree((caddr_t
)rbuf
, M_TEMP
);
2997 kfree((caddr_t
)cookies
, M_TEMP
);
2998 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2999 NFSX_POSTOPATTR(info
.v3
), &error
));
3000 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3005 siz
-= io
.uio_resid
;
3008 * If nothing read, return eof
3014 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3015 NFSX_POSTOPATTR(info
.v3
) +
3016 NFSX_COOKIEVERF(info
.v3
) +
3020 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3021 tl
= nfsm_build(&info
, 4 * NFSX_UNSIGNED
);
3022 txdr_hyper(at
.va_filerev
, tl
);
3025 tl
= nfsm_build(&info
, 2 * NFSX_UNSIGNED
);
3028 FREE((caddr_t
)rbuf
, M_TEMP
);
3029 FREE((caddr_t
)cookies
, M_TEMP
);
3036 * Check for degenerate cases of nothing useful read.
3037 * If so go try again
3041 dp
= (struct dirent
*)cpos
;
3044 * For some reason FreeBSD's ufs_readdir() chooses to back the
3045 * directory offset up to a block boundary, so it is necessary to
3046 * skip over the records that preceed the requested offset. This
3047 * requires the assumption that file offset cookies monotonically
3050 while (cpos
< cend
&& ncookies
> 0 &&
3051 (dp
->d_ino
== 0 || dp
->d_type
== DT_WHT
||
3052 ((u_quad_t
)(*cookiep
)) <= toff
)) {
3053 dp
= _DIRENT_NEXT(dp
);
3058 if (cpos
>= cend
|| ncookies
== 0) {
3064 len
= 3 * NFSX_UNSIGNED
; /* paranoia, probably can be 0 */
3065 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3066 NFSX_POSTOPATTR(info
.v3
) +
3067 NFSX_COOKIEVERF(info
.v3
) + siz
,
3070 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3071 tl
= nfsm_build(&info
, 2 * NFSX_UNSIGNED
);
3072 txdr_hyper(at
.va_filerev
, tl
);
3074 mp1
= mp2
= info
.mb
;
3076 be
= bp
+ M_TRAILINGSPACE(mp1
);
3078 /* Loop through the records and build reply */
3079 while (cpos
< cend
&& ncookies
> 0) {
3080 if (dp
->d_ino
!= 0 && dp
->d_type
!= DT_WHT
) {
3081 nlen
= dp
->d_namlen
;
3082 rem
= nfsm_rndup(nlen
) - nlen
;
3083 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
3085 len
+= 2 * NFSX_UNSIGNED
;
3091 * Build the directory record xdr from
3094 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3096 bp
+= NFSX_UNSIGNED
;
3098 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3100 bp
+= NFSX_UNSIGNED
;
3102 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3103 *tl
= txdr_unsigned(dp
->d_ino
);
3104 bp
+= NFSX_UNSIGNED
;
3105 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3106 *tl
= txdr_unsigned(nlen
);
3107 bp
+= NFSX_UNSIGNED
;
3109 /* And loop around copying the name */
3113 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3118 bcopy(cp
, bp
, tsiz
);
3124 /* And null pad to a int32_t boundary */
3125 for (i
= 0; i
< rem
; i
++)
3127 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3129 /* Finish off the record */
3131 *tl
= txdr_unsigned(*cookiep
>> 32);
3132 bp
+= NFSX_UNSIGNED
;
3133 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3135 *tl
= txdr_unsigned(*cookiep
);
3136 bp
+= NFSX_UNSIGNED
;
3138 dp
= _DIRENT_NEXT(dp
);
3145 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3147 bp
+= NFSX_UNSIGNED
;
3148 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3153 bp
+= NFSX_UNSIGNED
;
3154 if (mp1
!= info
.mb
) {
3156 mp1
->m_len
= bp
- mtod(mp1
, caddr_t
);
3158 mp1
->m_len
+= bp
- info
.bpos
;
3159 FREE((caddr_t
)rbuf
, M_TEMP
);
3160 FREE((caddr_t
)cookies
, M_TEMP
);
3170 nfsrv_readdirplus(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3171 struct thread
*td
, struct mbuf
**mrq
)
3173 struct sockaddr
*nam
= nfsd
->nd_nam
;
3174 struct ucred
*cred
= &nfsd
->nd_cr
;
3179 struct mbuf
*mp1
, *mp2
;
3180 char *cpos
, *cend
, *rbuf
;
3181 struct vnode
*vp
= NULL
, *nvp
;
3182 struct mount
*mp
= NULL
;
3185 fhandle_t
*fhp
, *nfhp
= (fhandle_t
*)fl
.fl_nfh
;
3188 struct vattr va
, at
, *vap
= &va
;
3189 struct nfs_fattr
*fp
;
3190 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
3191 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, dirlen
, ncookies
;
3192 u_quad_t off
, toff
, verf
;
3193 off_t
*cookies
= NULL
, *cookiep
; /* needs to be int64_t or off_t */
3194 struct nfsm_info info
;
3196 info
.mrep
= nfsd
->nd_mrep
;
3198 info
.md
= nfsd
->nd_md
;
3199 info
.dpos
= nfsd
->nd_dpos
;
3201 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3202 fhp
= &nfh
.fh_generic
;
3203 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
3204 NULLOUT(tl
= nfsm_dissect(&info
, 6 * NFSX_UNSIGNED
));
3205 toff
= fxdr_hyper(tl
);
3207 verf
= fxdr_hyper(tl
);
3209 siz
= fxdr_unsigned(int, *tl
++);
3210 cnt
= fxdr_unsigned(int, *tl
);
3212 siz
= ((siz
+ DIRBLKSIZ
- 1) & ~(DIRBLKSIZ
- 1));
3213 xfer
= NFS_SRVMAXDATA(nfsd
);
3219 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3220 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3221 if (!error
&& vp
->v_type
!= VDIR
) {
3227 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_UNSIGNED
, &error
));
3228 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3232 error
= getret
= VOP_GETATTR(vp
, &at
);
3235 * XXX This check may be too strict for Solaris 2.5 clients.
3237 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
3238 error
= NFSERR_BAD_COOKIE
;
3241 error
= nfsrv_access(mp
, vp
, VEXEC
, cred
, rdonly
, td
, 0);
3246 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3247 NFSX_V3POSTOPATTR
, &error
));
3248 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3253 MALLOC(rbuf
, caddr_t
, siz
, M_TEMP
, M_WAITOK
);
3256 iv
.iov_len
= fullsiz
;
3259 io
.uio_offset
= (off_t
)off
;
3260 io
.uio_resid
= fullsiz
;
3261 io
.uio_segflg
= UIO_SYSSPACE
;
3262 io
.uio_rw
= UIO_READ
;
3266 kfree((caddr_t
)cookies
, M_TEMP
);
3269 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
3270 off
= (u_quad_t
)io
.uio_offset
;
3271 getret
= VOP_GETATTR(vp
, &at
);
3272 if (!cookies
&& !error
)
3273 error
= NFSERR_PERM
;
3280 kfree((caddr_t
)cookies
, M_TEMP
);
3281 kfree((caddr_t
)rbuf
, M_TEMP
);
3282 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3283 NFSX_V3POSTOPATTR
, &error
));
3284 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3289 siz
-= io
.uio_resid
;
3292 * If nothing read, return eof
3298 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3303 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3304 tl
= nfsm_build(&info
, 4 * NFSX_UNSIGNED
);
3305 txdr_hyper(at
.va_filerev
, tl
);
3309 FREE((caddr_t
)cookies
, M_TEMP
);
3310 FREE((caddr_t
)rbuf
, M_TEMP
);
3317 * Check for degenerate cases of nothing useful read.
3318 * If so go try again
3322 dp
= (struct dirent
*)cpos
;
3325 * For some reason FreeBSD's ufs_readdir() chooses to back the
3326 * directory offset up to a block boundary, so it is necessary to
3327 * skip over the records that preceed the requested offset. This
3328 * requires the assumption that file offset cookies monotonically
3331 while (cpos
< cend
&& ncookies
> 0 &&
3332 (dp
->d_ino
== 0 || dp
->d_type
== DT_WHT
||
3333 ((u_quad_t
)(*cookiep
)) <= toff
)) {
3334 dp
= _DIRENT_NEXT(dp
);
3339 if (cpos
>= cend
|| ncookies
== 0) {
3346 * Probe one of the directory entries to see if the filesystem
3349 if (VFS_VGET(vp
->v_mount
, dp
->d_ino
, &nvp
) == EOPNOTSUPP
) {
3350 error
= NFSERR_NOTSUPP
;
3353 kfree((caddr_t
)cookies
, M_TEMP
);
3354 kfree((caddr_t
)rbuf
, M_TEMP
);
3355 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3356 NFSX_V3POSTOPATTR
, &error
));
3357 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3366 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+
3368 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, cnt
, &error
));
3369 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3370 tl
= nfsm_build(&info
, 2 * NFSX_UNSIGNED
);
3371 txdr_hyper(at
.va_filerev
, tl
);
3372 mp1
= mp2
= info
.mb
;
3374 be
= bp
+ M_TRAILINGSPACE(mp1
);
3376 /* Loop through the records and build reply */
3377 while (cpos
< cend
&& ncookies
> 0) {
3378 if (dp
->d_ino
!= 0 && dp
->d_type
!= DT_WHT
) {
3379 nlen
= dp
->d_namlen
;
3380 rem
= nfsm_rndup(nlen
)-nlen
;
3383 * For readdir_and_lookup get the vnode using
3386 if (VFS_VGET(vp
->v_mount
, dp
->d_ino
, &nvp
))
3388 bzero((caddr_t
)nfhp
, NFSX_V3FH
);
3389 nfhp
->fh_fsid
= fhp
->fh_fsid
;
3390 if (VFS_VPTOFH(nvp
, &nfhp
->fh_fid
)) {
3395 if (VOP_GETATTR(nvp
, vap
)) {
3404 * If either the dircount or maxcount will be
3405 * exceeded, get out now. Both of these lengths
3406 * are calculated conservatively, including all
3409 len
+= (8 * NFSX_UNSIGNED
+ nlen
+ rem
+ NFSX_V3FH
+
3411 dirlen
+= (6 * NFSX_UNSIGNED
+ nlen
+ rem
);
3412 if (len
> cnt
|| dirlen
> fullsiz
) {
3418 * Build the directory record xdr from
3421 fp
= (struct nfs_fattr
*)&fl
.fl_fattr
;
3422 nfsm_srvfattr(nfsd
, vap
, fp
);
3423 fl
.fl_fhsize
= txdr_unsigned(NFSX_V3FH
);
3424 fl
.fl_fhok
= nfs_true
;
3425 fl
.fl_postopok
= nfs_true
;
3426 fl
.fl_off
.nfsuquad
[0] = txdr_unsigned(*cookiep
>> 32);
3427 fl
.fl_off
.nfsuquad
[1] = txdr_unsigned(*cookiep
);
3429 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3431 bp
+= NFSX_UNSIGNED
;
3432 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3434 bp
+= NFSX_UNSIGNED
;
3435 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3436 *tl
= txdr_unsigned(dp
->d_ino
);
3437 bp
+= NFSX_UNSIGNED
;
3438 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3439 *tl
= txdr_unsigned(nlen
);
3440 bp
+= NFSX_UNSIGNED
;
3442 /* And loop around copying the name */
3446 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3447 if ((bp
+ xfer
) > be
)
3451 bcopy(cp
, bp
, tsiz
);
3457 /* And null pad to a int32_t boundary */
3458 for (i
= 0; i
< rem
; i
++)
3462 * Now copy the flrep structure out.
3464 xfer
= sizeof (struct flrep
);
3467 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3468 if ((bp
+ xfer
) > be
)
3472 bcopy(cp
, bp
, tsiz
);
3480 dp
= _DIRENT_NEXT(dp
);
3487 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3489 bp
+= NFSX_UNSIGNED
;
3490 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3495 bp
+= NFSX_UNSIGNED
;
3496 if (mp1
!= info
.mb
) {
3498 mp1
->m_len
= bp
- mtod(mp1
, caddr_t
);
3500 mp1
->m_len
+= bp
- info
.bpos
;
3501 FREE((caddr_t
)cookies
, M_TEMP
);
3502 FREE((caddr_t
)rbuf
, M_TEMP
);
3511 * nfs commit service
3514 nfsrv_commit(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3515 struct thread
*td
, struct mbuf
**mrq
)
3517 struct sockaddr
*nam
= nfsd
->nd_nam
;
3518 struct ucred
*cred
= &nfsd
->nd_cr
;
3519 struct vattr bfor
, aft
;
3520 struct vnode
*vp
= NULL
;
3521 struct mount
*mp
= NULL
;
3525 int error
= 0, rdonly
, for_ret
= 1, aft_ret
= 1, cnt
;
3527 struct nfsm_info info
;
3529 info
.mrep
= nfsd
->nd_mrep
;
3531 info
.md
= nfsd
->nd_md
;
3532 info
.dpos
= nfsd
->nd_dpos
;
3534 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3535 fhp
= &nfh
.fh_generic
;
3536 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
3537 NULLOUT(tl
= nfsm_dissect(&info
, 3 * NFSX_UNSIGNED
));
3540 * XXX At this time VOP_FSYNC() does not accept offset and byte
3541 * count parameters, so these arguments are useless (someday maybe).
3543 off
= fxdr_hyper(tl
);
3545 cnt
= fxdr_unsigned(int, *tl
);
3546 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3547 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3549 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3550 2 * NFSX_UNSIGNED
, &error
));
3551 nfsm_srvwcc_data(&info
, nfsd
, for_ret
, &bfor
,
3556 for_ret
= VOP_GETATTR(vp
, &bfor
);
3558 if (cnt
> MAX_COMMIT_COUNT
) {
3560 * Give up and do the whole thing
3563 (vp
->v_object
->flags
& OBJ_MIGHTBEDIRTY
)) {
3564 vm_object_page_clean(vp
->v_object
, 0, 0, OBJPC_SYNC
);
3566 error
= VOP_FSYNC(vp
, MNT_WAIT
);
3569 * Locate and synchronously write any buffers that fall
3570 * into the requested range. Note: we are assuming that
3571 * f_iosize is a power of 2.
3573 int iosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
3574 int iomask
= iosize
- 1;
3578 * Align to iosize boundry, super-align to page boundry.
3581 cnt
+= off
& iomask
;
3582 off
&= ~(u_quad_t
)iomask
;
3584 if (off
& PAGE_MASK
) {
3585 cnt
+= off
& PAGE_MASK
;
3586 off
&= ~(u_quad_t
)PAGE_MASK
;
3591 (vp
->v_object
->flags
& OBJ_MIGHTBEDIRTY
)) {
3592 vm_object_page_clean(vp
->v_object
, off
/ PAGE_SIZE
, (cnt
+ PAGE_MASK
) / PAGE_SIZE
, OBJPC_SYNC
);
3600 * If we have a buffer and it is marked B_DELWRI we
3601 * have to lock and write it. Otherwise the prior
3602 * write is assumed to have already been committed.
3604 if ((bp
= findblk(vp
, loffset
, FINDBLK_TEST
)) != NULL
) {
3605 if (bp
->b_flags
& B_DELWRI
)
3606 bp
= findblk(vp
, loffset
, 0);
3611 if (bp
->b_flags
& B_DELWRI
) {
3628 aft_ret
= VOP_GETATTR(vp
, &aft
);
3631 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3632 NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
,
3634 nfsm_srvwcc_data(&info
, nfsd
, for_ret
, &bfor
,
3637 tl
= nfsm_build(&info
, NFSX_V3WRITEVERF
);
3638 if (nfsver
.tv_sec
== 0)
3640 *tl
++ = txdr_unsigned(nfsver
.tv_sec
);
3641 *tl
= txdr_unsigned(nfsver
.tv_nsec
/ 1000);
3653 * nfs statfs service
3656 nfsrv_statfs(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3657 struct thread
*td
, struct mbuf
**mrq
)
3659 struct sockaddr
*nam
= nfsd
->nd_nam
;
3660 struct ucred
*cred
= &nfsd
->nd_cr
;
3662 struct nfs_statfs
*sfp
;
3663 int error
= 0, rdonly
, getret
= 1;
3664 struct vnode
*vp
= NULL
;
3665 struct mount
*mp
= NULL
;
3669 struct statfs statfs
;
3671 struct nfsm_info info
;
3673 info
.mrep
= nfsd
->nd_mrep
;
3675 info
.md
= nfsd
->nd_md
;
3676 info
.dpos
= nfsd
->nd_dpos
;
3677 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3679 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3680 fhp
= &nfh
.fh_generic
;
3681 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
3682 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3683 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3685 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_UNSIGNED
, &error
));
3686 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3691 error
= VFS_STATFS(vp
->v_mount
, sf
, proc0
.p_ucred
);
3692 getret
= VOP_GETATTR(vp
, &at
);
3695 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3696 NFSX_POSTOPATTR(info
.v3
) + NFSX_STATFS(info
.v3
),
3699 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3704 sfp
= nfsm_build(&info
, NFSX_STATFS(info
.v3
));
3706 tval
= (u_quad_t
)sf
->f_blocks
;
3707 tval
*= (u_quad_t
)sf
->f_bsize
;
3708 txdr_hyper(tval
, &sfp
->sf_tbytes
);
3709 tval
= (u_quad_t
)sf
->f_bfree
;
3710 tval
*= (u_quad_t
)sf
->f_bsize
;
3711 txdr_hyper(tval
, &sfp
->sf_fbytes
);
3712 tval
= (u_quad_t
)sf
->f_bavail
;
3713 tval
*= (u_quad_t
)sf
->f_bsize
;
3714 txdr_hyper(tval
, &sfp
->sf_abytes
);
3715 sfp
->sf_tfiles
.nfsuquad
[0] = 0;
3716 sfp
->sf_tfiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_files
);
3717 sfp
->sf_ffiles
.nfsuquad
[0] = 0;
3718 sfp
->sf_ffiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3719 sfp
->sf_afiles
.nfsuquad
[0] = 0;
3720 sfp
->sf_afiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3721 sfp
->sf_invarsec
= 0;
3723 sfp
->sf_tsize
= txdr_unsigned(NFS_MAXDGRAMDATA
);
3724 sfp
->sf_bsize
= txdr_unsigned(sf
->f_bsize
);
3725 sfp
->sf_blocks
= txdr_unsigned(sf
->f_blocks
);
3726 sfp
->sf_bfree
= txdr_unsigned(sf
->f_bfree
);
3727 sfp
->sf_bavail
= txdr_unsigned(sf
->f_bavail
);
3737 * nfs fsinfo service
3740 nfsrv_fsinfo(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3741 struct thread
*td
, struct mbuf
**mrq
)
3743 struct sockaddr
*nam
= nfsd
->nd_nam
;
3744 struct ucred
*cred
= &nfsd
->nd_cr
;
3745 struct nfsv3_fsinfo
*sip
;
3746 int error
= 0, rdonly
, getret
= 1, pref
;
3747 struct vnode
*vp
= NULL
;
3748 struct mount
*mp
= NULL
;
3754 struct nfsm_info info
;
3756 info
.mrep
= nfsd
->nd_mrep
;
3758 info
.md
= nfsd
->nd_md
;
3759 info
.dpos
= nfsd
->nd_dpos
;
3761 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3762 fhp
= &nfh
.fh_generic
;
3763 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
3764 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3765 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3767 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_UNSIGNED
, &error
));
3768 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3773 /* XXX Try to make a guess on the max file size. */
3774 VFS_STATFS(vp
->v_mount
, &sb
, proc0
.p_ucred
);
3775 maxfsize
= (u_quad_t
)0x80000000 * sb
.f_bsize
- 1;
3777 getret
= VOP_GETATTR(vp
, &at
);
3780 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3781 NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
, &error
));
3782 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3783 sip
= nfsm_build(&info
, NFSX_V3FSINFO
);
3787 * There should be file system VFS OP(s) to get this information.
3788 * For now, assume ufs.
3790 if (slp
->ns_so
->so_type
== SOCK_DGRAM
)
3791 pref
= NFS_MAXDGRAMDATA
;
3794 sip
->fs_rtmax
= txdr_unsigned(NFS_MAXDATA
);
3795 sip
->fs_rtpref
= txdr_unsigned(pref
);
3796 sip
->fs_rtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3797 sip
->fs_wtmax
= txdr_unsigned(NFS_MAXDATA
);
3798 sip
->fs_wtpref
= txdr_unsigned(pref
);
3799 sip
->fs_wtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3800 sip
->fs_dtpref
= txdr_unsigned(pref
);
3801 txdr_hyper(maxfsize
, &sip
->fs_maxfilesize
);
3802 sip
->fs_timedelta
.nfsv3_sec
= 0;
3803 sip
->fs_timedelta
.nfsv3_nsec
= txdr_unsigned(1);
3804 sip
->fs_properties
= txdr_unsigned(NFSV3FSINFO_LINK
|
3805 NFSV3FSINFO_SYMLINK
| NFSV3FSINFO_HOMOGENEOUS
|
3806 NFSV3FSINFO_CANSETTIME
);
3815 * nfs pathconf service
3818 nfsrv_pathconf(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3819 struct thread
*td
, struct mbuf
**mrq
)
3821 struct sockaddr
*nam
= nfsd
->nd_nam
;
3822 struct ucred
*cred
= &nfsd
->nd_cr
;
3823 struct nfsv3_pathconf
*pc
;
3824 int error
= 0, rdonly
, getret
= 1;
3825 register_t linkmax
, namemax
, chownres
, notrunc
;
3826 struct vnode
*vp
= NULL
;
3827 struct mount
*mp
= NULL
;
3831 struct nfsm_info info
;
3833 info
.mrep
= nfsd
->nd_mrep
;
3835 info
.md
= nfsd
->nd_md
;
3836 info
.dpos
= nfsd
->nd_dpos
;
3838 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3839 fhp
= &nfh
.fh_generic
;
3840 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
3841 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3842 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3844 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_UNSIGNED
, &error
));
3845 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3849 error
= VOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
);
3851 error
= VOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
);
3853 error
= VOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
);
3855 error
= VOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
);
3856 getret
= VOP_GETATTR(vp
, &at
);
3859 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3860 NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
,
3862 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3867 pc
= nfsm_build(&info
, NFSX_V3PATHCONF
);
3869 pc
->pc_linkmax
= txdr_unsigned(linkmax
);
3870 pc
->pc_namemax
= txdr_unsigned(namemax
);
3871 pc
->pc_notrunc
= txdr_unsigned(notrunc
);
3872 pc
->pc_chownrestricted
= txdr_unsigned(chownres
);
3875 * These should probably be supported by VOP_PATHCONF(), but
3876 * until msdosfs is exportable (why would you want to?), the
3877 * Unix defaults should be ok.
3879 pc
->pc_caseinsensitive
= nfs_false
;
3880 pc
->pc_casepreserving
= nfs_true
;
3889 * Null operation, used by clients to ping server
3893 nfsrv_null(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3894 struct thread
*td
, struct mbuf
**mrq
)
3896 struct nfsm_info info
;
3897 int error
= NFSERR_RETVOID
;
3899 info
.mrep
= nfsd
->nd_mrep
;
3902 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3903 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, 0, &error
));
3910 * No operation, used for obsolete procedures
3914 nfsrv_noop(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3915 struct thread
*td
, struct mbuf
**mrq
)
3917 struct nfsm_info info
;
3920 info
.mrep
= nfsd
->nd_mrep
;
3923 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3924 if (nfsd
->nd_repstat
)
3925 error
= nfsd
->nd_repstat
;
3927 error
= EPROCUNAVAIL
;
3928 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, 0, &error
));
3936 * Perform access checking for vnodes obtained from file handles that would
3937 * refer to files already opened by a Unix client. You cannot just use
3938 * vn_writechk() and VOP_ACCESS() for two reasons.
3939 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3940 * 2 - The owner is to be given access irrespective of mode bits for some
3941 * operations, so that processes that chmod after opening a file don't
3942 * break. I don't like this because it opens a security hole, but since
3943 * the nfs server opens a security hole the size of a barn door anyhow,
3946 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
3947 * will return EPERM instead of EACCESS. EPERM is always an error.
3950 nfsrv_access(struct mount
*mp
, struct vnode
*vp
, int flags
, struct ucred
*cred
,
3951 int rdonly
, struct thread
*td
, int override
)
3956 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3957 if (flags
& VWRITE
) {
3958 /* Just vn_writechk() changed to check rdonly */
3960 * Disallow write attempts on read-only file systems;
3961 * unless the file is a socket or a block or character
3962 * device resident on the file system.
3965 ((mp
->mnt_flag
| vp
->v_mount
->mnt_flag
) & MNT_RDONLY
)) {
3966 switch (vp
->v_type
) {
3976 * If there's shared text associated with
3977 * the inode, we can't allow writing.
3979 if (vp
->v_flag
& VTEXT
)
3982 error
= VOP_GETATTR(vp
, &vattr
);
3985 error
= VOP_ACCESS(vp
, flags
, cred
);
3987 * Allow certain operations for the owner (reads and writes
3988 * on files that are already open).
3990 if (override
&& error
== EACCES
&& cred
->cr_uid
== vattr
.va_uid
)
3994 #endif /* NFS_NOSERVER */