1 /* $NetBSD: nfs_serv.c,v 1.149 2009/12/23 01:09:25 pooka Exp $ */
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * @(#)nfs_serv.c 8.8 (Berkeley) 7/31/95
38 * nfs version 2 and 3 server calls to vnode ops
39 * - these routines generally have 3 phases
40 * 1 - break down and validate rpc request in mbuf list
41 * 2 - do the vnode ops for the request
42 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
43 * 3 - build the rpc reply in an mbuf list
45 * - do not mix the phases, since the nfsm_?? macros can return failures
46 * on a bad rpc or similar and do not do any vrele() or vput()'s
48 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
49 * error number iff error != 0 whereas
50 * returning an error from the server function implies a fatal error
51 * such as a badly constructed rpc request that should be dropped without
53 * For Version 3, nfsm_reply() does not return for the error case, since
54 * most version 3 rpcs return more than the status for error cases.
57 #include <sys/cdefs.h>
58 __KERNEL_RCSID(0, "$NetBSD: nfs_serv.c,v 1.149 2009/12/23 01:09:25 pooka Exp $");
60 #include <sys/param.h>
61 #include <sys/systm.h>
64 #include <sys/namei.h>
65 #include <sys/vnode.h>
66 #include <sys/mount.h>
67 #include <sys/socket.h>
68 #include <sys/socketvar.h>
70 #include <sys/dirent.h>
72 #include <sys/kernel.h>
74 #include <sys/kauth.h>
75 #include <sys/module.h>
76 #include <sys/syscall.h>
77 #include <sys/syscallargs.h>
78 #include <sys/syscallvar.h>
82 #include <nfs/nfsproto.h>
83 #include <nfs/rpcv2.h>
85 #include <nfs/xdr_subs.h>
86 #include <nfs/nfsm_subs.h>
87 #include <nfs/nfs_var.h>
89 MODULE(MODULE_CLASS_MISC
, nfsserver
, "nfs");
92 extern u_int32_t nfs_xdrneg1
;
93 extern u_int32_t nfs_false
, nfs_true
;
94 extern const enum vtype nv3tov_type
[8];
95 extern struct nfsstats nfsstats
;
96 extern const nfstype nfsv2_type
[9];
97 extern const nfstype nfsv3_type
[9];
98 int nfsrvw_procrastinate
= NFS_GATHERDELAY
* 1000;
99 bool nfsd_use_loan
= true; /* use page-loan for READ OP */
101 #define nqsrv_getl(vp, rw) /* nothing */
103 static const struct syscall_package nfsserver_syscalls
[] = {
104 { SYS_nfssvc
, 0, (sy_call_t
*)sys_nfssvc
},
109 nfsserver_modcmd(modcmd_t cmd
, void *arg
)
111 extern struct vfs_hooks nfs_export_hooks
; /* XXX */
115 case MODULE_CMD_INIT
:
116 error
= syscall_establish(NULL
, nfsserver_syscalls
);
120 nfs_init(); /* XXX for monolithic kernel */
122 nfsrv_initcache(); /* Init the server request cache */
123 nfsrv_init(0); /* Init server data structures */
124 vfs_hooks_attach(&nfs_export_hooks
);
125 nfs_timer_srvinit(nfsrv_timer
);
127 case MODULE_CMD_FINI
:
128 error
= syscall_disestablish(NULL
, nfsserver_syscalls
);
133 * Kill export list before detaching VFS hooks, so we
134 * we don't leak state due to a concurrent umount().
137 vfs_hooks_detach(&nfs_export_hooks
);
139 /* Kill timer before server goes away. */
143 /* Server uses server cache, so kill cache last. */
152 * nfs v3 access service
155 nfsrv3_access(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
157 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
158 struct mbuf
*nam
= nfsd
->nd_nam
;
159 char *dpos
= nfsd
->nd_dpos
;
160 kauth_cred_t cred
= nfsd
->nd_cr
;
166 int error
= 0, rdonly
, cache
= 0, getret
;
168 struct mbuf
*mb
, *mreq
;
170 u_long inmode
, testmode
, outmode
;
173 nfsm_srvmtofh(&nsfh
);
174 nfsm_dissect(tl
, u_int32_t
*, NFSX_UNSIGNED
);
175 error
= nfsrv_fhtovp(&nsfh
, 1, &vp
, cred
, slp
, nam
, &rdonly
,
176 (nfsd
->nd_flag
& ND_KERBAUTH
), false);
178 nfsm_reply(NFSX_UNSIGNED
);
179 nfsm_srvpostop_attr(1, (struct vattr
*)0);
182 inmode
= fxdr_unsigned(u_int32_t
, *tl
);
184 if ((inmode
& NFSV3ACCESS_READ
) &&
185 nfsrv_access(vp
, VREAD
, cred
, rdonly
, lwp
, 0) == 0)
186 outmode
|= NFSV3ACCESS_READ
;
187 if (vp
->v_type
!= VDIR
) {
188 testmode
= inmode
& (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
);
190 nfsrv_access(vp
, VWRITE
, cred
, rdonly
, lwp
, 0) == 0)
192 if ((inmode
& NFSV3ACCESS_EXECUTE
) &&
193 nfsrv_access(vp
, VEXEC
, cred
, rdonly
, lwp
, 0) == 0)
194 outmode
|= NFSV3ACCESS_EXECUTE
;
196 testmode
= inmode
& (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
|
199 nfsrv_access(vp
, VWRITE
, cred
, rdonly
, lwp
, 0) == 0)
201 if ((inmode
& NFSV3ACCESS_LOOKUP
) &&
202 nfsrv_access(vp
, VEXEC
, cred
, rdonly
, lwp
, 0) == 0)
203 outmode
|= NFSV3ACCESS_LOOKUP
;
205 getret
= VOP_GETATTR(vp
, &va
, cred
);
207 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED
);
208 nfsm_srvpostop_attr(getret
, &va
);
209 nfsm_build(tl
, u_int32_t
*, NFSX_UNSIGNED
);
210 *tl
= txdr_unsigned(outmode
);
215 * nfs getattr service
218 nfsrv_getattr(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
220 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
221 struct mbuf
*nam
= nfsd
->nd_nam
;
222 char *dpos
= nfsd
->nd_dpos
;
223 kauth_cred_t cred
= nfsd
->nd_cr
;
224 struct nfs_fattr
*fp
;
231 int error
= 0, rdonly
, cache
= 0;
233 struct mbuf
*mb
, *mreq
;
236 nfsm_srvmtofh(&nsfh
);
237 error
= nfsrv_fhtovp(&nsfh
, 1, &vp
, cred
, slp
, nam
, &rdonly
,
238 (nfsd
->nd_flag
& ND_KERBAUTH
), false);
243 nqsrv_getl(vp
, ND_READ
);
244 error
= VOP_GETATTR(vp
, &va
, cred
);
246 nfsm_reply(NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
249 nfsm_build(fp
, struct nfs_fattr
*, NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
250 nfsm_srvfillattr(&va
, fp
);
255 * nfs setattr service
258 nfsrv_setattr(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
260 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
261 struct mbuf
*nam
= nfsd
->nd_nam
;
262 char *dpos
= nfsd
->nd_dpos
;
263 kauth_cred_t cred
= nfsd
->nd_cr
;
264 struct vattr va
, preat
;
265 struct nfsv2_sattr
*sp
;
266 struct nfs_fattr
*fp
;
272 int error
= 0, rdonly
, cache
= 0, preat_ret
= 1, postat_ret
= 1;
273 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), gcheck
= 0;
275 struct mbuf
*mb
, *mreq
;
277 struct timespec guard
;
279 memset(&guard
, 0, sizeof guard
); /* XXX gcc */
281 nfsm_srvmtofh(&nsfh
);
285 nfsm_dissect(tl
, u_int32_t
*, NFSX_UNSIGNED
);
286 gcheck
= fxdr_unsigned(int, *tl
);
288 nfsm_dissect(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
289 fxdr_nfsv3time(tl
, &guard
);
292 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
294 * Nah nah nah nah na nah
295 * There is a bug in the Sun client that puts 0xffff in the mode
296 * field of sattr when it should put in 0xffffffff. The u_short
297 * doesn't sign extend.
298 * --> check the low order 2 bytes for 0xffff
300 if ((fxdr_unsigned(int, sp
->sa_mode
) & 0xffff) != 0xffff)
301 va
.va_mode
= nfstov_mode(sp
->sa_mode
);
302 if (sp
->sa_uid
!= nfs_xdrneg1
)
303 va
.va_uid
= fxdr_unsigned(uid_t
, sp
->sa_uid
);
304 if (sp
->sa_gid
!= nfs_xdrneg1
)
305 va
.va_gid
= fxdr_unsigned(gid_t
, sp
->sa_gid
);
306 if (sp
->sa_size
!= nfs_xdrneg1
)
307 va
.va_size
= fxdr_unsigned(u_quad_t
, sp
->sa_size
);
308 if (sp
->sa_atime
.nfsv2_sec
!= nfs_xdrneg1
) {
310 fxdr_nfsv2time(&sp
->sa_atime
, &va
.va_atime
);
313 fxdr_unsigned(u_int32_t
,sp
->sa_atime
.nfsv2_sec
);
314 va
.va_atime
.tv_nsec
= 0;
317 if (sp
->sa_mtime
.nfsv2_sec
!= nfs_xdrneg1
)
318 fxdr_nfsv2time(&sp
->sa_mtime
, &va
.va_mtime
);
323 * Now that we have all the fields, lets do it.
325 error
= nfsrv_fhtovp(&nsfh
, 1, &vp
, cred
, slp
, nam
, &rdonly
,
326 (nfsd
->nd_flag
& ND_KERBAUTH
), false);
328 nfsm_reply(2 * NFSX_UNSIGNED
);
329 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &va
);
332 nqsrv_getl(vp
, ND_WRITE
);
334 error
= preat_ret
= VOP_GETATTR(vp
, &preat
, cred
);
335 if (!error
&& gcheck
&&
336 (preat
.va_ctime
.tv_sec
!= guard
.tv_sec
||
337 preat
.va_ctime
.tv_nsec
!= guard
.tv_nsec
))
338 error
= NFSERR_NOT_SYNC
;
341 nfsm_reply(NFSX_WCCDATA(v3
));
342 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &va
);
348 * If the size is being changed write acces is required, otherwise
349 * just check for a read only file system.
351 if (va
.va_size
== ((u_quad_t
)((quad_t
) -1))) {
352 if (rdonly
|| (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
357 if (vp
->v_type
== VDIR
) {
360 } else if ((error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
,
364 error
= VOP_SETATTR(vp
, &va
, cred
);
365 postat_ret
= VOP_GETATTR(vp
, &va
, cred
);
370 nfsm_reply(NFSX_WCCORFATTR(v3
));
372 nfsm_srvwcc_data(preat_ret
, &preat
, postat_ret
, &va
);
375 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
376 nfsm_srvfillattr(&va
, fp
);
385 nfsrv_lookup(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
387 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
388 struct mbuf
*nam
= nfsd
->nd_nam
;
389 char *dpos
= nfsd
->nd_dpos
;
390 kauth_cred_t cred
= nfsd
->nd_cr
;
391 struct nfs_fattr
*fp
;
392 struct nameidata nd
, ind
, *ndp
= &nd
;
393 struct vnode
*vp
, *dirp
;
399 int error
= 0, cache
= 0, dirattr_ret
= 1;
401 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), pubflag
;
403 struct mbuf
*mb
, *mreq
;
404 struct vattr va
, dirattr
;
407 nfsm_srvmtofh(&nsfh
);
408 nfsm_srvnamesiz(len
);
410 pubflag
= nfs_ispublicfh(&nsfh
);
412 nd
.ni_cnd
.cn_cred
= cred
;
413 nd
.ni_cnd
.cn_nameiop
= LOOKUP
;
414 nd
.ni_cnd
.cn_flags
= LOCKLEAF
| SAVESTART
;
415 error
= nfs_namei(&nd
, &nsfh
, len
, slp
, nam
, &md
, &dpos
,
416 &dirp
, lwp
, (nfsd
->nd_flag
& ND_KERBAUTH
), pubflag
);
418 if (!error
&& pubflag
) {
419 if (nd
.ni_vp
->v_type
== VDIR
&& nfs_pub
.np_index
!= NULL
) {
421 * Setup call to lookup() to see if we can find
422 * the index file. Arguably, this doesn't belong
426 VOP_UNLOCK(nd
.ni_vp
, 0);
427 ind
.ni_pathlen
= strlen(nfs_pub
.np_index
);
428 ind
.ni_cnd
.cn_nameptr
= ind
.ni_cnd
.cn_pnbuf
=
430 ind
.ni_startdir
= nd
.ni_vp
;
431 vref(ind
.ni_startdir
);
432 error
= lookup_for_nfsd_index(&ind
);
435 * Found an index file. Get rid of
436 * the old references.
441 vrele(nd
.ni_startdir
);
447 * If the public filehandle was used, check that this lookup
448 * didn't result in a filehandle outside the publicly exported
452 if (!error
&& ndp
->ni_vp
->v_mount
!= nfs_pub
.np_mount
) {
460 dirattr_ret
= VOP_GETATTR(dirp
, &dirattr
, cred
);
465 nfsm_reply(NFSX_POSTOPATTR(v3
));
466 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
470 nqsrv_getl(ndp
->ni_startdir
, ND_READ
);
471 PNBUF_PUT(nd
.ni_cnd
.cn_pnbuf
);
473 error
= nfsrv_composefh(vp
, &nsfh
, v3
);
475 error
= VOP_GETATTR(vp
, &va
, cred
);
477 vrele(ndp
->ni_startdir
);
478 nfsm_reply(NFSX_SRVFH(&nsfh
, v3
) + NFSX_POSTOPORFATTR(v3
) +
479 NFSX_POSTOPATTR(v3
));
481 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
484 nfsm_srvfhtom(&nsfh
, v3
);
486 nfsm_srvpostop_attr(0, &va
);
487 nfsm_srvpostop_attr(dirattr_ret
, &dirattr
);
489 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
490 nfsm_srvfillattr(&va
, fp
);
496 * nfs readlink service
499 nfsrv_readlink(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
501 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
502 struct mbuf
*nam
= nfsd
->nd_nam
;
503 char *dpos
= nfsd
->nd_dpos
;
504 kauth_cred_t cred
= nfsd
->nd_cr
;
505 struct iovec iv
[(NFS_MAXPATHLEN
+MLEN
-1)/MLEN
];
506 struct iovec
*ivp
= iv
;
511 int error
= 0, rdonly
, cache
= 0, i
, padlen
, getret
;
513 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
515 struct mbuf
*mb
, *mp2
= NULL
, *mp3
= NULL
, *mreq
;
519 struct uio io
, *uiop
= &io
;
522 nfsm_srvmtofh(&nsfh
);
525 while (len
< NFS_MAXPATHLEN
) {
526 mp
= m_get(M_WAIT
, MT_DATA
);
527 MCLAIM(mp
, &nfs_mowner
);
529 mp
->m_len
= NFSMSIZ(mp
);
536 if ((len
+mp
->m_len
) > NFS_MAXPATHLEN
) {
537 mp
->m_len
= NFS_MAXPATHLEN
-len
;
538 len
= NFS_MAXPATHLEN
;
541 ivp
->iov_base
= mtod(mp
, void *);
542 ivp
->iov_len
= mp
->m_len
;
547 uiop
->uio_iovcnt
= i
;
548 uiop
->uio_offset
= 0;
549 uiop
->uio_resid
= len
;
550 uiop
->uio_rw
= UIO_READ
;
551 UIO_SETUP_SYSSPACE(uiop
);
552 error
= nfsrv_fhtovp(&nsfh
, 1, &vp
, cred
, slp
, nam
,
553 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
556 nfsm_reply(2 * NFSX_UNSIGNED
);
557 nfsm_srvpostop_attr(1, (struct vattr
*)0);
560 if (vp
->v_type
!= VLNK
) {
567 nqsrv_getl(vp
, ND_READ
);
568 error
= VOP_READLINK(vp
, uiop
, cred
);
570 getret
= VOP_GETATTR(vp
, &attr
, cred
);
574 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_UNSIGNED
);
576 nfsm_srvpostop_attr(getret
, &attr
);
580 len
-= uiop
->uio_resid
;
581 padlen
= nfsm_padlen(len
);
582 if (uiop
->uio_resid
|| padlen
)
583 nfs_zeropad(mp3
, uiop
->uio_resid
, padlen
);
584 nfsm_build(tl
, u_int32_t
*, NFSX_UNSIGNED
);
585 *tl
= txdr_unsigned(len
);
594 nfsrv_read(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
596 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
597 struct mbuf
*nam
= nfsd
->nd_nam
;
598 char *dpos
= nfsd
->nd_dpos
;
599 kauth_cred_t cred
= nfsd
->nd_cr
;
601 struct nfs_fattr
*fp
;
606 int error
= 0, rdonly
, cache
= 0, getret
;
607 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
608 uint32_t reqlen
, len
, cnt
, left
;
611 struct mbuf
*mb
, *mreq
;
614 struct uio io
, *uiop
= &io
;
619 nfsm_srvmtofh(&nsfh
);
621 nfsm_dissect(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
622 off
= fxdr_hyper(tl
);
624 nfsm_dissect(tl
, u_int32_t
*, NFSX_UNSIGNED
);
625 off
= (off_t
)fxdr_unsigned(u_int32_t
, *tl
);
627 nfsm_dissect(tl
, uint32_t *, NFSX_UNSIGNED
);
628 reqlen
= fxdr_unsigned(uint32_t, *tl
);
629 reqlen
= MIN(reqlen
, NFS_SRVMAXDATA(nfsd
));
630 error
= nfsrv_fhtovp(&nsfh
, 1, &vp
, cred
, slp
, nam
,
631 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
633 nfsm_reply(2 * NFSX_UNSIGNED
);
634 nfsm_srvpostop_attr(1, (struct vattr
*)0);
637 if (vp
->v_type
!= VREG
) {
641 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
644 nqsrv_getl(vp
, ND_READ
);
645 if ((error
= nfsrv_access(vp
, VREAD
, cred
, rdonly
, lwp
, 1)) != 0)
646 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, lwp
, 1);
648 getret
= VOP_GETATTR(vp
, &va
, cred
);
653 nfsm_reply(NFSX_POSTOPATTR(v3
));
654 nfsm_srvpostop_attr(getret
, &va
);
657 if (off
>= va
.va_size
)
659 else if ((off
+ reqlen
) > va
.va_size
)
660 cnt
= va
.va_size
- off
;
663 nfsm_reply(NFSX_POSTOPORFATTR(v3
) + 3 * NFSX_UNSIGNED
+nfsm_rndup(cnt
));
665 nfsm_build(tl
, u_int32_t
*, NFSX_V3FATTR
+ 4 * NFSX_UNSIGNED
);
667 fp
= (struct nfs_fattr
*)tl
;
668 tl
+= (NFSX_V3FATTR
/ sizeof (u_int32_t
));
670 nfsm_build(tl
, u_int32_t
*, NFSX_V2FATTR
+ NFSX_UNSIGNED
);
671 fp
= (struct nfs_fattr
*)tl
;
672 tl
+= (NFSX_V2FATTR
/ sizeof (u_int32_t
));
677 struct vm_page
**pgpp
;
678 voff_t pgoff
= trunc_page(off
);
682 npages
= (round_page(off
+ cnt
) - pgoff
) >> PAGE_SHIFT
;
683 KASSERT(npages
<= M_EXT_MAXPAGES
); /* XXX */
685 /* allocate kva for mbuf data */
686 lva
= sokvaalloc(npages
<< PAGE_SHIFT
, slp
->ns_so
);
688 /* fall back to VOP_READ */
693 m
= m_get(M_WAIT
, MT_DATA
);
694 MCLAIM(m
, &nfs_mowner
);
695 pgpp
= m
->m_ext
.ext_pgs
;
698 error
= uvm_loanuobjpages(&vp
->v_uobj
, pgoff
, npages
,
701 sokvafree(lva
, npages
<< PAGE_SHIFT
);
708 /* associate kva to mbuf */
709 MEXTADD(m
, (void *)(lva
+ ((vaddr_t
)off
& PAGE_MASK
)),
710 cnt
, M_MBUF
, soloanfree
, slp
->ns_so
);
711 m
->m_flags
|= M_EXT_PAGES
| M_EXT_ROMAP
;
715 for (i
= 0; i
< npages
; i
++) {
716 pmap_kenter_pa(lva
, VM_PAGE_TO_PHYS(pgpp
[i
]),
721 pmap_update(pmap_kernel());
734 * Generate the mbuf list with the uio_iov ref. to it.
739 siz
= min(M_TRAILINGSPACE(m
), left
);
745 m
= m_get(M_WAIT
, MT_DATA
);
746 MCLAIM(m
, &nfs_mowner
);
753 iv
= malloc(i
* sizeof(struct iovec
), M_TEMP
, M_WAITOK
);
754 uiop
->uio_iov
= iv2
= iv
;
760 panic("nfsrv_read iov");
761 siz
= min(M_TRAILINGSPACE(m
), left
);
763 iv
->iov_base
= mtod(m
, char *) +
773 uiop
->uio_iovcnt
= i
;
774 uiop
->uio_offset
= off
;
775 uiop
->uio_resid
= cnt
;
776 uiop
->uio_rw
= UIO_READ
;
777 UIO_SETUP_SYSSPACE(uiop
);
778 error
= VOP_READ(vp
, uiop
, IO_NODELOCKED
, cred
);
779 free((void *)iv2
, M_TEMP
);
782 if (error
|| (getret
= VOP_GETATTR(vp
, &va
, cred
)) != 0){
787 nfsm_reply(NFSX_POSTOPATTR(v3
));
788 nfsm_srvpostop_attr(getret
, &va
);
795 nfsm_srvfillattr(&va
, fp
);
796 len
-= uiop
->uio_resid
;
797 padlen
= nfsm_padlen(len
);
798 if (uiop
->uio_resid
|| padlen
)
799 nfs_zeropad(mb
, uiop
->uio_resid
, padlen
);
802 *tl
++ = txdr_unsigned(len
);
804 if (off
+ len
>= va
.va_size
)
809 *tl
= txdr_unsigned(len
);
817 nfsrv_write(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
819 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
820 struct mbuf
*nam
= nfsd
->nd_nam
;
821 char *dpos
= nfsd
->nd_dpos
;
822 kauth_cred_t cred
= nfsd
->nd_cr
;
826 struct nfs_fattr
*fp
;
828 struct vattr va
, forat
;
832 int error
= 0, rdonly
, cache
= 0, len
, forat_ret
= 1;
833 int ioflags
, aftat_ret
= 1, retlen
, zeroing
, adjust
;
834 int stable
= NFSV3WRITE_FILESYNC
;
835 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
837 struct mbuf
*mb
, *mreq
;
840 struct uio io
, *uiop
= &io
;
848 nfsm_srvmtofh(&nsfh
);
850 nfsm_dissect(tl
, u_int32_t
*, 5 * NFSX_UNSIGNED
);
851 off
= fxdr_hyper(tl
);
853 stable
= fxdr_unsigned(int, *tl
++);
855 nfsm_dissect(tl
, u_int32_t
*, 4 * NFSX_UNSIGNED
);
856 off
= (off_t
)fxdr_unsigned(u_int32_t
, *++tl
);
859 retlen
= len
= fxdr_unsigned(int32_t, *tl
);
863 * For NFS Version 2, it is not obvious what a write of zero length
864 * should do, but I might as well be consistent with Version 3,
865 * which is to return ok so long as there are no permission problems.
873 adjust
= dpos
- mtod(mp
, char *);
875 if (mp
->m_len
> 0 && adjust
> 0)
880 else if (mp
->m_len
> 0) {
883 mp
->m_len
-= (i
- len
);
892 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
894 nfsm_reply(2 * NFSX_UNSIGNED
);
895 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
898 error
= nfsrv_fhtovp(&nsfh
, 1, &vp
, cred
, slp
, nam
,
899 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
901 nfsm_reply(2 * NFSX_UNSIGNED
);
902 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
906 forat_ret
= VOP_GETATTR(vp
, &forat
, cred
);
907 if (vp
->v_type
!= VREG
) {
911 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
914 nqsrv_getl(vp
, ND_WRITE
);
915 error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
, lwp
, 1);
919 nfsm_reply(NFSX_WCCDATA(v3
));
920 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
925 ivp
= malloc(cnt
* sizeof (struct iovec
), M_TEMP
, M_WAITOK
);
926 uiop
->uio_iov
= iv
= ivp
;
927 uiop
->uio_iovcnt
= cnt
;
931 ivp
->iov_base
= mtod(mp
, void *);
932 ivp
->iov_len
= mp
->m_len
;
940 * The IO_METASYNC flag indicates that all metadata (and not
941 * just enough to ensure data integrity) must be written to
942 * stable storage synchronously.
943 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
945 if (stable
== NFSV3WRITE_UNSTABLE
)
946 ioflags
= IO_NODELOCKED
;
947 else if (stable
== NFSV3WRITE_DATASYNC
)
948 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
950 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
951 uiop
->uio_resid
= len
;
952 uiop
->uio_rw
= UIO_WRITE
;
953 uiop
->uio_offset
= off
;
954 UIO_SETUP_SYSSPACE(uiop
);
955 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
956 nfsstats
.srvvop_writes
++;
959 aftat_ret
= VOP_GETATTR(vp
, &va
, cred
);
963 nfsm_reply(NFSX_PREOPATTR(v3
) + NFSX_POSTOPORFATTR(v3
) +
964 2 * NFSX_UNSIGNED
+ NFSX_WRITEVERF(v3
));
966 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
969 nfsm_build(tl
, u_int32_t
*, 4 * NFSX_UNSIGNED
);
970 *tl
++ = txdr_unsigned(retlen
);
971 if (stable
== NFSV3WRITE_UNSTABLE
)
972 *tl
++ = txdr_unsigned(stable
);
974 *tl
++ = txdr_unsigned(NFSV3WRITE_FILESYNC
);
976 * Actually, there is no need to txdr these fields,
977 * but it may make the values more human readable,
978 * for debugging purposes.
980 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
981 *tl
= txdr_unsigned(boottime
.tv_nsec
/ 1000);
983 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
984 nfsm_srvfillattr(&va
, fp
);
990 * XXX elad: the original NFSW_SAMECRED() macro also made sure the
991 * two nd_flag fields of the descriptors contained
995 nfsrv_samecred(kauth_cred_t cred1
, kauth_cred_t cred2
)
999 if (kauth_cred_geteuid(cred1
) != kauth_cred_geteuid(cred2
))
1001 if (kauth_cred_ngroups(cred1
) != kauth_cred_ngroups(cred2
))
1003 do_ngroups
= kauth_cred_ngroups(cred1
);
1004 for (i
= 0; i
< do_ngroups
; i
++)
1005 if (kauth_cred_group(cred1
, i
) !=
1006 kauth_cred_group(cred2
, i
))
1012 static struct nfsrvw_delayhash
*
1013 nfsrv_nwdelayhash(struct nfssvc_sock
*slp
, const nfsrvfh_t
*nsfh
)
1017 hash
= hash32_buf(NFSRVFH_DATA(nsfh
), NFSRVFH_SIZE(nsfh
),
1019 return &slp
->ns_wdelayhashtbl
[hash
% NFS_WDELAYHASHSIZ
];
1023 * NFS write service with write gathering support. Called when
1024 * nfsrvw_procrastinate > 0.
1025 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1026 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1030 nfsrv_writegather(struct nfsrv_descript
**ndp
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
1035 struct nfsrv_descript
*wp
, *nfsd
, *owp
, *swp
;
1036 struct nfs_fattr
*fp
;
1039 struct nfsrvw_delayhash
*wpp
;
1041 struct vattr va
, forat
;
1045 int error
= 0, rdonly
, cache
= 0, len
= 0, forat_ret
= 1;
1046 int ioflags
, aftat_ret
= 1, adjust
, v3
, zeroing
;
1048 struct mbuf
*mb
, *mreq
, *mrep
, *md
;
1050 struct uio io
, *uiop
= &io
;
1051 u_quad_t frev
, cur_usec
;
1057 mrep
= nfsd
->nd_mrep
;
1059 dpos
= nfsd
->nd_dpos
;
1061 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1062 LIST_INIT(&nfsd
->nd_coalesce
);
1063 nfsd
->nd_mreq
= NULL
;
1064 nfsd
->nd_stable
= NFSV3WRITE_FILESYNC
;
1066 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1067 nfsd
->nd_time
= cur_usec
+ nfsrvw_procrastinate
;
1070 * Now, get the write header..
1072 nfsm_srvmtofh(&nfsd
->nd_fh
);
1074 nfsm_dissect(tl
, u_int32_t
*, 5 * NFSX_UNSIGNED
);
1075 nfsd
->nd_off
= fxdr_hyper(tl
);
1077 nfsd
->nd_stable
= fxdr_unsigned(int, *tl
++);
1079 nfsm_dissect(tl
, u_int32_t
*, 4 * NFSX_UNSIGNED
);
1080 nfsd
->nd_off
= (off_t
)fxdr_unsigned(u_int32_t
, *++tl
);
1083 len
= fxdr_unsigned(int32_t, *tl
);
1085 nfsd
->nd_eoff
= nfsd
->nd_off
+ len
;
1088 * Trim the header out of the mbuf list and trim off any trailing
1089 * junk so that the mbuf list has only the write data.
1097 adjust
= dpos
- mtod(mp
, char *);
1098 mp
->m_len
-= adjust
;
1099 if (mp
->m_len
> 0 && adjust
> 0)
1100 NFSMADV(mp
, adjust
);
1107 mp
->m_len
-= (i
- len
);
1113 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1117 nfsm_writereply(2 * NFSX_UNSIGNED
, v3
);
1119 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1120 nfsd
->nd_mreq
= mreq
;
1121 nfsd
->nd_mrep
= NULL
;
1126 * Add this entry to the hash and time queues.
1129 mutex_enter(&nfsd_lock
);
1130 wp
= LIST_FIRST(&slp
->ns_tq
);
1131 while (wp
&& wp
->nd_time
< nfsd
->nd_time
) {
1133 wp
= LIST_NEXT(wp
, nd_tq
);
1136 LIST_INSERT_AFTER(owp
, nfsd
, nd_tq
);
1138 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1140 if (nfsd
->nd_mrep
) {
1141 wpp
= nfsrv_nwdelayhash(slp
, &nfsd
->nd_fh
);
1143 wp
= LIST_FIRST(wpp
);
1144 while (wp
&& nfsrv_comparefh(&nfsd
->nd_fh
, &wp
->nd_fh
)) {
1146 wp
= LIST_NEXT(wp
, nd_hash
);
1148 while (wp
&& wp
->nd_off
< nfsd
->nd_off
&&
1149 !nfsrv_comparefh(&nfsd
->nd_fh
, &wp
->nd_fh
)) {
1151 wp
= LIST_NEXT(wp
, nd_hash
);
1154 LIST_INSERT_AFTER(owp
, nfsd
, nd_hash
);
1157 * Search the hash list for overlapping entries and
1160 for(; nfsd
&& NFSW_CONTIG(owp
, nfsd
); nfsd
= wp
) {
1161 wp
= LIST_NEXT(nfsd
, nd_hash
);
1162 if (nfsrv_samecred(owp
->nd_cr
, nfsd
->nd_cr
))
1163 nfsrvw_coalesce(owp
, nfsd
);
1166 LIST_INSERT_HEAD(wpp
, nfsd
, nd_hash
);
1169 mutex_exit(&nfsd_lock
);
1173 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1174 * and generate the associated reply mbuf list(s).
1178 cur_usec
= (u_quad_t
)now
.tv_sec
* 1000000 + (u_quad_t
)now
.tv_usec
;
1179 mutex_enter(&nfsd_lock
);
1180 for (nfsd
= LIST_FIRST(&slp
->ns_tq
); nfsd
; nfsd
= owp
) {
1181 owp
= LIST_NEXT(nfsd
, nd_tq
);
1182 if (nfsd
->nd_time
> cur_usec
)
1186 LIST_REMOVE(nfsd
, nd_tq
);
1187 LIST_REMOVE(nfsd
, nd_hash
);
1188 mutex_exit(&nfsd_lock
);
1190 mrep
= nfsd
->nd_mrep
;
1191 nfsd
->nd_mrep
= NULL
;
1193 v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1194 forat_ret
= aftat_ret
= 1;
1195 error
= nfsrv_fhtovp(&nfsd
->nd_fh
, 1, &vp
, cred
, slp
,
1196 nfsd
->nd_nam
, &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
),
1200 forat_ret
= VOP_GETATTR(vp
, &forat
, cred
);
1201 if (vp
->v_type
!= VREG
) {
1205 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
1210 nqsrv_getl(vp
, ND_WRITE
);
1211 error
= nfsrv_access(vp
, VWRITE
, cred
, rdonly
, lwp
, 1);
1214 if (nfsd
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1215 ioflags
= IO_NODELOCKED
;
1216 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
)
1217 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1219 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1220 uiop
->uio_rw
= UIO_WRITE
;
1221 uiop
->uio_offset
= nfsd
->nd_off
;
1222 uiop
->uio_resid
= nfsd
->nd_eoff
- nfsd
->nd_off
;
1223 UIO_SETUP_SYSSPACE(uiop
);
1224 if (uiop
->uio_resid
> 0) {
1232 uiop
->uio_iovcnt
= i
;
1233 iov
= malloc(i
* sizeof (struct iovec
), M_TEMP
, M_WAITOK
);
1234 uiop
->uio_iov
= ivp
= iov
;
1237 if (mp
->m_len
> 0) {
1238 ivp
->iov_base
= mtod(mp
, void *);
1239 ivp
->iov_len
= mp
->m_len
;
1245 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
1246 nfsstats
.srvvop_writes
++;
1248 free((void *)iov
, M_TEMP
);
1252 aftat_ret
= VOP_GETATTR(vp
, &va
, cred
);
1257 * Loop around generating replies for all write rpcs that have
1258 * now been completed.
1263 nfsm_writereply(NFSX_WCCDATA(v3
), v3
);
1265 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1268 nfsm_writereply(NFSX_PREOPATTR(v3
) +
1269 NFSX_POSTOPORFATTR(v3
) + 2 * NFSX_UNSIGNED
+
1270 NFSX_WRITEVERF(v3
), v3
);
1272 nfsm_srvwcc_data(forat_ret
, &forat
, aftat_ret
, &va
);
1273 nfsm_build(tl
, u_int32_t
*, 4 * NFSX_UNSIGNED
);
1274 *tl
++ = txdr_unsigned(nfsd
->nd_len
);
1275 *tl
++ = txdr_unsigned(swp
->nd_stable
);
1277 * Actually, there is no need to txdr these fields,
1278 * but it may make the values more human readable,
1279 * for debugging purposes.
1281 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
1282 *tl
= txdr_unsigned(boottime
.tv_nsec
/ 1000);
1284 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1285 nfsm_srvfillattr(&va
, fp
);
1288 nfsd
->nd_mreq
= mreq
;
1290 panic("nfsrv_write: nd_mrep not free");
1293 * Done. Put it at the head of the timer queue so that
1294 * the final phase can return the reply.
1296 mutex_enter(&nfsd_lock
);
1299 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1301 nfsd
= LIST_FIRST(&swp
->nd_coalesce
);
1303 LIST_REMOVE(nfsd
, nd_tq
);
1305 mutex_exit(&nfsd_lock
);
1309 mutex_enter(&nfsd_lock
);
1310 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1311 mutex_exit(&nfsd_lock
);
1314 mutex_exit(&nfsd_lock
);
1318 * Search for a reply to return.
1320 mutex_enter(&nfsd_lock
);
1321 LIST_FOREACH(nfsd
, &slp
->ns_tq
, nd_tq
) {
1322 if (nfsd
->nd_mreq
) {
1323 LIST_REMOVE(nfsd
, nd_tq
);
1324 *mrq
= nfsd
->nd_mreq
;
1329 mutex_exit(&nfsd_lock
);
1334 * Coalesce the write request nfsd into owp. To do this we must:
1335 * - remove nfsd from the queues
1336 * - merge nfsd->nd_mrep into owp->nd_mrep
1337 * - update the nd_eoff and nd_stable for owp
1338 * - put nfsd on owp's nd_coalesce list
1339 * NB: Must be called at splsoftclock().
1342 nfsrvw_coalesce(struct nfsrv_descript
*owp
, struct nfsrv_descript
*nfsd
)
1346 struct nfsrv_descript
*m
;
1348 KASSERT(mutex_owned(&nfsd_lock
));
1350 LIST_REMOVE(nfsd
, nd_hash
);
1351 LIST_REMOVE(nfsd
, nd_tq
);
1352 if (owp
->nd_eoff
< nfsd
->nd_eoff
) {
1353 overlap
= owp
->nd_eoff
- nfsd
->nd_off
;
1355 panic("nfsrv_coalesce: bad off");
1357 m_adj(nfsd
->nd_mrep
, overlap
);
1361 mp
->m_next
= nfsd
->nd_mrep
;
1362 owp
->nd_eoff
= nfsd
->nd_eoff
;
1364 m_freem(nfsd
->nd_mrep
);
1365 nfsd
->nd_mrep
= NULL
;
1366 if (nfsd
->nd_stable
== NFSV3WRITE_FILESYNC
)
1367 owp
->nd_stable
= NFSV3WRITE_FILESYNC
;
1368 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
&&
1369 owp
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1370 owp
->nd_stable
= NFSV3WRITE_DATASYNC
;
1371 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nfsd
, nd_tq
);
1373 * nfsd might hold coalesce elements! Move them to owp.
1374 * Otherwise, requests may be lost and clients will be stuck.
1376 while ((m
= LIST_FIRST(&nfsd
->nd_coalesce
)) != NULL
) {
1377 LIST_REMOVE(m
, nd_tq
);
1378 LIST_INSERT_HEAD(&owp
->nd_coalesce
, m
, nd_tq
);
1383 * nfs create service
1384 * now does a truncate to 0 length via. setattr if it already exists
1387 nfsrv_create(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
1389 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1390 struct mbuf
*nam
= nfsd
->nd_nam
;
1391 char *dpos
= nfsd
->nd_dpos
;
1392 kauth_cred_t cred
= nfsd
->nd_cr
;
1393 struct nfs_fattr
*fp
;
1394 struct vattr va
, dirfor
, diraft
;
1395 struct nfsv2_sattr
*sp
;
1397 struct nameidata nd
;
1401 int error
= 0, cache
= 0, len
, tsize
, dirfor_ret
= 1, diraft_ret
= 1;
1402 int rdev
= 0, abort
= 0;
1403 int v3
= (nfsd
->nd_flag
& ND_NFSV3
), how
, exclusive_flag
= 0;
1405 struct mbuf
*mb
, *mreq
;
1406 struct vnode
*vp
= NULL
, *dirp
= NULL
;
1408 u_quad_t frev
, tempsize
;
1409 u_char cverf
[NFSX_V3CREATEVERF
];
1411 nd
.ni_cnd
.cn_nameiop
= 0;
1412 nfsm_srvmtofh(&nsfh
);
1413 nfsm_srvnamesiz(len
);
1414 nd
.ni_cnd
.cn_cred
= cred
;
1415 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1416 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1417 error
= nfs_namei(&nd
, &nsfh
, len
, slp
, nam
, &md
, &dpos
,
1418 &dirp
, lwp
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
1420 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
);
1423 nfsm_reply(NFSX_WCCDATA(v3
));
1424 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1433 nfsm_dissect(tl
, u_int32_t
*, NFSX_UNSIGNED
);
1434 how
= fxdr_unsigned(int, *tl
);
1436 case NFSV3CREATE_GUARDED
:
1441 case NFSV3CREATE_UNCHECKED
:
1444 case NFSV3CREATE_EXCLUSIVE
:
1445 nfsm_dissect(cp
, void *, NFSX_V3CREATEVERF
);
1446 memcpy(cverf
, cp
, NFSX_V3CREATEVERF
);
1452 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
1453 va
.va_type
= IFTOVT(fxdr_unsigned(u_int32_t
, sp
->sa_mode
));
1454 if (va
.va_type
== VNON
)
1456 va
.va_mode
= nfstov_mode(sp
->sa_mode
);
1457 switch (va
.va_type
) {
1459 tsize
= fxdr_unsigned(int32_t, sp
->sa_size
);
1461 va
.va_size
= (u_quad_t
)tsize
;
1466 rdev
= fxdr_unsigned(int32_t, sp
->sa_size
);
1474 * Iff doesn't exist, create it
1475 * otherwise just truncate to 0 length
1476 * should I set the mode too ??
1478 if (nd
.ni_vp
== NULL
) {
1479 if (va
.va_type
== VREG
|| va
.va_type
== VSOCK
) {
1480 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1481 error
= VOP_CREATE(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
);
1483 if (exclusive_flag
) {
1488 * assuming NFSX_V3CREATEVERF
1489 * == sizeof(nfstime3)
1491 fxdr_nfsv3time(cverf
, &va
.va_atime
);
1492 error
= VOP_SETATTR(nd
.ni_vp
, &va
,
1496 } else if (va
.va_type
== VCHR
|| va
.va_type
== VBLK
||
1497 va
.va_type
== VFIFO
) {
1498 if (va
.va_type
== VCHR
&& rdev
== 0xffffffff)
1500 if (va
.va_type
!= VFIFO
&&
1501 (error
= kauth_authorize_system(cred
,
1502 KAUTH_SYSTEM_MKNOD
, 0, NULL
, NULL
, NULL
))) {
1503 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1509 va
.va_rdev
= (dev_t
)rdev
;
1510 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1511 error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
,
1516 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
) {
1519 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1525 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1532 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1534 if (nd
.ni_dvp
== vp
)
1539 if (!error
&& va
.va_size
!= -1) {
1540 error
= nfsrv_access(vp
, VWRITE
, cred
,
1541 (nd
.ni_cnd
.cn_flags
& RDONLY
), lwp
, 0);
1543 nqsrv_getl(vp
, ND_WRITE
);
1544 tempsize
= va
.va_size
;
1546 va
.va_size
= tempsize
;
1547 error
= VOP_SETATTR(vp
, &va
, cred
);
1554 error
= nfsrv_composefh(vp
, &nsfh
, v3
);
1556 error
= VOP_GETATTR(vp
, &va
, cred
);
1560 if (exclusive_flag
&& !error
) {
1562 * XXX assuming NFSX_V3CREATEVERF == sizeof(nfstime3)
1564 char oldverf
[NFSX_V3CREATEVERF
];
1566 txdr_nfsv3time(&va
.va_atime
, oldverf
);
1567 if (memcmp(cverf
, oldverf
, NFSX_V3CREATEVERF
))
1571 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
);
1579 nfsm_reply(NFSX_SRVFH(&nsfh
, v3
) + NFSX_FATTR(v3
) + NFSX_WCCDATA(v3
));
1582 nfsm_srvpostop_fh(&nsfh
);
1583 nfsm_srvpostop_attr(0, &va
);
1585 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1587 nfsm_srvfhtom(&nsfh
, v3
);
1588 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
1589 nfsm_srvfillattr(&va
, fp
);
1596 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1597 if (nd
.ni_dvp
== nd
.ni_vp
)
1608 * nfs v3 mknod service
1611 nfsrv_mknod(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
1613 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1614 struct mbuf
*nam
= nfsd
->nd_nam
;
1615 char *dpos
= nfsd
->nd_dpos
;
1616 kauth_cred_t cred
= nfsd
->nd_cr
;
1617 struct vattr va
, dirfor
, diraft
;
1619 struct nameidata nd
;
1622 int error
= 0, cache
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
1624 u_int32_t major
, minor
;
1627 struct mbuf
*mb
, *mreq
;
1628 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
1632 nd
.ni_cnd
.cn_nameiop
= 0;
1633 nfsm_srvmtofh(&nsfh
);
1634 nfsm_srvnamesiz(len
);
1635 nd
.ni_cnd
.cn_cred
= cred
;
1636 nd
.ni_cnd
.cn_nameiop
= CREATE
;
1637 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1638 error
= nfs_namei(&nd
, &nsfh
, len
, slp
, nam
, &md
, &dpos
,
1639 &dirp
, lwp
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
1641 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
);
1643 nfsm_reply(NFSX_WCCDATA(1));
1644 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1650 nfsm_dissect(tl
, u_int32_t
*, NFSX_UNSIGNED
);
1651 vtyp
= nfsv3tov_type(*tl
);
1652 if (vtyp
!= VCHR
&& vtyp
!= VBLK
&& vtyp
!= VSOCK
&& vtyp
!= VFIFO
) {
1653 error
= NFSERR_BADTYPE
;
1659 if (vtyp
== VCHR
|| vtyp
== VBLK
) {
1662 nfsm_dissect(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
1663 major
= fxdr_unsigned(u_int32_t
, *tl
++);
1664 minor
= fxdr_unsigned(u_int32_t
, *tl
);
1665 rdev
= makedev(major
, minor
);
1666 if (major(rdev
) != major
|| minor(rdev
) != minor
) {
1674 * Iff doesn't exist, create it.
1679 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1680 if (nd
.ni_dvp
== nd
.ni_vp
)
1689 if (vtyp
== VSOCK
) {
1690 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1691 error
= VOP_CREATE(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
);
1693 if (va
.va_type
!= VFIFO
&&
1694 (error
= kauth_authorize_system(cred
,
1695 KAUTH_SYSTEM_MKNOD
, 0, NULL
, NULL
, NULL
))) {
1696 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1700 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1701 error
= VOP_MKNOD(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
);
1704 if (nd
.ni_cnd
.cn_flags
& ISSYMLINK
) {
1706 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1713 error
= nfsrv_composefh(vp
, &nsfh
, true);
1715 error
= VOP_GETATTR(vp
, &va
, cred
);
1719 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
);
1724 nfsm_reply(NFSX_SRVFH(&nsfh
, true) + NFSX_POSTOPATTR(1) +
1727 nfsm_srvpostop_fh(&nsfh
);
1728 nfsm_srvpostop_attr(0, &va
);
1730 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1734 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1735 if (nd
.ni_dvp
== nd
.ni_vp
)
1748 * nfs remove service
1751 nfsrv_remove(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
1753 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1754 struct mbuf
*nam
= nfsd
->nd_nam
;
1755 char *dpos
= nfsd
->nd_dpos
;
1756 kauth_cred_t cred
= nfsd
->nd_cr
;
1757 struct nameidata nd
;
1761 int error
= 0, cache
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
1762 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1764 struct mbuf
*mb
, *mreq
;
1765 struct vnode
*vp
, *dirp
;
1766 struct vattr dirfor
, diraft
;
1771 vp
= (struct vnode
*)0;
1773 nfsm_srvmtofh(&nsfh
);
1774 nfsm_srvnamesiz(len
);
1775 nd
.ni_cnd
.cn_cred
= cred
;
1776 nd
.ni_cnd
.cn_nameiop
= DELETE
;
1777 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
1778 error
= nfs_namei(&nd
, &nsfh
, len
, slp
, nam
, &md
, &dpos
,
1779 &dirp
, lwp
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
1781 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
);
1785 if (vp
->v_type
== VDIR
) {
1790 * The root of a mounted filesystem cannot be deleted.
1792 if (vp
->v_vflag
& VV_ROOT
) {
1797 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
1798 nqsrv_getl(vp
, ND_WRITE
);
1799 error
= VOP_REMOVE(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
1801 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
1802 if (nd
.ni_dvp
== vp
)
1811 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
);
1815 nfsm_reply(NFSX_WCCDATA(v3
));
1817 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
1824 * nfs rename service
1827 nfsrv_rename(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
1829 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
1830 struct mbuf
*nam
= nfsd
->nd_nam
;
1831 char *dpos
= nfsd
->nd_dpos
;
1832 kauth_cred_t cred
= nfsd
->nd_cr
;
1836 int error
= 0, cache
= 0, fdirfor_ret
= 1, fdiraft_ret
= 1;
1838 int tdirfor_ret
= 1, tdiraft_ret
= 1;
1839 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1841 struct mbuf
*mb
, *mreq
;
1842 struct nameidata fromnd
, tond
;
1843 struct vnode
*fvp
, *tvp
, *tdvp
;
1844 struct vnode
*fdirp
= NULL
, *tdirp
= NULL
;
1845 struct mount
*localfs
= NULL
;
1846 struct vattr fdirfor
, fdiraft
, tdirfor
, tdiraft
;
1847 nfsrvfh_t fnsfh
, tnsfh
;
1853 fvp
= (struct vnode
*)0;
1855 fromnd
.ni_cnd
.cn_nameiop
= 0;
1856 tond
.ni_cnd
.cn_nameiop
= 0;
1857 nfsm_srvmtofh(&fnsfh
);
1858 nfsm_srvnamesiz(len
);
1860 * Remember our original uid so that we can reset cr_uid before
1861 * the second nfs_namei() call, in case it is remapped.
1863 saved_uid
= kauth_cred_geteuid(cred
);
1864 fromnd
.ni_cnd
.cn_cred
= cred
;
1865 fromnd
.ni_cnd
.cn_nameiop
= DELETE
;
1866 fromnd
.ni_cnd
.cn_flags
= LOCKPARENT
| SAVESTART
| INRENAME
;
1867 error
= nfs_namei(&fromnd
, &fnsfh
, len
, slp
, nam
, &md
,
1868 &dpos
, &fdirp
, lwp
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
1870 fdirfor_ret
= VOP_GETATTR(fdirp
, &fdirfor
, cred
);
1873 nfsm_reply(2 * NFSX_WCCDATA(v3
));
1874 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
1875 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
1880 if (fromnd
.ni_dvp
!= fromnd
.ni_vp
) {
1881 VOP_UNLOCK(fromnd
.ni_dvp
, 0);
1885 localfs
= fvp
->v_mount
;
1886 error
= VFS_RENAMELOCK_ENTER(localfs
);
1888 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
1889 vrele(fromnd
.ni_dvp
);
1894 /* Copied, regrettably, from vfs_syscalls.c (q.v.) */
1896 if ((fromnd
.ni_cnd
.cn_namelen
== 1 &&
1897 fromnd
.ni_cnd
.cn_nameptr
[0] == '.') ||
1898 (fromnd
.ni_cnd
.cn_namelen
== 2 &&
1899 fromnd
.ni_cnd
.cn_nameptr
[0] == '.' &&
1900 fromnd
.ni_cnd
.cn_nameptr
[1] == '.')) {
1902 VFS_RENAMELOCK_EXIT(localfs
);
1903 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
1904 vrele(fromnd
.ni_dvp
);
1907 saveflag
= fromnd
.ni_cnd
.cn_flags
& SAVESTART
;
1908 fromnd
.ni_cnd
.cn_flags
&= ~SAVESTART
;
1909 vn_lock(fromnd
.ni_dvp
, LK_EXCLUSIVE
| LK_RETRY
);
1910 error
= relookup(fromnd
.ni_dvp
, &fromnd
.ni_vp
, &fromnd
.ni_cnd
);
1911 fromnd
.ni_cnd
.cn_flags
|= saveflag
;
1913 VOP_UNLOCK(fromnd
.ni_dvp
, 0);
1914 VFS_RENAMELOCK_EXIT(localfs
);
1915 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
1916 vrele(fromnd
.ni_dvp
);
1919 VOP_UNLOCK(fromnd
.ni_vp
, 0);
1920 if (fromnd
.ni_dvp
!= fromnd
.ni_vp
)
1921 VOP_UNLOCK(fromnd
.ni_dvp
, 0);
1924 nfsm_srvmtofh(&tnsfh
);
1926 nfsm_dissect(tl
, uint32_t *, NFSX_UNSIGNED
);
1927 len2
= fxdr_unsigned(uint32_t, *tl
);
1928 /* len2 will be checked by nfs_namei */
1932 nfsm_strsiz(len2
, NFS_MAXNAMLEN
);
1934 kauth_cred_seteuid(cred
, saved_uid
);
1935 tond
.ni_cnd
.cn_cred
= cred
;
1936 tond
.ni_cnd
.cn_nameiop
= RENAME
;
1937 tond
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
| NOCACHE
|
1938 SAVESTART
| INRENAME
;
1939 error
= nfs_namei(&tond
, &tnsfh
, len2
, slp
, nam
, &md
,
1940 &dpos
, &tdirp
, lwp
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
1942 tdirfor_ret
= VOP_GETATTR(tdirp
, &tdirfor
, cred
);
1945 VFS_RENAMELOCK_EXIT(localfs
);
1946 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
1947 vrele(fromnd
.ni_dvp
);
1954 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
1960 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
1967 if (tvp
->v_type
== VDIR
&& tvp
->v_mountedhere
) {
1975 if (fvp
->v_type
== VDIR
&& fvp
->v_mountedhere
) {
1982 if (fvp
->v_mount
!= tdvp
->v_mount
) {
1996 * If source is the same as the destination (that is the
1997 * same vnode with the same name in the same directory),
1998 * then there is nothing to do.
2000 if (fvp
== tvp
&& fromnd
.ni_dvp
== tdvp
&&
2001 fromnd
.ni_cnd
.cn_namelen
== tond
.ni_cnd
.cn_namelen
&&
2002 !memcmp(fromnd
.ni_cnd
.cn_nameptr
, tond
.ni_cnd
.cn_nameptr
,
2003 fromnd
.ni_cnd
.cn_namelen
))
2007 nqsrv_getl(fromnd
.ni_dvp
, ND_WRITE
);
2008 nqsrv_getl(tdvp
, ND_WRITE
);
2010 nqsrv_getl(tvp
, ND_WRITE
);
2012 error
= VOP_RENAME(fromnd
.ni_dvp
, fromnd
.ni_vp
, &fromnd
.ni_cnd
,
2013 tond
.ni_dvp
, tond
.ni_vp
, &tond
.ni_cnd
);
2014 VFS_RENAMELOCK_EXIT(localfs
);
2016 VOP_ABORTOP(tond
.ni_dvp
, &tond
.ni_cnd
);
2023 VFS_RENAMELOCK_EXIT(localfs
);
2024 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2025 vrele(fromnd
.ni_dvp
);
2030 vrele(tond
.ni_startdir
);
2031 PNBUF_PUT(tond
.ni_cnd
.cn_pnbuf
);
2032 tond
.ni_cnd
.cn_nameiop
= 0;
2036 fdiraft_ret
= VOP_GETATTR(fdirp
, &fdiraft
, cred
);
2043 tdiraft_ret
= VOP_GETATTR(tdirp
, &tdiraft
, cred
);
2048 vrele(fromnd
.ni_startdir
);
2049 PNBUF_PUT(fromnd
.ni_cnd
.cn_pnbuf
);
2050 fromnd
.ni_cnd
.cn_nameiop
= 0;
2052 nfsm_reply(2 * NFSX_WCCDATA(v3
));
2054 nfsm_srvwcc_data(fdirfor_ret
, &fdirfor
, fdiraft_ret
, &fdiraft
);
2055 nfsm_srvwcc_data(tdirfor_ret
, &tdirfor
, tdiraft_ret
, &tdiraft
);
2066 if (tond
.ni_cnd
.cn_nameiop
) {
2067 vrele(tond
.ni_startdir
);
2068 PNBUF_PUT(tond
.ni_cnd
.cn_pnbuf
);
2071 VFS_RENAMELOCK_EXIT(localfs
);
2073 if (fromnd
.ni_cnd
.cn_nameiop
) {
2074 vrele(fromnd
.ni_startdir
);
2075 PNBUF_PUT(fromnd
.ni_cnd
.cn_pnbuf
);
2076 VOP_ABORTOP(fromnd
.ni_dvp
, &fromnd
.ni_cnd
);
2077 vrele(fromnd
.ni_dvp
);
2087 nfsrv_link(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
2089 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2090 struct mbuf
*nam
= nfsd
->nd_nam
;
2091 char *dpos
= nfsd
->nd_dpos
;
2092 kauth_cred_t cred
= nfsd
->nd_cr
;
2093 struct nameidata nd
;
2097 int error
= 0, rdonly
, cache
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2098 int getret
= 1, v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2100 struct mbuf
*mb
, *mreq
;
2101 struct vnode
*vp
, *xp
, *dirp
= (struct vnode
*)0;
2102 struct vattr dirfor
, diraft
, at
;
2103 nfsrvfh_t nsfh
, dnsfh
;
2106 nfsm_srvmtofh(&nsfh
);
2107 nfsm_srvmtofh(&dnsfh
);
2108 nfsm_srvnamesiz(len
);
2109 error
= nfsrv_fhtovp(&nsfh
, false, &vp
, cred
, slp
, nam
,
2110 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
2112 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2113 nfsm_srvpostop_attr(getret
, &at
);
2114 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2117 if (vp
->v_type
== VDIR
) {
2121 nd
.ni_cnd
.cn_cred
= cred
;
2122 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2123 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2124 error
= nfs_namei(&nd
, &dnsfh
, len
, slp
, nam
, &md
, &dpos
,
2125 &dirp
, lwp
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
2127 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
);
2137 if (vp
->v_mount
!= xp
->v_mount
)
2141 nqsrv_getl(vp
, ND_WRITE
);
2142 nqsrv_getl(xp
, ND_WRITE
);
2143 error
= VOP_LINK(nd
.ni_dvp
, vp
, &nd
.ni_cnd
);
2145 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2146 if (nd
.ni_dvp
== nd
.ni_vp
)
2155 getret
= VOP_GETATTR(vp
, &at
, cred
);
2158 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
);
2163 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_WCCDATA(v3
));
2165 nfsm_srvpostop_attr(getret
, &at
);
2166 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2173 * nfs symbolic link service
2176 nfsrv_symlink(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
2178 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2179 struct mbuf
*nam
= nfsd
->nd_nam
;
2180 char *dpos
= nfsd
->nd_dpos
;
2181 kauth_cred_t cred
= nfsd
->nd_cr
;
2182 struct vattr va
, dirfor
, diraft
;
2183 struct nameidata nd
;
2186 struct nfsv2_sattr
*sp
;
2187 char *bpos
, *pathcp
= NULL
, *cp2
;
2190 int error
= 0, cache
= 0, dirfor_ret
= 1, diraft_ret
= 1, abort
= 0;
2192 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2193 struct mbuf
*mb
, *mreq
;
2194 struct vnode
*dirp
= (struct vnode
*)0;
2198 nd
.ni_cnd
.cn_nameiop
= 0;
2199 nfsm_srvmtofh(&nsfh
);
2200 nfsm_srvnamesiz(len
);
2201 nd
.ni_cnd
.cn_cred
= cred
;
2202 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2203 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2204 error
= nfs_namei(&nd
, &nsfh
, len
, slp
, nam
, &md
, &dpos
,
2205 &dirp
, lwp
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
2207 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
);
2217 nfsm_dissect(tl
, uint32_t *, NFSX_UNSIGNED
);
2218 len2
= fxdr_unsigned(uint32_t, *tl
);
2219 if (len2
> PATH_MAX
) {
2220 /* XXX should check _PC_NO_TRUNC */
2221 error
= ENAMETOOLONG
;
2227 nfsm_strsiz(len2
, NFS_MAXPATHLEN
);
2229 pathcp
= malloc(len2
+ 1, M_TEMP
, M_WAITOK
);
2230 iv
.iov_base
= pathcp
;
2232 io
.uio_resid
= len2
;
2236 io
.uio_rw
= UIO_READ
;
2237 UIO_SETUP_SYSSPACE(&io
);
2238 nfsm_mtouio(&io
, len2
);
2240 nfsm_dissect(sp
, struct nfsv2_sattr
*, NFSX_V2SATTR
);
2241 va
.va_mode
= fxdr_unsigned(u_int16_t
, sp
->sa_mode
);
2243 *(pathcp
+ len2
) = '\0';
2247 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2248 if (nd
.ni_dvp
== nd
.ni_vp
)
2256 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2257 error
= VOP_SYMLINK(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
, pathcp
);
2260 error
= nfsrv_composefh(nd
.ni_vp
, &nsfh
, v3
);
2262 error
= VOP_GETATTR(nd
.ni_vp
, &va
, cred
);
2270 free(pathcp
, M_TEMP
);
2273 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
);
2279 nfsm_reply(NFSX_SRVFH(&nsfh
, v3
) + NFSX_POSTOPATTR(v3
) +
2283 nfsm_srvpostop_fh(&nsfh
);
2284 nfsm_srvpostop_attr(0, &va
);
2286 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2291 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2292 if (nd
.ni_dvp
== nd
.ni_vp
)
2302 free(pathcp
, M_TEMP
);
2310 nfsrv_mkdir(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
2312 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2313 struct mbuf
*nam
= nfsd
->nd_nam
;
2314 char *dpos
= nfsd
->nd_dpos
;
2315 kauth_cred_t cred
= nfsd
->nd_cr
;
2316 struct vattr va
, dirfor
, diraft
;
2317 struct nfs_fattr
*fp
;
2318 struct nameidata nd
;
2323 int error
= 0, cache
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2325 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2327 struct mbuf
*mb
, *mreq
;
2328 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
2332 nfsm_srvmtofh(&nsfh
);
2333 nfsm_srvnamesiz(len
);
2334 nd
.ni_cnd
.cn_cred
= cred
;
2335 nd
.ni_cnd
.cn_nameiop
= CREATE
;
2336 nd
.ni_cnd
.cn_flags
= LOCKPARENT
;
2337 error
= nfs_namei(&nd
, &nsfh
, len
, slp
, nam
, &md
, &dpos
,
2338 &dirp
, lwp
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
2340 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
);
2343 nfsm_reply(NFSX_WCCDATA(v3
));
2344 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2355 nfsm_dissect(tl
, u_int32_t
*, NFSX_UNSIGNED
);
2356 va
.va_mode
= nfstov_mode(*tl
++);
2361 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2362 if (nd
.ni_dvp
== vp
)
2370 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2371 error
= VOP_MKDIR(nd
.ni_dvp
, &nd
.ni_vp
, &nd
.ni_cnd
, &va
);
2374 error
= nfsrv_composefh(vp
, &nsfh
, v3
);
2376 error
= VOP_GETATTR(vp
, &va
, cred
);
2382 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
);
2388 nfsm_reply(NFSX_SRVFH(&nsfh
, v3
) + NFSX_POSTOPATTR(v3
) +
2392 nfsm_srvpostop_fh(&nsfh
);
2393 nfsm_srvpostop_attr(0, &va
);
2395 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2397 nfsm_srvfhtom(&nsfh
, v3
);
2398 nfsm_build(fp
, struct nfs_fattr
*, NFSX_V2FATTR
);
2399 nfsm_srvfillattr(&va
, fp
);
2404 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2405 if (nd
.ni_dvp
== nd
.ni_vp
)
2421 nfsrv_rmdir(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
2423 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2424 struct mbuf
*nam
= nfsd
->nd_nam
;
2425 char *dpos
= nfsd
->nd_dpos
;
2426 kauth_cred_t cred
= nfsd
->nd_cr
;
2430 int error
= 0, cache
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2431 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2433 struct mbuf
*mb
, *mreq
;
2434 struct vnode
*vp
, *dirp
= (struct vnode
*)0;
2435 struct vattr dirfor
, diraft
;
2437 struct nameidata nd
;
2440 nfsm_srvmtofh(&nsfh
);
2441 nfsm_srvnamesiz(len
);
2442 nd
.ni_cnd
.cn_cred
= cred
;
2443 nd
.ni_cnd
.cn_nameiop
= DELETE
;
2444 nd
.ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
2445 error
= nfs_namei(&nd
, &nsfh
, len
, slp
, nam
, &md
, &dpos
,
2446 &dirp
, lwp
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
2448 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
, cred
);
2451 nfsm_reply(NFSX_WCCDATA(v3
));
2452 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2458 if (vp
->v_type
!= VDIR
) {
2463 * No rmdir "." please.
2465 if (nd
.ni_dvp
== vp
) {
2470 * The root of a mounted filesystem cannot be deleted.
2472 if (vp
->v_vflag
& VV_ROOT
)
2476 nqsrv_getl(nd
.ni_dvp
, ND_WRITE
);
2477 nqsrv_getl(vp
, ND_WRITE
);
2478 error
= VOP_RMDIR(nd
.ni_dvp
, nd
.ni_vp
, &nd
.ni_cnd
);
2480 VOP_ABORTOP(nd
.ni_dvp
, &nd
.ni_cnd
);
2481 if (nd
.ni_dvp
== nd
.ni_vp
)
2489 diraft_ret
= VOP_GETATTR(dirp
, &diraft
, cred
);
2493 nfsm_reply(NFSX_WCCDATA(v3
));
2495 nfsm_srvwcc_data(dirfor_ret
, &dirfor
, diraft_ret
, &diraft
);
2502 * nfs readdir service
2503 * - mallocs what it thinks is enough to read
2504 * count rounded up to a multiple of NFS_SRVDIRBLKSIZ <= NFS_MAXREADDIR
2505 * - calls VOP_READDIR()
2506 * - loops around building the reply
2507 * if the output generated exceeds count break out of loop
2508 * The nfsm_clget macro is used here so that the reply will be packed
2509 * tightly in mbuf clusters.
2510 * - it only knows that it has encountered eof when the VOP_READDIR()
2512 * - as such one readdir rpc will return eof false although you are there
2513 * and then the next will return eof
2514 * - it trims out records with d_fileno == 0
2515 * this doesn't matter for Unix clients, but they might confuse clients
2517 * - it trims out records with d_type == DT_WHT
2518 * these cannot be seen through NFS (unless we extend the protocol)
2519 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2520 * than requested, but this may not apply to all filesystems. For
2521 * example, client NFS does not { although it is never remote mounted
2523 * The alternate call nfsrv_readdirplus() does lookups as well.
2524 * PS: The NFS protocol spec. does not clarify what the "count" byte
2525 * argument is a count of.. just name strings and file id's or the
2526 * entire reply rpc or ...
2527 * I tried just file name and id sizes and it confused the Sun client,
2528 * so I am using the full rpc size now. The "paranoia.." comment refers
2529 * to including the status longwords that are not a part of the dir.
2530 * "entry" structures, but are in the rpc.
2533 #define NFS_SRVDIRBLKSIZ 1024
2537 u_int32_t fl_postopok
;
2538 struct nfs_fattr fl_fattr
; /* XXX: must be of fattr3 size */
2540 u_int32_t fl_fhsize
;
2541 /* handle comes here, filled in dynamically */
2545 nfsrv_readdir(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
2547 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2548 struct mbuf
*nam
= nfsd
->nd_nam
;
2549 char *dpos
= nfsd
->nd_dpos
;
2550 kauth_cred_t cred
= nfsd
->nd_cr
;
2558 struct mbuf
*mb
, *mreq
, *mp2
;
2559 char *cpos
, *cend
, *cp2
, *rbuf
;
2565 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2566 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, cache
= 0, ncookies
;
2567 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2568 u_quad_t frev
, off
, toff
, verf
;
2569 off_t
*cookies
= NULL
, *cookiep
;
2572 nfsm_srvmtofh(&nsfh
);
2574 nfsm_dissect(tl
, u_int32_t
*, 5 * NFSX_UNSIGNED
);
2575 toff
= fxdr_hyper(tl
);
2577 verf
= fxdr_hyper(tl
);
2580 nfsm_dissect(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
2581 toff
= fxdr_unsigned(u_quad_t
, *tl
++);
2584 cnt
= fxdr_unsigned(int, *tl
);
2585 siz
= ((cnt
+ NFS_SRVDIRBLKSIZ
- 1) & ~(NFS_SRVDIRBLKSIZ
- 1));
2586 xfer
= NFS_SRVMAXDATA(nfsd
);
2590 error
= nfsrv_fhtovp(&nsfh
, 1, &vp
, cred
, slp
, nam
,
2591 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
2592 if (!error
&& vp
->v_type
!= VDIR
) {
2597 nfsm_reply(NFSX_UNSIGNED
);
2598 nfsm_srvpostop_attr(getret
, &at
);
2601 nqsrv_getl(vp
, ND_READ
);
2603 error
= getret
= VOP_GETATTR(vp
, &at
, cred
);
2604 #ifdef NFS3_STRICTVERF
2606 * XXX This check is too strict for Solaris 2.5 clients.
2608 if (!error
&& toff
&& verf
!= at
.va_filerev
)
2609 error
= NFSERR_BAD_COOKIE
;
2613 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, lwp
, 0);
2616 nfsm_reply(NFSX_POSTOPATTR(v3
));
2617 nfsm_srvpostop_attr(getret
, &at
);
2621 rbuf
= malloc(siz
, M_TEMP
, M_WAITOK
);
2624 iv
.iov_len
= fullsiz
;
2627 io
.uio_offset
= (off_t
)off
;
2628 io
.uio_resid
= fullsiz
;
2629 io
.uio_rw
= UIO_READ
;
2630 UIO_SETUP_SYSSPACE(&io
);
2632 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
2634 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &cookies
, &ncookies
);
2636 off
= (off_t
)io
.uio_offset
;
2637 if (!cookies
&& !error
)
2638 error
= NFSERR_PERM
;
2640 getret
= VOP_GETATTR(vp
, &at
, cred
);
2648 free((void *)rbuf
, M_TEMP
);
2650 free((void *)cookies
, M_TEMP
);
2651 nfsm_reply(NFSX_POSTOPATTR(v3
));
2652 nfsm_srvpostop_attr(getret
, &at
);
2656 siz
-= io
.uio_resid
;
2659 * If nothing read, return eof
2664 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) +
2667 nfsm_srvpostop_attr(getret
, &at
);
2668 nfsm_build(tl
, u_int32_t
*, 4 * NFSX_UNSIGNED
);
2669 txdr_hyper(at
.va_filerev
, tl
);
2672 nfsm_build(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
2675 free((void *)rbuf
, M_TEMP
);
2676 free((void *)cookies
, M_TEMP
);
2682 * Check for degenerate cases of nothing useful read.
2683 * If so go try again
2687 dp
= (struct dirent
*)cpos
;
2690 while (cpos
< cend
&& ncookies
> 0 &&
2691 (dp
->d_fileno
== 0 || dp
->d_type
== DT_WHT
)) {
2692 cpos
+= dp
->d_reclen
;
2693 dp
= (struct dirent
*)cpos
;
2697 if (cpos
>= cend
|| ncookies
== 0) {
2700 free(cookies
, M_TEMP
);
2705 len
= 3 * NFSX_UNSIGNED
; /* paranoia, probably can be 0 */
2706 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_COOKIEVERF(v3
) + siz
);
2708 nfsm_srvpostop_attr(getret
, &at
);
2709 nfsm_build(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
2710 txdr_hyper(at
.va_filerev
, tl
);
2714 be
= bp
+ M_TRAILINGSPACE(mp
);
2716 /* Loop through the records and build reply */
2717 while (cpos
< cend
&& ncookies
> 0) {
2718 if (dp
->d_fileno
!= 0 && dp
->d_type
!= DT_WHT
) {
2719 nlen
= dp
->d_namlen
;
2720 rem
= nfsm_rndup(nlen
)-nlen
;
2721 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
2723 len
+= 2 * NFSX_UNSIGNED
;
2729 * Build the directory record xdr from
2734 bp
+= NFSX_UNSIGNED
;
2737 *tl
= txdr_unsigned(dp
->d_fileno
>> 32);
2738 bp
+= NFSX_UNSIGNED
;
2741 *tl
= txdr_unsigned(dp
->d_fileno
);
2742 bp
+= NFSX_UNSIGNED
;
2744 *tl
= txdr_unsigned(nlen
);
2745 bp
+= NFSX_UNSIGNED
;
2747 /* And loop around copying the name */
2756 memcpy(bp
, cp
, tsiz
);
2762 /* And null pad to an int32_t boundary */
2763 for (i
= 0; i
< rem
; i
++)
2767 /* Finish off the record */
2768 txdr_hyper(*cookiep
, &jar
);
2770 *tl
= jar
.nfsuquad
[0];
2771 bp
+= NFSX_UNSIGNED
;
2774 *tl
= jar
.nfsuquad
[1];
2775 bp
+= NFSX_UNSIGNED
;
2777 cpos
+= dp
->d_reclen
;
2778 dp
= (struct dirent
*)cpos
;
2785 bp
+= NFSX_UNSIGNED
;
2791 bp
+= NFSX_UNSIGNED
;
2794 mp
->m_len
= bp
- mtod(mp
, char *);
2796 mp
->m_len
+= bp
- bpos
;
2797 free((void *)rbuf
, M_TEMP
);
2798 free((void *)cookies
, M_TEMP
);
2803 nfsrv_readdirplus(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
2805 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
2806 struct mbuf
*nam
= nfsd
->nd_nam
;
2807 char *dpos
= nfsd
->nd_dpos
;
2808 kauth_cred_t cred
= nfsd
->nd_cr
;
2816 struct mbuf
*mb
, *mreq
, *mp2
;
2817 char *cpos
, *cend
, *cp2
, *rbuf
;
2818 struct vnode
*vp
, *nvp
;
2823 struct vattr va
, at
, *vap
= &va
;
2824 struct nfs_fattr
*fp
;
2825 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2826 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, cache
= 0, dirlen
, ncookies
;
2827 u_quad_t frev
, off
, toff
, verf
;
2828 off_t
*cookies
= NULL
, *cookiep
;
2830 nfsm_srvmtofh(&nsfh
);
2831 nfsm_dissect(tl
, u_int32_t
*, 6 * NFSX_UNSIGNED
);
2832 toff
= fxdr_hyper(tl
);
2834 verf
= fxdr_hyper(tl
);
2836 siz
= fxdr_unsigned(int, *tl
++);
2837 cnt
= fxdr_unsigned(int, *tl
);
2839 siz
= ((siz
+ NFS_SRVDIRBLKSIZ
- 1) & ~(NFS_SRVDIRBLKSIZ
- 1));
2840 xfer
= NFS_SRVMAXDATA(nfsd
);
2844 error
= nfsrv_fhtovp(&nsfh
, 1, &vp
, cred
, slp
, nam
,
2845 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
2846 if (!error
&& vp
->v_type
!= VDIR
) {
2851 nfsm_reply(NFSX_UNSIGNED
);
2852 nfsm_srvpostop_attr(getret
, &at
);
2855 error
= getret
= VOP_GETATTR(vp
, &at
, cred
);
2856 #ifdef NFS3_STRICTVERF
2858 * XXX This check is too strict for Solaris 2.5 clients.
2860 if (!error
&& toff
&& verf
!= at
.va_filerev
)
2861 error
= NFSERR_BAD_COOKIE
;
2864 nqsrv_getl(vp
, ND_READ
);
2865 error
= nfsrv_access(vp
, VEXEC
, cred
, rdonly
, lwp
, 0);
2869 nfsm_reply(NFSX_V3POSTOPATTR
);
2870 nfsm_srvpostop_attr(getret
, &at
);
2875 rbuf
= malloc(siz
, M_TEMP
, M_WAITOK
);
2878 iv
.iov_len
= fullsiz
;
2881 io
.uio_offset
= (off_t
)off
;
2882 io
.uio_resid
= fullsiz
;
2883 io
.uio_rw
= UIO_READ
;
2884 UIO_SETUP_SYSSPACE(&io
);
2887 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
2889 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &cookies
, &ncookies
);
2891 off
= (u_quad_t
)io
.uio_offset
;
2892 getret
= VOP_GETATTR(vp
, &at
, cred
);
2897 * If the VGET operation doesn't work for this filesystem,
2898 * we can't support readdirplus. Returning NOTSUPP should
2899 * make clients fall back to plain readdir.
2900 * There's no need to check for VPTOFH as well, we wouldn't
2901 * even be here otherwise.
2904 if ((getret
= VFS_VGET(vp
->v_mount
, at
.va_fileid
, &nvp
)))
2905 getret
= (getret
== EOPNOTSUPP
) ?
2906 NFSERR_NOTSUPP
: NFSERR_IO
;
2911 if (!cookies
&& !error
)
2912 error
= NFSERR_PERM
;
2918 free((void *)cookies
, M_TEMP
);
2919 free((void *)rbuf
, M_TEMP
);
2920 nfsm_reply(NFSX_V3POSTOPATTR
);
2921 nfsm_srvpostop_attr(getret
, &at
);
2925 siz
-= io
.uio_resid
;
2928 * If nothing read, return eof
2933 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+
2935 nfsm_srvpostop_attr(getret
, &at
);
2936 nfsm_build(tl
, u_int32_t
*, 4 * NFSX_UNSIGNED
);
2937 txdr_hyper(at
.va_filerev
, tl
);
2941 free((void *)cookies
, M_TEMP
);
2942 free((void *)rbuf
, M_TEMP
);
2948 * Check for degenerate cases of nothing useful read.
2949 * If so go try again
2953 dp
= (struct dirent
*)cpos
;
2956 while (cpos
< cend
&& ncookies
> 0 &&
2957 (dp
->d_fileno
== 0 || dp
->d_type
== DT_WHT
)) {
2958 cpos
+= dp
->d_reclen
;
2959 dp
= (struct dirent
*)cpos
;
2963 if (cpos
>= cend
|| ncookies
== 0) {
2966 free(cookies
, M_TEMP
);
2971 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+ 2 * NFSX_UNSIGNED
;
2973 nfsm_srvpostop_attr(getret
, &at
);
2974 nfsm_build(tl
, u_int32_t
*, 2 * NFSX_UNSIGNED
);
2975 txdr_hyper(at
.va_filerev
, tl
);
2978 be
= bp
+ M_TRAILINGSPACE(mp
);
2980 /* Loop through the records and build reply */
2981 while (cpos
< cend
&& ncookies
> 0) {
2982 if (dp
->d_fileno
!= 0 && dp
->d_type
!= DT_WHT
) {
2985 nlen
= dp
->d_namlen
;
2986 rem
= nfsm_rndup(nlen
)-nlen
;
2989 * For readdir_and_lookup get the vnode using
2992 if (VFS_VGET(vp
->v_mount
, dp
->d_fileno
, &nvp
))
2994 if (nfsrv_composefh(nvp
, &nnsfh
, true)) {
2998 if (VOP_GETATTR(nvp
, vap
, cred
)) {
3005 * If either the dircount or maxcount will be
3006 * exceeded, get out now. Both of these lengths
3007 * are calculated conservatively, including all
3010 len
+= (8 * NFSX_UNSIGNED
+ nlen
+ rem
+ NFSX_V3FH
+
3012 dirlen
+= (6 * NFSX_UNSIGNED
+ nlen
+ rem
);
3013 if (len
> cnt
|| dirlen
> fullsiz
) {
3019 * Build the directory record xdr from
3022 fp
= (struct nfs_fattr
*)&fl
.fl_fattr
;
3023 nfsm_srvfillattr(vap
, fp
);
3024 fl
.fl_fhsize
= txdr_unsigned(NFSX_V3FH
);
3025 fl
.fl_fhok
= nfs_true
;
3026 fl
.fl_postopok
= nfs_true
;
3027 txdr_hyper(*cookiep
, fl
.fl_off
.nfsuquad
);
3031 bp
+= NFSX_UNSIGNED
;
3033 *tl
= txdr_unsigned(dp
->d_fileno
>> 32);
3034 bp
+= NFSX_UNSIGNED
;
3036 *tl
= txdr_unsigned(dp
->d_fileno
);
3037 bp
+= NFSX_UNSIGNED
;
3039 *tl
= txdr_unsigned(nlen
);
3040 bp
+= NFSX_UNSIGNED
;
3042 /* And loop around copying the name */
3047 if ((bp
+ xfer
) > be
)
3051 memcpy(bp
, cp
, tsiz
);
3057 /* And null pad to an int32_t boundary */
3058 for (i
= 0; i
< rem
; i
++)
3062 * Now copy the flrep structure out.
3064 xfer
= sizeof(struct flrep
);
3068 if ((bp
+ xfer
) > be
)
3072 memcpy(bp
, cp
, tsiz
);
3080 * ... and filehandle.
3082 xfer
= NFSRVFH_SIZE(&nnsfh
);
3083 cp
= NFSRVFH_DATA(&nnsfh
);
3086 if ((bp
+ xfer
) > be
)
3090 memcpy(bp
, cp
, tsiz
);
3098 cpos
+= dp
->d_reclen
;
3099 dp
= (struct dirent
*)cpos
;
3106 bp
+= NFSX_UNSIGNED
;
3112 bp
+= NFSX_UNSIGNED
;
3115 mp
->m_len
= bp
- mtod(mp
, char *);
3117 mp
->m_len
+= bp
- bpos
;
3118 free((void *)cookies
, M_TEMP
);
3119 free((void *)rbuf
, M_TEMP
);
3124 * nfs commit service
3127 nfsrv_commit(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
3129 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3130 struct mbuf
*nam
= nfsd
->nd_nam
;
3131 char *dpos
= nfsd
->nd_dpos
;
3132 kauth_cred_t cred
= nfsd
->nd_cr
;
3133 struct vattr bfor
, aft
;
3139 int error
= 0, rdonly
, for_ret
= 1, aft_ret
= 1, cache
= 0;
3142 struct mbuf
*mb
, *mreq
;
3143 u_quad_t frev
, off
, end
;
3145 nfsm_srvmtofh(&nsfh
);
3146 nfsm_dissect(tl
, u_int32_t
*, 3 * NFSX_UNSIGNED
);
3148 off
= fxdr_hyper(tl
);
3150 cnt
= fxdr_unsigned(uint32_t, *tl
);
3151 error
= nfsrv_fhtovp(&nsfh
, 1, &vp
, cred
, slp
, nam
,
3152 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
3154 nfsm_reply(2 * NFSX_UNSIGNED
);
3155 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
3158 for_ret
= VOP_GETATTR(vp
, &bfor
, cred
);
3159 end
= (cnt
> 0) ? off
+ cnt
: vp
->v_size
;
3160 if (end
< off
|| end
> vp
->v_size
)
3162 if (off
< vp
->v_size
)
3163 error
= VOP_FSYNC(vp
, cred
, FSYNC_WAIT
, off
, end
);
3164 /* else error == 0, from nfsrv_fhtovp() */
3165 aft_ret
= VOP_GETATTR(vp
, &aft
, cred
);
3167 nfsm_reply(NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
);
3168 nfsm_srvwcc_data(for_ret
, &bfor
, aft_ret
, &aft
);
3170 nfsm_build(tl
, u_int32_t
*, NFSX_V3WRITEVERF
);
3171 *tl
++ = txdr_unsigned(boottime
.tv_sec
);
3172 *tl
= txdr_unsigned(boottime
.tv_nsec
/ 1000);
3180 * nfs statfs service
3183 nfsrv_statfs(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
3185 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3186 struct mbuf
*nam
= nfsd
->nd_nam
;
3187 char *dpos
= nfsd
->nd_dpos
;
3188 kauth_cred_t cred
= nfsd
->nd_cr
;
3189 struct statvfs
*sf
= NULL
;
3190 struct nfs_statfs
*sfp
;
3194 int error
= 0, rdonly
, cache
= 0, getret
= 1;
3195 int v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3197 struct mbuf
*mb
, *mreq
;
3201 u_quad_t frev
, tval
;
3203 nfsm_srvmtofh(&nsfh
);
3204 error
= nfsrv_fhtovp(&nsfh
, 1, &vp
, cred
, slp
, nam
,
3205 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
3207 nfsm_reply(NFSX_UNSIGNED
);
3208 nfsm_srvpostop_attr(getret
, &at
);
3211 sf
= malloc(sizeof(*sf
), M_TEMP
, M_WAITOK
);
3212 error
= VFS_STATVFS(vp
->v_mount
, sf
);
3213 getret
= VOP_GETATTR(vp
, &at
, cred
);
3215 nfsm_reply(NFSX_POSTOPATTR(v3
) + NFSX_STATFS(v3
));
3217 nfsm_srvpostop_attr(getret
, &at
);
3222 nfsm_build(sfp
, struct nfs_statfs
*, NFSX_STATFS(v3
));
3224 tval
= (u_quad_t
)((quad_t
)sf
->f_blocks
* (quad_t
)sf
->f_frsize
);
3225 txdr_hyper(tval
, &sfp
->sf_tbytes
);
3226 tval
= (u_quad_t
)((quad_t
)sf
->f_bfree
* (quad_t
)sf
->f_frsize
);
3227 txdr_hyper(tval
, &sfp
->sf_fbytes
);
3228 tval
= (u_quad_t
)((quad_t
)sf
->f_bavail
* (quad_t
)sf
->f_frsize
);
3229 txdr_hyper(tval
, &sfp
->sf_abytes
);
3230 tval
= (u_quad_t
)sf
->f_files
;
3231 txdr_hyper(tval
, &sfp
->sf_tfiles
);
3232 tval
= (u_quad_t
)sf
->f_ffree
;
3233 txdr_hyper(tval
, &sfp
->sf_ffiles
);
3234 txdr_hyper(tval
, &sfp
->sf_afiles
);
3235 sfp
->sf_invarsec
= 0;
3237 sfp
->sf_tsize
= txdr_unsigned(NFS_MAXDGRAMDATA
);
3238 sfp
->sf_bsize
= txdr_unsigned(sf
->f_frsize
);
3239 sfp
->sf_blocks
= txdr_unsigned(sf
->f_blocks
);
3240 sfp
->sf_bfree
= txdr_unsigned(sf
->f_bfree
);
3241 sfp
->sf_bavail
= txdr_unsigned(sf
->f_bavail
);
3250 * nfs fsinfo service
3253 nfsrv_fsinfo(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
3255 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3256 struct mbuf
*nam
= nfsd
->nd_nam
;
3257 char *dpos
= nfsd
->nd_dpos
;
3258 kauth_cred_t cred
= nfsd
->nd_cr
;
3260 struct nfsv3_fsinfo
*sip
;
3263 int error
= 0, rdonly
, cache
= 0, getret
= 1;
3266 struct mbuf
*mb
, *mreq
;
3270 u_quad_t frev
, maxfsize
;
3273 nfsm_srvmtofh(&nsfh
);
3274 error
= nfsrv_fhtovp(&nsfh
, 1, &vp
, cred
, slp
, nam
,
3275 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
3277 nfsm_reply(NFSX_UNSIGNED
);
3278 nfsm_srvpostop_attr(getret
, &at
);
3282 /* XXX Try to make a guess on the max file size. */
3283 sb
= malloc(sizeof(*sb
), M_TEMP
, M_WAITOK
);
3284 VFS_STATVFS(vp
->v_mount
, sb
);
3285 maxfsize
= (u_quad_t
)0x80000000 * sb
->f_frsize
- 1;
3288 getret
= VOP_GETATTR(vp
, &at
, cred
);
3290 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
);
3291 nfsm_srvpostop_attr(getret
, &at
);
3292 nfsm_build(sip
, struct nfsv3_fsinfo
*, NFSX_V3FSINFO
);
3296 * There should be file system VFS OP(s) to get this information.
3297 * For now, assume ufs.
3299 if (slp
->ns_so
->so_type
== SOCK_DGRAM
)
3300 maxdata
= NFS_MAXDGRAMDATA
;
3302 maxdata
= NFS_MAXDATA
;
3303 sip
->fs_rtmax
= txdr_unsigned(maxdata
);
3304 sip
->fs_rtpref
= txdr_unsigned(maxdata
);
3305 sip
->fs_rtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3306 sip
->fs_wtmax
= txdr_unsigned(maxdata
);
3307 sip
->fs_wtpref
= txdr_unsigned(maxdata
);
3308 sip
->fs_wtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3309 sip
->fs_dtpref
= txdr_unsigned(maxdata
);
3310 txdr_hyper(maxfsize
, &sip
->fs_maxfilesize
);
3311 sip
->fs_timedelta
.nfsv3_sec
= 0;
3312 sip
->fs_timedelta
.nfsv3_nsec
= txdr_unsigned(1);
3313 sip
->fs_properties
= txdr_unsigned(NFSV3FSINFO_LINK
|
3314 NFSV3FSINFO_SYMLINK
| NFSV3FSINFO_HOMOGENEOUS
|
3315 NFSV3FSINFO_CANSETTIME
);
3320 * nfs pathconf service
3323 nfsrv_pathconf(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
, struct lwp
*lwp
, struct mbuf
**mrq
)
3325 struct mbuf
*mrep
= nfsd
->nd_mrep
, *md
= nfsd
->nd_md
;
3326 struct mbuf
*nam
= nfsd
->nd_nam
;
3327 char *dpos
= nfsd
->nd_dpos
;
3328 kauth_cred_t cred
= nfsd
->nd_cr
;
3330 struct nfsv3_pathconf
*pc
;
3333 int error
= 0, rdonly
, cache
= 0, getret
= 1;
3334 register_t linkmax
, namemax
, chownres
, notrunc
;
3336 struct mbuf
*mb
, *mreq
;
3342 nfsm_srvmtofh(&nsfh
);
3343 error
= nfsrv_fhtovp(&nsfh
, 1, &vp
, cred
, slp
, nam
,
3344 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), false);
3346 nfsm_reply(NFSX_UNSIGNED
);
3347 nfsm_srvpostop_attr(getret
, &at
);
3350 error
= VOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
);
3352 error
= VOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
);
3354 error
= VOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
);
3356 error
= VOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
);
3357 getret
= VOP_GETATTR(vp
, &at
, cred
);
3359 nfsm_reply(NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
);
3360 nfsm_srvpostop_attr(getret
, &at
);
3363 nfsm_build(pc
, struct nfsv3_pathconf
*, NFSX_V3PATHCONF
);
3365 pc
->pc_linkmax
= txdr_unsigned(linkmax
);
3366 pc
->pc_namemax
= txdr_unsigned(namemax
);
3367 pc
->pc_notrunc
= txdr_unsigned(notrunc
);
3368 pc
->pc_chownrestricted
= txdr_unsigned(chownres
);
3371 * These should probably be supported by VOP_PATHCONF(), but
3372 * until msdosfs is exportable (why would you want to?), the
3373 * Unix defaults should be ok.
3375 pc
->pc_caseinsensitive
= nfs_false
;
3376 pc
->pc_casepreserving
= nfs_true
;
3381 * Null operation, used by clients to ping server
3385 nfsrv_null(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3386 struct lwp
*lwp
, struct mbuf
**mrq
)
3388 struct mbuf
*mrep
= nfsd
->nd_mrep
;
3390 int error
= NFSERR_RETVOID
, cache
= 0;
3391 struct mbuf
*mb
, *mreq
;
3400 * No operation, used for obsolete procedures
3404 nfsrv_noop(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3405 struct lwp
*lwp
, struct mbuf
**mrq
)
3407 struct mbuf
*mrep
= nfsd
->nd_mrep
;
3409 int error
, cache
= 0;
3410 struct mbuf
*mb
, *mreq
;
3413 if (nfsd
->nd_repstat
)
3414 error
= nfsd
->nd_repstat
;
3416 error
= EPROCUNAVAIL
;
3423 * Perform access checking for vnodes obtained from file handles that would
3424 * refer to files already opened by a Unix client. You cannot just use
3425 * vn_writechk() and VOP_ACCESS() for two reasons.
3426 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3427 * 2 - The owner is to be given access irrespective of mode bits for some
3428 * operations, so that processes that chmod after opening a file don't
3429 * break. I don't like this because it opens a security hole, but since
3430 * the nfs server opens a security hole the size of a barn door anyhow,
3433 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
3434 * will return EPERM instead of EACCESS. EPERM is always an error.
3437 nfsrv_access(struct vnode
*vp
, int flags
, kauth_cred_t cred
, int rdonly
, struct lwp
*lwp
, int override
)
3441 if (flags
& VWRITE
) {
3442 /* Just vn_writechk() changed to check rdonly */
3444 * Disallow write attempts on read-only file systems;
3445 * unless the file is a socket or a block or character
3446 * device resident on the file system.
3448 if (rdonly
|| (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)) {
3449 switch (vp
->v_type
) {
3460 * If the vnode is in use as a process's text,
3461 * we can't allow writing.
3463 if (vp
->v_iflag
& VI_TEXT
)
3466 error
= VOP_GETATTR(vp
, &vattr
, cred
);
3469 error
= VOP_ACCESS(vp
, flags
, cred
);
3471 * Allow certain operations for the owner (reads and writes
3472 * on files that are already open).
3474 if (override
&& error
== EACCES
&& kauth_cred_geteuid(cred
) == vattr
.va_uid
)