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. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * @(#)nfs_serv.c 8.8 (Berkeley) 7/31/95
33 * $FreeBSD: src/sys/nfs/nfs_serv.c,v 1.93.2.6 2002/12/29 18:19:53 dillon Exp $
37 * nfs version 2 and 3 server calls to vnode ops
38 * - these routines generally have 3 phases
39 * 1 - break down and validate rpc request in mbuf list
40 * 2 - do the vnode ops for the request
41 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
42 * 3 - build the rpc reply in an mbuf list
44 * - do not mix the phases, since the nfsm_?? macros can return failures
45 * on a bad rpc or similar and do not do any vrele() or vput()'s
47 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
48 * error number iff error != 0 whereas
49 * returning an error from the server function implies a fatal error
50 * such as a badly constructed rpc request that should be dropped without
52 * For Version 3, nfsm_reply() does not return for the error case, since
53 * most version 3 rpcs return more than the status for error cases.
56 * Warning: always pay careful attention to resource cleanup on return
57 * and note that nfsm_*() macros can terminate a procedure on certain
61 #include <sys/param.h>
62 #include <sys/systm.h>
65 #include <sys/nlookup.h>
66 #include <sys/namei.h>
67 #include <sys/unistd.h>
68 #include <sys/vnode.h>
69 #include <sys/mount.h>
70 #include <sys/socket.h>
71 #include <sys/socketvar.h>
72 #include <sys/malloc.h>
74 #include <sys/dirent.h>
76 #include <sys/kernel.h>
77 #include <sys/sysctl.h>
81 #include <vm/vm_extern.h>
82 #include <vm/vm_object.h>
86 #include <sys/thread2.h>
92 #include "nfsm_subs.h"
95 #define nfsdbprintf(info) kprintf info
97 #define nfsdbprintf(info)
100 #define MAX_REORDERED_RPC (16)
101 #define MAX_COMMIT_COUNT (1024 * 1024)
103 #define NUM_HEURISTIC 1031
104 #define NHUSE_INIT 64
106 #define NHUSE_MAX 2048
108 static struct nfsheur
{
109 struct vnode
*nh_vp
; /* vp to match (unreferenced pointer) */
110 off_t nh_nextoff
; /* next offset for sequential detection */
111 int nh_use
; /* use count for selection */
112 int nh_seqcount
; /* heuristic */
113 } nfsheur
[NUM_HEURISTIC
];
115 nfstype nfsv3_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFSOCK
,
118 nfstype nfsv2_type
[9] = { NFNON
, NFREG
, NFDIR
, NFBLK
, NFCHR
, NFLNK
, NFNON
,
121 int nfsrvw_procrastinate
= NFS_GATHERDELAY
* 1000;
122 int nfsrvw_procrastinate_v3
= 0;
124 static struct timespec nfsver
;
126 SYSCTL_DECL(_vfs_nfs
);
129 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, async
, CTLFLAG_RW
, &nfs_async
, 0,
130 "Enable unstable and fast writes");
131 static int nfs_commit_blks
;
132 static int nfs_commit_miss
;
133 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, commit_blks
, CTLFLAG_RW
, &nfs_commit_blks
, 0,
134 "Number of committed blocks");
135 SYSCTL_INT(_vfs_nfs
, OID_AUTO
, commit_miss
, CTLFLAG_RW
, &nfs_commit_miss
, 0,
136 "Number of nfs blocks committed from dirty buffers");
138 static int nfsrv_access (struct mount
*, struct vnode
*, int,
139 struct ucred
*, int, struct thread
*, int);
140 static void nfsrvw_coalesce (struct nfsrv_descript
*,
141 struct nfsrv_descript
*);
144 * Heuristic to detect sequential operation.
146 static struct nfsheur
*
147 nfsrv_sequential_heuristic(struct uio
*uio
, struct vnode
*vp
, int writeop
)
152 /* Locate best candidate */
154 hi
= ((int)(vm_offset_t
) vp
/ sizeof(struct vnode
)) % NUM_HEURISTIC
;
158 if (nfsheur
[hi
].nh_vp
== vp
) {
162 if (nfsheur
[hi
].nh_use
> 0)
163 --nfsheur
[hi
].nh_use
;
164 hi
= (hi
+ 1) % NUM_HEURISTIC
;
165 if (nfsheur
[hi
].nh_use
< nh
->nh_use
)
169 /* Initialize hint if this is a new file */
170 if (nh
->nh_vp
!= vp
) {
172 nh
->nh_nextoff
= uio
->uio_offset
;
173 nh
->nh_use
= NHUSE_INIT
;
174 if (uio
->uio_offset
== 0)
181 * Calculate heuristic
183 * See vfs_vnops.c:sequential_heuristic().
185 if ((uio
->uio_offset
== 0 && nh
->nh_seqcount
> 0) ||
186 uio
->uio_offset
== nh
->nh_nextoff
) {
187 nh
->nh_seqcount
+= howmany(uio
->uio_resid
, 16384);
188 if (nh
->nh_seqcount
> IO_SEQMAX
)
189 nh
->nh_seqcount
= IO_SEQMAX
;
190 } else if (qabs(uio
->uio_offset
- nh
->nh_nextoff
) <= MAX_REORDERED_RPC
*
191 imax(vp
->v_mount
->mnt_stat
.f_iosize
, uio
->uio_resid
)) {
192 /* Probably a reordered RPC, leave seqcount alone. */
193 } else if (nh
->nh_seqcount
> 1) {
194 nh
->nh_seqcount
/= 2;
198 nh
->nh_use
+= NHUSE_INC
;
199 if (nh
->nh_use
> NHUSE_MAX
)
200 nh
->nh_use
= NHUSE_MAX
;
205 * nfs v3 access service
208 nfsrv3_access(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
209 struct thread
*td
, struct mbuf
**mrq
)
211 struct sockaddr
*nam
= nfsd
->nd_nam
;
212 struct ucred
*cred
= &nfsd
->nd_cr
;
213 struct vnode
*vp
= NULL
;
214 struct mount
*mp
= NULL
;
217 int error
= 0, rdonly
, getret
;
218 struct vattr vattr
, *vap
= &vattr
;
219 u_long testmode
, nfsmode
;
220 struct nfsm_info info
;
223 info
.dpos
= nfsd
->nd_dpos
;
224 info
.md
= nfsd
->nd_md
;
225 info
.mrep
= nfsd
->nd_mrep
;
228 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
229 fhp
= &nfh
.fh_generic
;
230 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
231 NULLOUT(tl
= nfsm_dissect(&info
, NFSX_UNSIGNED
));
232 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
, &rdonly
,
233 (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
235 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_UNSIGNED
, &error
));
236 nfsm_srvpostop_attr(&info
, nfsd
, 1, NULL
);
240 nfsmode
= fxdr_unsigned(u_int32_t
, *tl
);
241 if ((nfsmode
& NFSV3ACCESS_READ
) &&
242 nfsrv_access(mp
, vp
, VREAD
, cred
, rdonly
, td
, 0))
243 nfsmode
&= ~NFSV3ACCESS_READ
;
244 if (vp
->v_type
== VDIR
)
245 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
|
248 testmode
= (NFSV3ACCESS_MODIFY
| NFSV3ACCESS_EXTEND
);
249 if ((nfsmode
& testmode
) &&
250 nfsrv_access(mp
, vp
, VWRITE
, cred
, rdonly
, td
, 0))
251 nfsmode
&= ~testmode
;
252 if (vp
->v_type
== VDIR
)
253 testmode
= NFSV3ACCESS_LOOKUP
;
255 testmode
= NFSV3ACCESS_EXECUTE
;
256 if ((nfsmode
& testmode
) &&
257 nfsrv_access(mp
, vp
, VEXEC
, cred
, rdonly
, td
, 0))
258 nfsmode
&= ~testmode
;
259 getret
= VOP_GETATTR(vp
, vap
);
262 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
263 NFSX_POSTOPATTR(1) + NFSX_UNSIGNED
, &error
));
264 nfsm_srvpostop_attr(&info
, nfsd
, getret
, vap
);
265 tl
= nfsm_build(&info
, NFSX_UNSIGNED
);
266 *tl
= txdr_unsigned(nfsmode
);
275 * nfs getattr service
278 nfsrv_getattr(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
279 struct thread
*td
, struct mbuf
**mrq
)
281 struct sockaddr
*nam
= nfsd
->nd_nam
;
282 struct ucred
*cred
= &nfsd
->nd_cr
;
283 struct nfs_fattr
*fp
;
285 struct vattr
*vap
= &va
;
286 struct vnode
*vp
= NULL
;
287 struct mount
*mp
= NULL
;
290 int error
= 0, rdonly
;
291 struct nfsm_info info
;
293 info
.mrep
= nfsd
->nd_mrep
;
294 info
.md
= nfsd
->nd_md
;
295 info
.dpos
= nfsd
->nd_dpos
;
298 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
299 fhp
= &nfh
.fh_generic
;
300 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
301 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
302 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
304 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, 0, &error
));
308 error
= VOP_GETATTR(vp
, vap
);
311 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
312 NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
), &error
));
317 fp
= nfsm_build(&info
, NFSX_FATTR(nfsd
->nd_flag
& ND_NFSV3
));
318 nfsm_srvfattr(nfsd
, vap
, fp
);
329 * nfs setattr service
332 nfsrv_setattr(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
333 struct thread
*td
, struct mbuf
**mrq
)
335 struct sockaddr
*nam
= nfsd
->nd_nam
;
336 struct ucred
*cred
= &nfsd
->nd_cr
;
337 struct vattr va
, preat
;
338 struct vattr
*vap
= &va
;
339 struct nfsv2_sattr
*sp
;
340 struct nfs_fattr
*fp
;
341 struct vnode
*vp
= NULL
;
342 struct mount
*mp
= NULL
;
346 int error
= 0, rdonly
, preat_ret
= 1, postat_ret
= 1;
348 struct timespec guard
;
349 struct nfsm_info info
;
351 info
.mrep
= nfsd
->nd_mrep
;
353 info
.md
= nfsd
->nd_md
;
354 info
.dpos
= nfsd
->nd_dpos
;
355 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
357 guard
.tv_sec
= 0; /* fix compiler warning */
360 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
361 fhp
= &nfh
.fh_generic
;
362 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
365 ERROROUT(nfsm_srvsattr(&info
, vap
));
366 NULLOUT(tl
= nfsm_dissect(&info
, NFSX_UNSIGNED
));
367 gcheck
= fxdr_unsigned(int, *tl
);
369 NULLOUT(tl
= nfsm_dissect(&info
, 2 * NFSX_UNSIGNED
));
370 fxdr_nfsv3time(tl
, &guard
);
373 NULLOUT(sp
= nfsm_dissect(&info
, NFSX_V2SATTR
));
375 * Nah nah nah nah na nah
376 * There is a bug in the Sun client that puts 0xffff in the mode
377 * field of sattr when it should put in 0xffffffff. The u_short
378 * doesn't sign extend.
379 * --> check the low order 2 bytes for 0xffff
381 if ((fxdr_unsigned(int, sp
->sa_mode
) & 0xffff) != 0xffff)
382 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
383 if (sp
->sa_uid
!= nfs_xdrneg1
)
384 vap
->va_uid
= fxdr_unsigned(uid_t
, sp
->sa_uid
);
385 if (sp
->sa_gid
!= nfs_xdrneg1
)
386 vap
->va_gid
= fxdr_unsigned(gid_t
, sp
->sa_gid
);
387 if (sp
->sa_size
!= nfs_xdrneg1
)
388 vap
->va_size
= fxdr_unsigned(u_quad_t
, sp
->sa_size
);
389 if (sp
->sa_atime
.nfsv2_sec
!= nfs_xdrneg1
) {
391 fxdr_nfsv2time(&sp
->sa_atime
, &vap
->va_atime
);
393 vap
->va_atime
.tv_sec
=
394 fxdr_unsigned(int32_t, sp
->sa_atime
.nfsv2_sec
);
395 vap
->va_atime
.tv_nsec
= 0;
398 if (sp
->sa_mtime
.nfsv2_sec
!= nfs_xdrneg1
)
399 fxdr_nfsv2time(&sp
->sa_mtime
, &vap
->va_mtime
);
404 * Now that we have all the fields, lets do it.
406 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
, &rdonly
,
407 (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
409 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
410 2 * NFSX_UNSIGNED
, &error
));
411 nfsm_srvwcc_data(&info
, nfsd
, preat_ret
, &preat
,
418 * vp now an active resource, pay careful attention to cleanup
422 error
= preat_ret
= VOP_GETATTR(vp
, &preat
);
423 if (!error
&& gcheck
&&
424 (preat
.va_ctime
.tv_sec
!= guard
.tv_sec
||
425 preat
.va_ctime
.tv_nsec
!= guard
.tv_nsec
))
426 error
= NFSERR_NOT_SYNC
;
430 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
431 NFSX_WCCDATA(info
.v3
), &error
));
432 nfsm_srvwcc_data(&info
, nfsd
, preat_ret
, &preat
,
440 * If the size is being changed write acces is required, otherwise
441 * just check for a read only file system.
443 if (vap
->va_size
== ((u_quad_t
)((quad_t
) -1))) {
444 if (rdonly
|| (mp
->mnt_flag
& MNT_RDONLY
)) {
449 if (vp
->v_type
== VDIR
) {
452 } else if ((error
= nfsrv_access(mp
, vp
, VWRITE
, cred
, rdonly
,
457 error
= VOP_SETATTR(vp
, vap
, cred
);
458 postat_ret
= VOP_GETATTR(vp
, vap
);
464 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
465 NFSX_WCCORFATTR(info
.v3
), &error
));
467 nfsm_srvwcc_data(&info
, nfsd
, preat_ret
, &preat
,
472 fp
= nfsm_build(&info
, NFSX_V2FATTR
);
473 nfsm_srvfattr(nfsd
, vap
, fp
);
487 nfsrv_lookup(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
488 struct thread
*td
, struct mbuf
**mrq
)
490 struct sockaddr
*nam
= nfsd
->nd_nam
;
491 struct ucred
*cred
= &nfsd
->nd_cr
;
492 struct nfs_fattr
*fp
;
493 struct nlookupdata nd
;
499 int error
= 0, len
, dirattr_ret
= 1;
501 struct vattr va
, dirattr
, *vap
= &va
;
502 struct nfsm_info info
;
504 info
.mrep
= nfsd
->nd_mrep
;
506 info
.md
= nfsd
->nd_md
;
507 info
.dpos
= nfsd
->nd_dpos
;
508 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
510 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
515 fhp
= &nfh
.fh_generic
;
516 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
517 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
519 pubflag
= nfs_ispublicfh(fhp
);
521 error
= nfs_namei(&nd
, cred
, 0, NULL
, &vp
,
522 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
,
523 &dirp
, td
, (nfsd
->nd_flag
& ND_KERBAUTH
), pubflag
);
526 * namei failure, only dirp to cleanup. Clear out garbarge from
527 * structure in case macros jump to nfsmout.
533 dirattr_ret
= VOP_GETATTR(dirp
, &dirattr
);
537 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
538 NFSX_POSTOPATTR(info
.v3
), &error
));
539 nfsm_srvpostop_attr(&info
, nfsd
, dirattr_ret
, &dirattr
);
545 * Locate index file for public filehandle
547 * error is 0 on entry and 0 on exit from this block.
551 if (vp
->v_type
== VDIR
&& nfs_pub
.np_index
!= NULL
) {
553 * Setup call to lookup() to see if we can find
554 * the index file. Arguably, this doesn't belong
555 * in a kernel.. Ugh. If an error occurs, do not
556 * try to install an index file and then clear the
559 * When we replace nd with ind and redirect ndp,
560 * maintenance of ni_startdir and ni_vp shift to
561 * ind and we have to clean them up in the old nd.
562 * However, the cnd resource continues to be maintained
563 * via the original nd. Confused? You aren't alone!
566 cache_copy(&nd
.nl_nch
, &nch
);
568 error
= nlookup_init_raw(&nd
, nfs_pub
.np_index
,
569 UIO_SYSSPACE
, 0, cred
, &nch
);
572 error
= nlookup(&nd
);
576 * Found an index file. Get rid of
577 * the old references. transfer vp and
578 * load up the new vp. Fortunately we do
579 * not have to deal with dvp, that would be
586 error
= cache_vget(&nd
.nl_nch
, nd
.nl_cred
,
588 KKASSERT(error
== 0);
593 * If the public filehandle was used, check that this lookup
594 * didn't result in a filehandle outside the publicly exported
595 * filesystem. We clear the poor vp here to avoid lockups due
599 if (vp
->v_mount
!= nfs_pub
.np_mount
) {
608 dirattr_ret
= VOP_GETATTR(dirp
, &dirattr
);
614 * Resources at this point:
615 * ndp->ni_vp may not be NULL
620 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
621 NFSX_POSTOPATTR(info
.v3
), &error
));
622 nfsm_srvpostop_attr(&info
, nfsd
, dirattr_ret
, &dirattr
);
628 * Clear out some resources prior to potentially blocking. This
629 * is not as critical as ni_dvp resources in other routines, but
635 * Get underlying attribute, then release remaining resources ( for
636 * the same potential blocking reason ) and reply.
638 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
639 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
641 error
= VOP_GETATTR(vp
, vap
);
645 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
646 NFSX_SRVFH(info
.v3
) +
647 NFSX_POSTOPORFATTR(info
.v3
) +
648 NFSX_POSTOPATTR(info
.v3
),
651 nfsm_srvpostop_attr(&info
, nfsd
, dirattr_ret
, &dirattr
);
655 nfsm_srvfhtom(&info
, fhp
);
657 nfsm_srvpostop_attr(&info
, nfsd
, 0, vap
);
658 nfsm_srvpostop_attr(&info
, nfsd
, dirattr_ret
, &dirattr
);
660 fp
= nfsm_build(&info
, NFSX_V2FATTR
);
661 nfsm_srvfattr(nfsd
, vap
, fp
);
668 nlookup_done(&nd
); /* may be called twice */
675 * nfs readlink service
678 nfsrv_readlink(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
679 struct thread
*td
, struct mbuf
**mrq
)
681 struct sockaddr
*nam
= nfsd
->nd_nam
;
682 struct ucred
*cred
= &nfsd
->nd_cr
;
683 struct iovec iv
[(NFS_MAXPATHLEN
+MLEN
-1)/MLEN
];
684 struct iovec
*ivp
= iv
;
686 int error
= 0, rdonly
, i
, tlen
, len
, getret
;
687 struct mbuf
*mp1
, *mp2
, *mp3
;
688 struct vnode
*vp
= NULL
;
689 struct mount
*mp
= NULL
;
693 struct uio io
, *uiop
= &io
;
694 struct nfsm_info info
;
696 info
.mrep
= nfsd
->nd_mrep
;
698 info
.md
= nfsd
->nd_md
;
699 info
.dpos
= nfsd
->nd_dpos
;
700 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
702 bzero(&io
, sizeof(struct uio
));
704 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
709 fhp
= &nfh
.fh_generic
;
710 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
713 while (len
< NFS_MAXPATHLEN
) {
714 mp1
= m_getcl(M_WAITOK
, MT_DATA
, 0);
715 mp1
->m_len
= MCLBYTES
;
722 if ((len
+ mp1
->m_len
) > NFS_MAXPATHLEN
) {
723 mp1
->m_len
= NFS_MAXPATHLEN
-len
;
724 len
= NFS_MAXPATHLEN
;
727 ivp
->iov_base
= mtod(mp1
, caddr_t
);
728 ivp
->iov_len
= mp1
->m_len
;
733 uiop
->uio_iovcnt
= i
;
734 uiop
->uio_offset
= 0;
735 uiop
->uio_resid
= len
;
736 uiop
->uio_rw
= UIO_READ
;
737 uiop
->uio_segflg
= UIO_SYSSPACE
;
739 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
740 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
742 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
743 2 * NFSX_UNSIGNED
, &error
));
744 nfsm_srvpostop_attr(&info
, nfsd
, 1, NULL
);
748 if (vp
->v_type
!= VLNK
) {
755 error
= VOP_READLINK(vp
, uiop
, cred
);
757 getret
= VOP_GETATTR(vp
, &attr
);
760 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
761 NFSX_POSTOPATTR(info
.v3
) + NFSX_UNSIGNED
,
764 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &attr
);
770 if (uiop
->uio_resid
> 0) {
771 len
-= uiop
->uio_resid
;
772 tlen
= nfsm_rndup(len
);
773 nfsm_adj(mp3
, NFS_MAXPATHLEN
-tlen
, tlen
-len
);
775 tl
= nfsm_build(&info
, NFSX_UNSIGNED
);
776 *tl
= txdr_unsigned(len
);
777 info
.mb
->m_next
= mp3
;
792 nfsrv_read(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
793 struct thread
*td
, struct mbuf
**mrq
)
795 struct nfsm_info info
;
796 struct sockaddr
*nam
= nfsd
->nd_nam
;
797 struct ucred
*cred
= &nfsd
->nd_cr
;
801 struct nfs_fattr
*fp
;
805 int error
= 0, rdonly
, cnt
, len
, left
, siz
, tlen
, getret
;
807 struct vnode
*vp
= NULL
;
808 struct mount
*mp
= NULL
;
811 struct uio io
, *uiop
= &io
;
812 struct vattr va
, *vap
= &va
;
817 info
.mrep
= nfsd
->nd_mrep
;
819 info
.md
= nfsd
->nd_md
;
820 info
.dpos
= nfsd
->nd_dpos
;
821 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
823 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
824 fhp
= &nfh
.fh_generic
;
825 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
827 NULLOUT(tl
= nfsm_dissect(&info
, 2 * NFSX_UNSIGNED
));
828 off
= fxdr_hyper(tl
);
830 NULLOUT(tl
= nfsm_dissect(&info
, NFSX_UNSIGNED
));
831 off
= (off_t
)fxdr_unsigned(u_int32_t
, *tl
);
833 NEGREPLYOUT(reqlen
= nfsm_srvstrsiz(&info
,
834 NFS_SRVMAXDATA(nfsd
), &error
));
837 * Reference vp. If an error occurs, vp will be invalid, but we
838 * have to NULL it just in case. The macros might goto nfsmout
842 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
843 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
846 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
847 2 * NFSX_UNSIGNED
, &error
));
848 nfsm_srvpostop_attr(&info
, nfsd
, 1, NULL
);
853 if (vp
->v_type
!= VREG
) {
857 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
860 if ((error
= nfsrv_access(mp
, vp
, VREAD
, cred
, rdonly
, td
, 1)) != 0)
861 error
= nfsrv_access(mp
, vp
, VEXEC
, cred
, rdonly
, td
, 1);
863 getret
= VOP_GETATTR(vp
, vap
);
869 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
870 NFSX_POSTOPATTR(info
.v3
), &error
));
871 nfsm_srvpostop_attr(&info
, nfsd
, getret
, vap
);
877 * Calculate byte count to read
880 if (off
>= vap
->va_size
)
882 else if ((off
+ reqlen
) > vap
->va_size
)
883 cnt
= vap
->va_size
- off
;
887 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
888 NFSX_POSTOPORFATTR(info
.v3
) +
889 3 * NFSX_UNSIGNED
+ nfsm_rndup(cnt
),
892 tl
= nfsm_build(&info
, NFSX_V3FATTR
+ 4 * NFSX_UNSIGNED
);
894 fp
= (struct nfs_fattr
*)tl
;
895 tl
+= (NFSX_V3FATTR
/ sizeof (u_int32_t
));
897 tl
= nfsm_build(&info
, NFSX_V2FATTR
+ NFSX_UNSIGNED
);
898 fp
= (struct nfs_fattr
*)tl
;
899 tl
+= (NFSX_V2FATTR
/ sizeof (u_int32_t
));
901 len
= left
= nfsm_rndup(cnt
);
904 * Generate the mbuf list with the uio_iov ref. to it.
909 siz
= min(M_TRAILINGSPACE(m
), left
);
915 m
= m_getcl(M_WAITOK
, MT_DATA
, 0);
921 iv
= kmalloc(i
* sizeof(struct iovec
), M_TEMP
, M_WAITOK
);
922 uiop
->uio_iov
= iv2
= iv
;
928 panic("nfsrv_read iov");
929 siz
= min(M_TRAILINGSPACE(m
), left
);
931 iv
->iov_base
= mtod(m
, caddr_t
) + m
->m_len
;
940 uiop
->uio_iovcnt
= i
;
941 uiop
->uio_offset
= off
;
942 uiop
->uio_resid
= len
;
943 uiop
->uio_rw
= UIO_READ
;
944 uiop
->uio_segflg
= UIO_SYSSPACE
;
945 nh
= nfsrv_sequential_heuristic(uiop
, vp
, 0);
946 ioflag
|= nh
->nh_seqcount
<< IO_SEQSHIFT
;
947 error
= VOP_READ(vp
, uiop
, IO_NODELOCKED
| ioflag
, cred
);
949 off
= uiop
->uio_offset
;
950 nh
->nh_nextoff
= off
;
952 kfree((caddr_t
)iv2
, M_TEMP
);
953 if (error
|| (getret
= VOP_GETATTR(vp
, vap
))) {
960 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
961 NFSX_POSTOPATTR(info
.v3
),
963 nfsm_srvpostop_attr(&info
, nfsd
, getret
, vap
);
972 nfsm_srvfattr(nfsd
, vap
, fp
);
973 tlen
= len
- uiop
->uio_resid
;
974 cnt
= cnt
< tlen
? cnt
: tlen
;
975 tlen
= nfsm_rndup(cnt
);
976 if (len
!= tlen
|| tlen
!= cnt
)
977 nfsm_adj(info
.mb
, len
- tlen
, tlen
- cnt
);
979 *tl
++ = txdr_unsigned(cnt
);
985 *tl
= txdr_unsigned(cnt
);
997 nfsrv_write(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
998 struct thread
*td
, struct mbuf
**mrq
)
1000 struct sockaddr
*nam
= nfsd
->nd_nam
;
1001 struct ucred
*cred
= &nfsd
->nd_cr
;
1005 struct nfs_fattr
*fp
;
1007 struct vattr va
, forat
;
1008 struct vattr
*vap
= &va
;
1010 int error
= 0, rdonly
, len
, forat_ret
= 1;
1011 int ioflags
, aftat_ret
= 1, retlen
, zeroing
, adjust
;
1012 int stable
= NFSV3WRITE_FILESYNC
;
1013 struct vnode
*vp
= NULL
;
1014 struct mount
*mp
= NULL
;
1018 struct uio io
, *uiop
= &io
;
1019 struct nfsm_info info
;
1022 info
.mrep
= nfsd
->nd_mrep
;
1024 info
.md
= nfsd
->nd_md
;
1025 info
.dpos
= nfsd
->nd_dpos
;
1026 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1028 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
1029 if (info
.mrep
== NULL
) {
1033 fhp
= &nfh
.fh_generic
;
1034 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
1036 NULLOUT(tl
= nfsm_dissect(&info
, 5 * NFSX_UNSIGNED
));
1037 off
= fxdr_hyper(tl
);
1039 stable
= fxdr_unsigned(int, *tl
++);
1041 NULLOUT(tl
= nfsm_dissect(&info
, 4 * NFSX_UNSIGNED
));
1042 off
= (off_t
)fxdr_unsigned(u_int32_t
, *++tl
);
1045 stable
= NFSV3WRITE_UNSTABLE
;
1047 retlen
= len
= fxdr_unsigned(int32_t, *tl
);
1051 * For NFS Version 2, it is not obvious what a write of zero length
1052 * should do, but I might as well be consistent with Version 3,
1053 * which is to return ok so long as there are no permission problems.
1059 if (mp1
== info
.md
) {
1061 adjust
= info
.dpos
- mtod(mp1
, caddr_t
);
1062 mp1
->m_len
-= adjust
;
1063 if (mp1
->m_len
> 0 && adjust
> 0)
1064 mp1
->m_data
+= adjust
;
1068 else if (mp1
->m_len
> 0) {
1071 mp1
->m_len
-= (i
- len
);
1080 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1082 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1083 2 * NFSX_UNSIGNED
, &error
));
1084 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1089 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
1090 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
1093 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1094 2 * NFSX_UNSIGNED
, &error
));
1095 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1101 forat_ret
= VOP_GETATTR(vp
, &forat
);
1102 if (vp
->v_type
!= VREG
) {
1106 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
1109 error
= nfsrv_access(mp
, vp
, VWRITE
, cred
, rdonly
, td
, 1);
1114 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1115 NFSX_WCCDATA(info
.v3
), &error
));
1116 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1123 ivp
= kmalloc(cnt
* sizeof(struct iovec
), M_TEMP
, M_WAITOK
);
1124 uiop
->uio_iov
= iv
= ivp
;
1125 uiop
->uio_iovcnt
= cnt
;
1128 if (mp1
->m_len
> 0) {
1129 ivp
->iov_base
= mtod(mp1
, caddr_t
);
1130 ivp
->iov_len
= mp1
->m_len
;
1138 * The IO_METASYNC flag indicates that all metadata (and not just
1139 * enough to ensure data integrity) mus be written to stable storage
1141 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1143 if (stable
== NFSV3WRITE_UNSTABLE
)
1144 ioflags
= IO_NODELOCKED
;
1145 else if (stable
== NFSV3WRITE_DATASYNC
)
1146 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1148 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1149 uiop
->uio_resid
= len
;
1150 uiop
->uio_rw
= UIO_WRITE
;
1151 uiop
->uio_segflg
= UIO_SYSSPACE
;
1152 uiop
->uio_td
= NULL
;
1153 uiop
->uio_offset
= off
;
1154 nh
= nfsrv_sequential_heuristic(uiop
, vp
, 1);
1155 ioflags
|= nh
->nh_seqcount
<< IO_SEQSHIFT
;
1156 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
1158 nh
->nh_nextoff
= uiop
->uio_offset
;
1159 nfsstats
.srvvop_writes
++;
1160 kfree((caddr_t
)iv
, M_TEMP
);
1162 aftat_ret
= VOP_GETATTR(vp
, vap
);
1167 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1168 NFSX_PREOPATTR(info
.v3
) +
1169 NFSX_POSTOPORFATTR(info
.v3
) +
1170 2 * NFSX_UNSIGNED
+ NFSX_WRITEVERF(info
.v3
),
1173 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1179 tl
= nfsm_build(&info
, 4 * NFSX_UNSIGNED
);
1180 *tl
++ = txdr_unsigned(retlen
);
1182 * If nfs_async is set, then pretend the write was FILESYNC.
1184 if (stable
== NFSV3WRITE_UNSTABLE
&& !nfs_async
)
1185 *tl
++ = txdr_unsigned(stable
);
1187 *tl
++ = txdr_unsigned(NFSV3WRITE_FILESYNC
);
1189 * Actually, there is no need to txdr these fields,
1190 * but it may make the values more human readable,
1191 * for debugging purposes.
1193 if (nfsver
.tv_sec
== 0)
1195 *tl
++ = txdr_unsigned(nfsver
.tv_sec
);
1196 *tl
= txdr_unsigned(nfsver
.tv_nsec
/ 1000);
1198 fp
= nfsm_build(&info
, NFSX_V2FATTR
);
1199 nfsm_srvfattr(nfsd
, vap
, fp
);
1209 * NFS write service with write gathering support. Called when
1210 * nfsrvw_procrastinate > 0.
1211 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1212 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1216 nfsrv_writegather(struct nfsrv_descript
**ndp
, struct nfssvc_sock
*slp
,
1217 struct thread
*td
, struct mbuf
**mrq
)
1220 struct nfsrv_descript
*wp
, *nfsd
, *owp
, *swp
;
1221 struct nfs_fattr
*fp
;
1224 struct nfsrvw_delayhash
*wpp
;
1226 struct vattr va
, forat
;
1228 int error
= 0, rdonly
, len
, forat_ret
= 1;
1229 int ioflags
, aftat_ret
= 1, adjust
, zeroing
;
1231 struct vnode
*vp
= NULL
;
1232 struct mount
*mp
= NULL
;
1233 struct uio io
, *uiop
= &io
;
1235 struct nfsm_info info
;
1239 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
1247 info
.mrep
= nfsd
->nd_mrep
;
1249 info
.md
= nfsd
->nd_md
;
1250 info
.dpos
= nfsd
->nd_dpos
;
1251 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1252 cred
= &nfsd
->nd_cr
;
1253 LIST_INIT(&nfsd
->nd_coalesce
);
1254 nfsd
->nd_mreq
= NULL
;
1255 nfsd
->nd_stable
= NFSV3WRITE_FILESYNC
;
1256 cur_usec
= nfs_curusec();
1257 nfsd
->nd_time
= cur_usec
+
1258 (info
.v3
? nfsrvw_procrastinate_v3
: nfsrvw_procrastinate
);
1261 * Now, get the write header..
1263 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, &nfsd
->nd_fh
, &error
));
1265 NULLOUT(tl
= nfsm_dissect(&info
, 5 * NFSX_UNSIGNED
));
1266 nfsd
->nd_off
= fxdr_hyper(tl
);
1268 nfsd
->nd_stable
= fxdr_unsigned(int, *tl
++);
1270 NULLOUT(tl
= nfsm_dissect(&info
, 4 * NFSX_UNSIGNED
));
1271 nfsd
->nd_off
= (off_t
)fxdr_unsigned(u_int32_t
, *++tl
);
1274 nfsd
->nd_stable
= NFSV3WRITE_UNSTABLE
;
1276 len
= fxdr_unsigned(int32_t, *tl
);
1278 nfsd
->nd_eoff
= nfsd
->nd_off
+ len
;
1281 * Trim the header out of the mbuf list and trim off any trailing
1282 * junk so that the mbuf list has only the write data.
1288 if (mp1
== info
.md
) {
1290 adjust
= info
.dpos
- mtod(mp1
, caddr_t
);
1291 mp1
->m_len
-= adjust
;
1292 if (mp1
->m_len
> 0 && adjust
> 0)
1293 mp1
->m_data
+= adjust
;
1300 mp1
->m_len
-= (i
- len
);
1306 if (len
> NFS_MAXDATA
|| len
< 0 || i
< len
) {
1311 nfsm_writereply(&info
, nfsd
, slp
, error
, 2 * NFSX_UNSIGNED
);
1313 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1316 nfsd
->nd_mreq
= info
.mreq
;
1317 nfsd
->nd_mrep
= NULL
;
1322 * Add this entry to the hash and time queues.
1325 wp
= slp
->ns_tq
.lh_first
;
1326 while (wp
&& wp
->nd_time
< nfsd
->nd_time
) {
1328 wp
= wp
->nd_tq
.le_next
;
1330 NFS_DPF(WG
, ("Q%03x", nfsd
->nd_retxid
& 0xfff));
1332 LIST_INSERT_AFTER(owp
, nfsd
, nd_tq
);
1334 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1336 if (nfsd
->nd_mrep
) {
1337 wpp
= NWDELAYHASH(slp
, nfsd
->nd_fh
.fh_fid
.fid_data
);
1341 bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1343 wp
= wp
->nd_hash
.le_next
;
1345 while (wp
&& wp
->nd_off
< nfsd
->nd_off
&&
1346 !bcmp((caddr_t
)&nfsd
->nd_fh
,(caddr_t
)&wp
->nd_fh
,NFSX_V3FH
)) {
1348 wp
= wp
->nd_hash
.le_next
;
1351 LIST_INSERT_AFTER(owp
, nfsd
, nd_hash
);
1354 * Search the hash list for overlapping entries and
1357 for(; nfsd
&& NFSW_CONTIG(owp
, nfsd
); nfsd
= wp
) {
1358 wp
= nfsd
->nd_hash
.le_next
;
1359 if (NFSW_SAMECRED(owp
, nfsd
))
1360 nfsrvw_coalesce(owp
, nfsd
);
1363 LIST_INSERT_HEAD(wpp
, nfsd
, nd_hash
);
1369 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1370 * and generate the associated reply mbuf list(s).
1373 cur_usec
= nfs_curusec();
1374 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= owp
) {
1375 owp
= nfsd
->nd_tq
.le_next
;
1376 if (nfsd
->nd_time
> cur_usec
)
1380 NFS_DPF(WG
, ("P%03x", nfsd
->nd_retxid
& 0xfff));
1381 LIST_REMOVE(nfsd
, nd_tq
);
1382 LIST_REMOVE(nfsd
, nd_hash
);
1383 info
.mrep
= nfsd
->nd_mrep
;
1385 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1386 nfsd
->nd_mrep
= NULL
;
1387 cred
= &nfsd
->nd_cr
;
1388 forat_ret
= aftat_ret
= 1;
1389 error
= nfsrv_fhtovp(&nfsd
->nd_fh
, 1, &mp
, &vp
, cred
, slp
,
1390 nfsd
->nd_nam
, &rdonly
,
1391 (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
1394 forat_ret
= VOP_GETATTR(vp
, &forat
);
1395 if (vp
->v_type
!= VREG
) {
1399 error
= (vp
->v_type
== VDIR
) ? EISDIR
: EACCES
;
1405 error
= nfsrv_access(mp
, vp
, VWRITE
, cred
, rdonly
, td
, 1);
1408 if (nfsd
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1409 ioflags
= IO_NODELOCKED
;
1410 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
)
1411 ioflags
= (IO_SYNC
| IO_NODELOCKED
);
1413 ioflags
= (IO_METASYNC
| IO_SYNC
| IO_NODELOCKED
);
1414 uiop
->uio_rw
= UIO_WRITE
;
1415 uiop
->uio_segflg
= UIO_SYSSPACE
;
1416 uiop
->uio_td
= NULL
;
1417 uiop
->uio_offset
= nfsd
->nd_off
;
1418 uiop
->uio_resid
= nfsd
->nd_eoff
- nfsd
->nd_off
;
1419 if (uiop
->uio_resid
> 0) {
1427 uiop
->uio_iovcnt
= i
;
1428 iov
= kmalloc(i
* sizeof(struct iovec
), M_TEMP
, M_WAITOK
);
1429 uiop
->uio_iov
= ivp
= iov
;
1432 if (mp1
->m_len
> 0) {
1433 ivp
->iov_base
= mtod(mp1
, caddr_t
);
1434 ivp
->iov_len
= mp1
->m_len
;
1440 error
= VOP_WRITE(vp
, uiop
, ioflags
, cred
);
1441 nfsstats
.srvvop_writes
++;
1443 kfree((caddr_t
)iov
, M_TEMP
);
1448 aftat_ret
= VOP_GETATTR(vp
, &va
);
1454 * Loop around generating replies for all write rpcs that have
1455 * now been completed.
1459 NFS_DPF(WG
, ("R%03x", nfsd
->nd_retxid
& 0xfff));
1461 nfsm_writereply(&info
, nfsd
, slp
, error
,
1462 NFSX_WCCDATA(info
.v3
));
1464 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1468 nfsm_writereply(&info
, nfsd
, slp
, error
,
1469 NFSX_PREOPATTR(info
.v3
) +
1470 NFSX_POSTOPORFATTR(info
.v3
) +
1472 NFSX_WRITEVERF(info
.v3
));
1474 nfsm_srvwcc_data(&info
, nfsd
, forat_ret
, &forat
,
1476 tl
= nfsm_build(&info
, 4 * NFSX_UNSIGNED
);
1477 *tl
++ = txdr_unsigned(nfsd
->nd_len
);
1478 *tl
++ = txdr_unsigned(swp
->nd_stable
);
1480 * Actually, there is no need to txdr these fields,
1481 * but it may make the values more human readable,
1482 * for debugging purposes.
1484 if (nfsver
.tv_sec
== 0)
1486 *tl
++ = txdr_unsigned(nfsver
.tv_sec
);
1487 *tl
= txdr_unsigned(nfsver
.tv_nsec
/ 1000);
1489 fp
= nfsm_build(&info
, NFSX_V2FATTR
);
1490 nfsm_srvfattr(nfsd
, &va
, fp
);
1493 nfsd
->nd_mreq
= info
.mreq
;
1495 panic("nfsrv_write: nd_mrep not free");
1498 * Done. Put it at the head of the timer queue so that
1499 * the final phase can return the reply.
1503 LIST_INSERT_HEAD(&slp
->ns_tq
, nfsd
, nd_tq
);
1505 nfsd
= swp
->nd_coalesce
.lh_first
;
1507 LIST_REMOVE(nfsd
, nd_tq
);
1511 LIST_INSERT_HEAD(&slp
->ns_tq
, swp
, nd_tq
);
1516 * Search for a reply to return.
1518 for (nfsd
= slp
->ns_tq
.lh_first
; nfsd
; nfsd
= nfsd
->nd_tq
.le_next
) {
1519 if (nfsd
->nd_mreq
) {
1520 NFS_DPF(WG
, ("X%03x", nfsd
->nd_retxid
& 0xfff));
1521 LIST_REMOVE(nfsd
, nd_tq
);
1527 *mrq
= nfsd
->nd_mreq
;
1536 * Coalesce the write request nfsd into owp. To do this we must:
1537 * - remove nfsd from the queues
1538 * - merge nfsd->nd_mrep into owp->nd_mrep
1539 * - update the nd_eoff and nd_stable for owp
1540 * - put nfsd on owp's nd_coalesce list
1541 * NB: Must be called at splsoftclock().
1544 nfsrvw_coalesce(struct nfsrv_descript
*owp
, struct nfsrv_descript
*nfsd
)
1548 struct nfsrv_descript
*p
;
1550 NFS_DPF(WG
, ("C%03x-%03x",
1551 nfsd
->nd_retxid
& 0xfff, owp
->nd_retxid
& 0xfff));
1552 LIST_REMOVE(nfsd
, nd_hash
);
1553 LIST_REMOVE(nfsd
, nd_tq
);
1554 if (owp
->nd_eoff
< nfsd
->nd_eoff
) {
1555 overlap
= owp
->nd_eoff
- nfsd
->nd_off
;
1557 panic("nfsrv_coalesce: bad off");
1559 m_adj(nfsd
->nd_mrep
, overlap
);
1563 mp1
->m_next
= nfsd
->nd_mrep
;
1564 owp
->nd_eoff
= nfsd
->nd_eoff
;
1566 m_freem(nfsd
->nd_mrep
);
1567 nfsd
->nd_mrep
= NULL
;
1568 if (nfsd
->nd_stable
== NFSV3WRITE_FILESYNC
)
1569 owp
->nd_stable
= NFSV3WRITE_FILESYNC
;
1570 else if (nfsd
->nd_stable
== NFSV3WRITE_DATASYNC
&&
1571 owp
->nd_stable
== NFSV3WRITE_UNSTABLE
)
1572 owp
->nd_stable
= NFSV3WRITE_DATASYNC
;
1573 LIST_INSERT_HEAD(&owp
->nd_coalesce
, nfsd
, nd_tq
);
1576 * If nfsd had anything else coalesced into it, transfer them
1577 * to owp, otherwise their replies will never get sent.
1579 for (p
= nfsd
->nd_coalesce
.lh_first
; p
;
1580 p
= nfsd
->nd_coalesce
.lh_first
) {
1581 LIST_REMOVE(p
, nd_tq
);
1582 LIST_INSERT_HEAD(&owp
->nd_coalesce
, p
, nd_tq
);
1587 * nfs create service
1588 * now does a truncate to 0 length via. setattr if it already exists
1591 nfsrv_create(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
1592 struct thread
*td
, struct mbuf
**mrq
)
1594 struct sockaddr
*nam
= nfsd
->nd_nam
;
1595 struct ucred
*cred
= &nfsd
->nd_cr
;
1596 struct nfs_fattr
*fp
;
1597 struct vattr va
, dirfor
, diraft
;
1598 struct vattr
*vap
= &va
;
1599 struct nfsv2_sattr
*sp
;
1601 struct nlookupdata nd
;
1602 int error
= 0, len
, tsize
, dirfor_ret
= 1, diraft_ret
= 1;
1603 dev_t rdev
= NOUDEV
;
1605 int how
, exclusive_flag
= 0;
1609 struct mount
*mp
= NULL
;
1613 u_char cverf
[NFSX_V3CREATEVERF
];
1614 struct nfsm_info info
;
1616 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
1622 info
.mrep
= nfsd
->nd_mrep
;
1624 info
.md
= nfsd
->nd_md
;
1625 info
.dpos
= nfsd
->nd_dpos
;
1626 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
1628 fhp
= &nfh
.fh_generic
;
1629 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
1630 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
1633 * Call namei and do initial cleanup to get a few things
1634 * out of the way. If we get an initial error we cleanup
1635 * and return here to avoid special-casing the invalid nd
1636 * structure through the rest of the case. dirp may be
1637 * set even if an error occurs, but the nd structure will not
1638 * be valid at all if an error occurs so we have to invalidate it
1639 * prior to calling nfsm_reply ( which might goto nfsmout ).
1641 error
= nfs_namei(&nd
, cred
, NLC_CREATE
, &dvp
, &vp
,
1642 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
1643 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1644 mp
= vfs_getvfs(&fhp
->fh_fsid
);
1648 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
1655 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1656 NFSX_WCCDATA(info
.v3
), &error
));
1657 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
1658 diraft_ret
, &diraft
);
1664 * No error. Continue. State:
1667 * vp may be valid or NULL if the target does not
1671 * The error state is set through the code and we may also do some
1672 * opportunistic releasing of vnodes to avoid holding locks through
1673 * NFS I/O. The cleanup at the end is a catch-all
1678 NULLOUT(tl
= nfsm_dissect(&info
, NFSX_UNSIGNED
));
1679 how
= fxdr_unsigned(int, *tl
);
1681 case NFSV3CREATE_GUARDED
:
1687 case NFSV3CREATE_UNCHECKED
:
1688 ERROROUT(nfsm_srvsattr(&info
, vap
));
1690 case NFSV3CREATE_EXCLUSIVE
:
1691 NULLOUT(cp
= nfsm_dissect(&info
, NFSX_V3CREATEVERF
));
1692 bcopy(cp
, cverf
, NFSX_V3CREATEVERF
);
1696 vap
->va_type
= VREG
;
1698 NULLOUT(sp
= nfsm_dissect(&info
, NFSX_V2SATTR
));
1699 vap
->va_type
= IFTOVT(fxdr_unsigned(u_int32_t
, sp
->sa_mode
));
1700 if (vap
->va_type
== VNON
)
1701 vap
->va_type
= VREG
;
1702 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
1703 switch (vap
->va_type
) {
1705 tsize
= fxdr_unsigned(int32_t, sp
->sa_size
);
1707 vap
->va_size
= (u_quad_t
)tsize
;
1712 rdev
= fxdr_unsigned(long, sp
->sa_size
);
1720 * Iff doesn't exist, create it
1721 * otherwise just truncate to 0 length
1722 * should I set the mode too ?
1724 * The only possible error we can have at this point is EEXIST.
1725 * nd.ni_vp will also be non-NULL in that case.
1728 if (vap
->va_mode
== (mode_t
)VNOVAL
)
1730 if (vap
->va_type
== VREG
|| vap
->va_type
== VSOCK
) {
1732 error
= VOP_NCREATE(&nd
.nl_nch
, dvp
, &vp
,
1737 if (exclusive_flag
) {
1740 bcopy(cverf
, (caddr_t
)&vap
->va_atime
,
1742 error
= VOP_SETATTR(vp
, vap
, cred
);
1746 vap
->va_type
== VCHR
||
1747 vap
->va_type
== VBLK
||
1748 vap
->va_type
== VFIFO
1751 * Handle SysV FIFO node special cases. All other
1752 * devices require super user to access.
1754 if (vap
->va_type
== VCHR
&& rdev
== 0xffffffff)
1755 vap
->va_type
= VFIFO
;
1756 if (vap
->va_type
!= VFIFO
&&
1757 (error
= caps_priv_check(cred
,
1758 SYSCAP_RESTRICTEDROOT
)))
1762 vap
->va_rmajor
= umajor(rdev
);
1763 vap
->va_rminor
= uminor(rdev
);
1766 error
= VOP_NMKNOD(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
);
1773 * XXX what is this junk supposed to do ?
1780 * release dvp prior to lookup
1788 * Even though LOCKPARENT was cleared, ni_dvp may
1791 nd
.ni_cnd
.cn_nameiop
= NAMEI_LOOKUP
;
1792 nd
.ni_cnd
.cn_flags
&= ~(CNP_LOCKPARENT
);
1793 nd
.ni_cnd
.cn_td
= td
;
1794 nd
.ni_cnd
.cn_cred
= cred
;
1796 error
= lookup(&nd
);
1800 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1802 /* fall through on certain errors */
1804 nfsrv_object_create(nd
.ni_vp
);
1805 if (nd
.ni_cnd
.cn_flags
& CNP_ISSYMLINK
) {
1814 if (vap
->va_size
!= -1) {
1815 error
= nfsrv_access(mp
, vp
, VWRITE
, cred
,
1816 (nd
.nl_flags
& NLC_NFS_RDONLY
), td
, 0);
1818 tempsize
= vap
->va_size
;
1820 vap
->va_size
= tempsize
;
1821 error
= VOP_SETATTR(vp
, vap
, cred
);
1827 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
1828 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1830 error
= VOP_GETATTR(vp
, vap
);
1833 if (exclusive_flag
&& !error
&&
1834 bcmp(cverf
, (caddr_t
)&vap
->va_atime
, NFSX_V3CREATEVERF
))
1836 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
1840 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1841 NFSX_SRVFH(info
.v3
) + NFSX_FATTR(info
.v3
) +
1842 NFSX_WCCDATA(info
.v3
),
1846 nfsm_srvpostop_fh(&info
, fhp
);
1847 nfsm_srvpostop_attr(&info
, nfsd
, 0, vap
);
1849 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
1850 diraft_ret
, &diraft
);
1853 nfsm_srvfhtom(&info
, fhp
);
1854 fp
= nfsm_build(&info
, NFSX_V2FATTR
);
1855 nfsm_srvfattr(nfsd
, vap
, fp
);
1860 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, 0, &error
));
1883 * nfs v3 mknod service
1886 nfsrv_mknod(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
1887 struct thread
*td
, struct mbuf
**mrq
)
1889 struct sockaddr
*nam
= nfsd
->nd_nam
;
1890 struct ucred
*cred
= &nfsd
->nd_cr
;
1891 struct vattr va
, dirfor
, diraft
;
1892 struct vattr
*vap
= &va
;
1894 struct nlookupdata nd
;
1895 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
1902 struct nfsm_info info
;
1904 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
1910 info
.mrep
= nfsd
->nd_mrep
;
1912 info
.md
= nfsd
->nd_md
;
1913 info
.dpos
= nfsd
->nd_dpos
;
1915 fhp
= &nfh
.fh_generic
;
1916 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
1917 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
1920 * Handle nfs_namei() call. If an error occurs, the nd structure
1921 * is not valid. However, nfsm_*() routines may still jump to
1925 error
= nfs_namei(&nd
, cred
, NLC_CREATE
, &dvp
, &vp
,
1926 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
1927 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
1929 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
1931 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
1932 NFSX_WCCDATA(1), &error
));
1933 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
1934 diraft_ret
, &diraft
);
1938 NULLOUT(tl
= nfsm_dissect(&info
, NFSX_UNSIGNED
));
1939 vtyp
= nfsv3tov_type(*tl
);
1940 if (vtyp
!= VCHR
&& vtyp
!= VBLK
&& vtyp
!= VSOCK
&& vtyp
!= VFIFO
) {
1941 error
= NFSERR_BADTYPE
;
1945 ERROROUT(nfsm_srvsattr(&info
, vap
));
1946 if (vtyp
== VCHR
|| vtyp
== VBLK
) {
1947 NULLOUT(tl
= nfsm_dissect(&info
, 2 * NFSX_UNSIGNED
));
1948 vap
->va_rmajor
= fxdr_unsigned(u_int32_t
, *tl
++);
1949 vap
->va_rminor
= fxdr_unsigned(u_int32_t
, *tl
);
1953 * Iff doesn't exist, create it.
1959 vap
->va_type
= vtyp
;
1960 if (vap
->va_mode
== (mode_t
)VNOVAL
)
1962 if (vtyp
== VSOCK
) {
1964 error
= VOP_NCREATE(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
);
1968 if (vtyp
!= VFIFO
&&
1969 (error
= caps_priv_check(cred
, SYSCAP_RESTRICTEDROOT
)))
1975 error
= VOP_NMKNOD(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
);
1983 * send response, cleanup, return.
1995 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
1996 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
1998 error
= VOP_GETATTR(vp
, vap
);
2004 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2009 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2010 NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) +
2011 NFSX_WCCDATA(1), &error
));
2013 nfsm_srvpostop_fh(&info
, fhp
);
2014 nfsm_srvpostop_attr(&info
, nfsd
, 0, vap
);
2016 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2017 diraft_ret
, &diraft
);
2037 * nfs remove service
2040 nfsrv_remove(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2041 struct thread
*td
, struct mbuf
**mrq
)
2043 struct sockaddr
*nam
= nfsd
->nd_nam
;
2044 struct ucred
*cred
= &nfsd
->nd_cr
;
2045 struct nlookupdata nd
;
2046 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2050 struct vattr dirfor
, diraft
;
2053 struct nfsm_info info
;
2055 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2061 info
.mrep
= nfsd
->nd_mrep
;
2063 info
.md
= nfsd
->nd_md
;
2064 info
.dpos
= nfsd
->nd_dpos
;
2065 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2067 fhp
= &nfh
.fh_generic
;
2068 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
2069 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
2071 error
= nfs_namei(&nd
, cred
, NLC_DELETE
, &dvp
, &vp
,
2072 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
2073 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2076 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2079 if (vp
->v_type
== VDIR
) {
2080 error
= EPERM
; /* POSIX */
2084 * The root of a mounted filesystem cannot be deleted.
2086 if (vp
->v_flag
& VROOT
) {
2098 error
= VOP_NREMOVE(&nd
.nl_nch
, dvp
, nd
.nl_cred
);
2103 if (dirp
&& info
.v3
)
2104 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2105 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_WCCDATA(info
.v3
), &error
));
2107 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2108 diraft_ret
, &diraft
);
2128 * nfs rename service
2131 nfsrv_rename(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2132 struct thread
*td
, struct mbuf
**mrq
)
2134 struct sockaddr
*nam
= nfsd
->nd_nam
;
2135 struct ucred
*cred
= &nfsd
->nd_cr
;
2136 int error
= 0, len
, len2
, fdirfor_ret
= 1, fdiraft_ret
= 1;
2137 int tdirfor_ret
= 1, tdiraft_ret
= 1;
2138 struct nlookupdata fromnd
, tond
;
2139 struct nchandle fnchd
;
2140 struct nchandle tnchd
;
2141 struct vnode
*fvp
, *fdirp
, *fdvp
;
2142 struct vnode
*tvp
, *tdirp
, *tdvp
;
2143 struct namecache
*ncp
;
2144 struct vattr fdirfor
, fdiraft
, tdirfor
, tdiraft
;
2145 int fnchd_status
= 0;
2146 int tnchd_status
= 0;
2148 fhandle_t
*ffhp
, *tfhp
;
2150 struct nfsm_info info
;
2152 info
.mrep
= nfsd
->nd_mrep
;
2154 info
.md
= nfsd
->nd_md
;
2155 info
.dpos
= nfsd
->nd_dpos
;
2156 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2158 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2162 ffhp
= &fnfh
.fh_generic
;
2163 tfhp
= &tnfh
.fh_generic
;
2166 * Clear fields incase goto nfsmout occurs from macro.
2169 nlookup_zero(&fromnd
);
2170 nlookup_zero(&tond
);
2174 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, ffhp
, &error
));
2175 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
2178 * Remember our original uid so that we can reset cr_uid before
2179 * the second nfs_namei() call, in case it is remapped.
2181 * NOTE! If nfs_namei() is called twice on the same nd, it assumes
2182 * a retry and does not try to reparse the path.
2184 saved_uid
= cred
->cr_uid
;
2186 error
= nfs_namei(&fromnd
, cred
, NLC_RENAME_SRC
,
2188 ffhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &fdirp
,
2189 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2192 fdirfor_ret
= VOP_GETATTR(fdirp
, &fdirfor
);
2195 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2196 2 * NFSX_WCCDATA(info
.v3
), &error
));
2197 nfsm_srvwcc_data(&info
, nfsd
, fdirfor_ret
, &fdirfor
,
2198 fdiraft_ret
, &fdiraft
);
2199 nfsm_srvwcc_data(&info
, nfsd
, tdirfor_ret
, &tdirfor
,
2200 tdiraft_ret
, &tdiraft
);
2205 fnchd
.mount
= fromnd
.nl_nch
.mount
;
2206 fnchd
.ncp
= fromnd
.nl_nch
.ncp
->nc_parent
;
2207 if (fnchd
.ncp
== NULL
) {
2215 * We have to unlock the from ncp before we can safely lookup
2218 KKASSERT(fromnd
.nl_flags
& NLC_NCPISLOCKED
);
2219 cache_unlock(&fromnd
.nl_nch
);
2220 fromnd
.nl_flags
&= ~NLC_NCPISLOCKED
;
2221 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, tfhp
, &error
));
2222 NEGATIVEOUT(len2
= nfsm_strsiz(&info
, NFS_MAXNAMLEN
));
2223 cred
->cr_uid
= saved_uid
;
2225 error
= nfs_namei(&tond
, cred
, NLC_RENAME_DST
, NULL
, NULL
,
2226 tfhp
, len2
, slp
, nam
, &info
.md
, &info
.dpos
, &tdirp
,
2227 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2230 tdirfor_ret
= VOP_GETATTR(tdirp
, &tdirfor
);
2234 tnchd
.mount
= tond
.nl_nch
.mount
;
2235 tnchd
.ncp
= tond
.nl_nch
.ncp
->nc_parent
;
2236 if (tnchd
.ncp
== NULL
) {
2243 cache_lock4_tondlocked(&fnchd
, &fromnd
.nl_nch
,
2244 &tnchd
, &tond
.nl_nch
,
2245 fromnd
.nl_cred
, tond
.nl_cred
);
2246 fromnd
.nl_flags
|= NLC_NCPISLOCKED
;
2251 * Revalidate namecache records and retry the lookups if necessary.
2253 if (fnchd
.ncp
!= fromnd
.nl_nch
.ncp
->nc_parent
||
2254 tnchd
.ncp
!= tond
.nl_nch
.ncp
->nc_parent
||
2255 (fromnd
.nl_nch
.ncp
->nc_flag
& (NCF_DESTROYED
| NCF_UNRESOLVED
)) ||
2256 fromnd
.nl_nch
.ncp
->nc_vp
== NULL
||
2257 (tond
.nl_nch
.ncp
->nc_flag
& (NCF_DESTROYED
| NCF_UNRESOLVED
))) {
2264 kprintf("nfs - retry rename %s to %s\n",
2265 fromnd
.nl_path
, tond
.nl_path
);
2270 * Source and target vnodes (tvp might be NULL)
2272 fvp
= fromnd
.nl_nch
.ncp
->nc_vp
;
2273 tvp
= tond
.nl_nch
.ncp
->nc_vp
;
2276 * Set fdvp and tdvp. We haven't done all the topology checks
2277 * so these can wind up NULL (e.g. if either fvp or tvp is a mount
2278 * point). If we get through the checks these will be guarenteed
2281 * Holding the children ncp's should be sufficient to prevent
2282 * fdvp and tdvp ripouts.
2284 fdvp
= fromnd
.nl_nch
.ncp
->nc_parent
->nc_vp
;
2285 tdvp
= tond
.nl_nch
.ncp
->nc_parent
->nc_vp
;
2288 if (fvp
->v_type
== VDIR
&& tvp
->v_type
!= VDIR
) {
2294 } else if (fvp
->v_type
!= VDIR
&& tvp
->v_type
== VDIR
) {
2301 if (tvp
->v_type
== VDIR
&& (tond
.nl_nch
.ncp
->nc_flag
& NCF_ISMOUNTPT
)) {
2309 if (fvp
->v_type
== VDIR
&& (fromnd
.nl_nch
.ncp
->nc_flag
& NCF_ISMOUNTPT
)) {
2316 if (fromnd
.nl_nch
.mount
!= tond
.nl_nch
.mount
) {
2323 if (fromnd
.nl_nch
.ncp
== tond
.nl_nch
.ncp
->nc_parent
) {
2331 * You cannot rename a source into itself or a subdirectory of itself.
2332 * We check this by travsering the target directory upwards looking
2333 * for a match against the source.
2336 for (ncp
= tond
.nl_nch
.ncp
; ncp
; ncp
= ncp
->nc_parent
) {
2337 if (fromnd
.nl_nch
.ncp
== ncp
) {
2345 * If source is the same as the destination (that is the
2346 * same vnode with the same name in the same directory),
2347 * then there is nothing to do.
2349 if (fromnd
.nl_nch
.ncp
== tond
.nl_nch
.ncp
)
2354 * The VOP_NRENAME function releases all vnode references &
2355 * locks prior to returning so we need to clear the pointers
2356 * to bypass cleanup code later on.
2358 error
= VOP_NRENAME(&fromnd
.nl_nch
, &tond
.nl_nch
,
2359 fdvp
, tdvp
, tond
.nl_cred
);
2368 fdiraft_ret
= VOP_GETATTR(fdirp
, &fdiraft
);
2370 tdiraft_ret
= VOP_GETATTR(tdirp
, &tdiraft
);
2371 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2372 2 * NFSX_WCCDATA(info
.v3
), &error
));
2374 nfsm_srvwcc_data(&info
, nfsd
, fdirfor_ret
, &fdirfor
,
2375 fdiraft_ret
, &fdiraft
);
2376 nfsm_srvwcc_data(&info
, nfsd
, tdirfor_ret
, &tdirfor
,
2377 tdiraft_ret
, &tdiraft
);
2383 if (fnchd_status
> 1)
2384 cache_unlock(&fnchd
);
2385 if (fnchd_status
> 0)
2387 if (tnchd_status
> 1)
2388 cache_unlock(&tnchd
);
2389 if (tnchd_status
> 0)
2395 nlookup_done(&tond
);
2398 nlookup_done(&fromnd
);
2406 nfsrv_link(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2407 struct thread
*td
, struct mbuf
**mrq
)
2409 struct sockaddr
*nam
= nfsd
->nd_nam
;
2410 struct ucred
*cred
= &nfsd
->nd_cr
;
2411 struct nlookupdata nd
;
2412 int error
= 0, rdonly
, len
, dirfor_ret
= 1, diraft_ret
= 1;
2419 struct vattr dirfor
, diraft
, at
;
2421 fhandle_t
*fhp
, *dfhp
;
2422 struct nfsm_info info
;
2424 info
.mrep
= nfsd
->nd_mrep
;
2426 info
.md
= nfsd
->nd_md
;
2427 info
.dpos
= nfsd
->nd_dpos
;
2428 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2430 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2432 dirp
= dvp
= vp
= xp
= NULL
;
2435 fhp
= &nfh
.fh_generic
;
2436 dfhp
= &dnfh
.fh_generic
;
2437 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
2438 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, dfhp
, &error
));
2439 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
2441 error
= nfsrv_fhtovp(fhp
, FALSE
, &xmp
, &xp
, cred
, slp
, nam
,
2442 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
2444 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2445 NFSX_POSTOPATTR(info
.v3
) +
2446 NFSX_WCCDATA(info
.v3
),
2448 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
2449 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2450 diraft_ret
, &diraft
);
2455 if (xp
->v_type
== VDIR
) {
2456 error
= EPERM
; /* POSIX */
2460 error
= nfs_namei(&nd
, cred
, NLC_CREATE
, &dvp
, &vp
,
2461 dfhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
2462 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2465 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2474 if (xp
->v_mount
!= dvp
->v_mount
)
2479 error
= VOP_NLINK(&nd
.nl_nch
, dvp
, xp
, nd
.nl_cred
);
2487 getret
= VOP_GETATTR(xp
, &at
);
2489 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2490 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2491 NFSX_POSTOPATTR(info
.v3
) + NFSX_WCCDATA(info
.v3
),
2494 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
2495 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2496 diraft_ret
, &diraft
);
2520 * nfs symbolic link service
2523 nfsrv_symlink(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2524 struct thread
*td
, struct mbuf
**mrq
)
2526 struct sockaddr
*nam
= nfsd
->nd_nam
;
2527 struct ucred
*cred
= &nfsd
->nd_cr
;
2528 struct vattr va
, dirfor
, diraft
;
2529 struct nlookupdata nd
;
2530 struct vattr
*vap
= &va
;
2531 struct nfsv2_sattr
*sp
;
2532 char *pathcp
= NULL
;
2535 int error
= 0, len
, len2
, dirfor_ret
= 1, diraft_ret
= 1;
2541 struct nfsm_info info
;
2543 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2549 info
.mrep
= nfsd
->nd_mrep
;
2551 info
.md
= nfsd
->nd_md
;
2552 info
.dpos
= nfsd
->nd_dpos
;
2553 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2555 fhp
= &nfh
.fh_generic
;
2556 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
2557 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
2559 error
= nfs_namei(&nd
, cred
, NLC_CREATE
, &dvp
, &vp
,
2560 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
2561 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2564 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2571 ERROROUT(nfsm_srvsattr(&info
, vap
));
2573 NEGATIVEOUT(len2
= nfsm_strsiz(&info
, NFS_MAXPATHLEN
));
2574 pathcp
= kmalloc(len2
+ 1, M_TEMP
, M_WAITOK
);
2575 iv
.iov_base
= pathcp
;
2577 io
.uio_resid
= len2
;
2581 io
.uio_segflg
= UIO_SYSSPACE
;
2582 io
.uio_rw
= UIO_READ
;
2584 ERROROUT(nfsm_mtouio(&info
, &io
, len2
));
2586 NULLOUT(sp
= nfsm_dissect(&info
, NFSX_V2SATTR
));
2587 vap
->va_mode
= nfstov_mode(sp
->sa_mode
);
2589 *(pathcp
+ len2
) = '\0';
2595 if (vap
->va_mode
== (mode_t
)VNOVAL
)
2599 error
= VOP_NSYMLINK(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
, pathcp
);
2603 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
2604 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
2606 error
= VOP_GETATTR(vp
, vap
);
2621 kfree(pathcp
, M_TEMP
);
2625 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2629 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2630 NFSX_SRVFH(info
.v3
) + NFSX_POSTOPATTR(info
.v3
) +
2631 NFSX_WCCDATA(info
.v3
),
2635 nfsm_srvpostop_fh(&info
, fhp
);
2636 nfsm_srvpostop_attr(&info
, nfsd
, 0, vap
);
2638 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2639 diraft_ret
, &diraft
);
2652 kfree(pathcp
, M_TEMP
);
2660 nfsrv_mkdir(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2661 struct thread
*td
, struct mbuf
**mrq
)
2663 struct sockaddr
*nam
= nfsd
->nd_nam
;
2664 struct ucred
*cred
= &nfsd
->nd_cr
;
2665 struct vattr va
, dirfor
, diraft
;
2666 struct vattr
*vap
= &va
;
2667 struct nfs_fattr
*fp
;
2668 struct nlookupdata nd
;
2670 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2676 struct nfsm_info info
;
2678 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2684 info
.dpos
= nfsd
->nd_dpos
;
2685 info
.mrep
= nfsd
->nd_mrep
;
2687 info
.md
= nfsd
->nd_md
;
2688 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2690 fhp
= &nfh
.fh_generic
;
2691 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
2692 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
2694 error
= nfs_namei(&nd
, cred
, NLC_CREATE
, &dvp
, &vp
,
2695 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
2696 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2699 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2702 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2703 NFSX_WCCDATA(info
.v3
), &error
));
2704 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2705 diraft_ret
, &diraft
);
2711 ERROROUT(nfsm_srvsattr(&info
, vap
));
2713 NULLOUT(tl
= nfsm_dissect(&info
, NFSX_UNSIGNED
));
2714 vap
->va_mode
= nfstov_mode(*tl
++);
2718 * At this point nd.ni_dvp is referenced and exclusively locked and
2719 * nd.ni_vp, if it exists, is referenced but not locked.
2722 vap
->va_type
= VDIR
;
2729 * Issue mkdir op. Since SAVESTART is not set, the pathname
2730 * component is freed by the VOP call. This will fill-in
2731 * nd.ni_vp, reference, and exclusively lock it.
2733 if (vap
->va_mode
== (mode_t
)VNOVAL
)
2736 error
= VOP_NMKDIR(&nd
.nl_nch
, dvp
, &vp
, nd
.nl_cred
, vap
);
2741 bzero(&fhp
->fh_fid
, sizeof(fhp
->fh_fid
));
2742 error
= VFS_VPTOFH(vp
, &fhp
->fh_fid
);
2744 error
= VOP_GETATTR(vp
, vap
);
2748 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2749 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2750 NFSX_SRVFH(info
.v3
) + NFSX_POSTOPATTR(info
.v3
) +
2751 NFSX_WCCDATA(info
.v3
),
2755 nfsm_srvpostop_fh(&info
, fhp
);
2756 nfsm_srvpostop_attr(&info
, nfsd
, 0, vap
);
2758 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2759 diraft_ret
, &diraft
);
2761 nfsm_srvfhtom(&info
, fhp
);
2762 fp
= nfsm_build(&info
, NFSX_V2FATTR
);
2763 nfsm_srvfattr(nfsd
, vap
, fp
);
2788 nfsrv_rmdir(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2789 struct thread
*td
, struct mbuf
**mrq
)
2791 struct sockaddr
*nam
= nfsd
->nd_nam
;
2792 struct ucred
*cred
= &nfsd
->nd_cr
;
2793 int error
= 0, len
, dirfor_ret
= 1, diraft_ret
= 1;
2797 struct vattr dirfor
, diraft
;
2800 struct nlookupdata nd
;
2801 struct nfsm_info info
;
2803 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2809 info
.mrep
= nfsd
->nd_mrep
;
2811 info
.md
= nfsd
->nd_md
;
2812 info
.dpos
= nfsd
->nd_dpos
;
2813 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2815 fhp
= &nfh
.fh_generic
;
2816 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
2817 NEGREPLYOUT(len
= nfsm_srvnamesiz(&info
, &error
));
2819 error
= nfs_namei(&nd
, cred
, NLC_DELETE
, &dvp
, &vp
,
2820 fhp
, len
, slp
, nam
, &info
.md
, &info
.dpos
, &dirp
,
2821 td
, (nfsd
->nd_flag
& ND_KERBAUTH
), FALSE
);
2824 dirfor_ret
= VOP_GETATTR(dirp
, &dirfor
);
2827 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
2828 NFSX_WCCDATA(info
.v3
), &error
));
2829 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2830 diraft_ret
, &diraft
);
2834 if (vp
->v_type
!= VDIR
) {
2840 * The root of a mounted filesystem cannot be deleted.
2842 if (vp
->v_flag
& VROOT
)
2846 * Issue or abort op. Since SAVESTART is not set, path name
2847 * component is freed by the VOP after either.
2854 error
= VOP_NRMDIR(&nd
.nl_nch
, dvp
, nd
.nl_cred
);
2861 diraft_ret
= VOP_GETATTR(dirp
, &diraft
);
2862 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_WCCDATA(info
.v3
), &error
));
2864 nfsm_srvwcc_data(&info
, nfsd
, dirfor_ret
, &dirfor
,
2865 diraft_ret
, &diraft
);
2887 * nfs readdir service
2888 * - mallocs what it thinks is enough to read
2889 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2890 * - calls VOP_READDIR()
2891 * - loops around building the reply
2892 * if the output generated exceeds count break out of loop
2893 * The nfsm_clget macro is used here so that the reply will be packed
2894 * tightly in mbuf clusters.
2895 * - it only knows that it has encountered eof when the VOP_READDIR()
2897 * - as such one readdir rpc will return eof false although you are there
2898 * and then the next will return eof
2899 * - it trims out records with d_fileno == 0
2900 * this doesn't matter for Unix clients, but they might confuse clients
2902 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2903 * than requested, but this may not apply to all filesystems. For
2904 * example, client NFS does not { although it is never remote mounted
2906 * The alternate call nfsrv_readdirplus() does lookups as well.
2907 * PS: The NFS protocol spec. does not clarify what the "count" byte
2908 * argument is a count of.. just name strings and file id's or the
2909 * entire reply rpc or ...
2910 * I tried just file name and id sizes and it confused the Sun client,
2911 * so I am using the full rpc size now. The "paranoia.." comment refers
2912 * to including the status longwords that are not a part of the dir.
2913 * "entry" structures, but are in the rpc.
2917 u_int32_t fl_postopok
;
2918 u_int32_t fl_fattr
[NFSX_V3FATTR
/ sizeof (u_int32_t
)];
2920 u_int32_t fl_fhsize
;
2921 u_int32_t fl_nfh
[NFSX_V3FH
/ sizeof (u_int32_t
)];
2925 nfsrv_readdir(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
2926 struct thread
*td
, struct mbuf
**mrq
)
2928 struct sockaddr
*nam
= nfsd
->nd_nam
;
2929 struct ucred
*cred
= &nfsd
->nd_cr
;
2934 struct mbuf
*mp1
, *mp2
;
2935 char *cpos
, *cend
, *rbuf
;
2936 struct vnode
*vp
= NULL
;
2937 struct mount
*mp
= NULL
;
2943 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
2944 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, ncookies
;
2949 off_t
*cookies
= NULL
, *cookiep
;
2950 struct nfsm_info info
;
2952 info
.mrep
= nfsd
->nd_mrep
;
2954 info
.md
= nfsd
->nd_md
;
2955 info
.dpos
= nfsd
->nd_dpos
;
2956 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
2958 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
2959 fhp
= &nfh
.fh_generic
;
2960 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
2962 NULLOUT(tl
= nfsm_dissect(&info
, 5 * NFSX_UNSIGNED
));
2963 toff
= fxdr_hyper(tl
);
2966 verf
= fxdr_hyper(tl
);
2970 NULLOUT(tl
= nfsm_dissect(&info
, 2 * NFSX_UNSIGNED
));
2971 toff
= fxdr_unsigned(u_quad_t
, *tl
++);
2973 verf
= 0; /* shut up gcc */
2977 cnt
= fxdr_unsigned(int, *tl
);
2978 siz
= roundup2(cnt
, DIRBLKSIZ
);
2979 xfer
= NFS_SRVMAXDATA(nfsd
);
2980 if ((unsigned)cnt
> xfer
)
2982 if ((unsigned)siz
> xfer
)
2985 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
2986 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
2987 if (!error
&& vp
->v_type
!= VDIR
) {
2993 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_UNSIGNED
, &error
));
2994 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3000 * Obtain lock on vnode for this section of the code
3004 error
= getret
= VOP_GETATTR(vp
, &at
);
3007 * XXX This check may be too strict for Solaris 2.5 clients.
3009 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
3010 error
= NFSERR_BAD_COOKIE
;
3014 error
= nfsrv_access(mp
, vp
, VEXEC
, cred
, rdonly
, td
, 0);
3018 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3019 NFSX_POSTOPATTR(info
.v3
), &error
));
3020 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3027 * end section. Allocate rbuf and continue
3029 rbuf
= kmalloc(siz
, M_TEMP
, M_WAITOK
);
3032 iv
.iov_len
= fullsiz
;
3035 io
.uio_offset
= (off_t
)off
;
3036 io
.uio_resid
= fullsiz
;
3037 io
.uio_segflg
= UIO_SYSSPACE
;
3038 io
.uio_rw
= UIO_READ
;
3042 kfree((caddr_t
)cookies
, M_TEMP
);
3045 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
3046 off
= (off_t
)io
.uio_offset
;
3047 if (!cookies
&& !error
)
3048 error
= NFSERR_PERM
;
3050 getret
= VOP_GETATTR(vp
, &at
);
3057 kfree((caddr_t
)rbuf
, M_TEMP
);
3059 kfree((caddr_t
)cookies
, M_TEMP
);
3060 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3061 NFSX_POSTOPATTR(info
.v3
), &error
));
3062 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3067 siz
-= io
.uio_resid
;
3070 * If nothing read, return eof
3076 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3077 NFSX_POSTOPATTR(info
.v3
) +
3078 NFSX_COOKIEVERF(info
.v3
) +
3082 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3083 tl
= nfsm_build(&info
, 4 * NFSX_UNSIGNED
);
3084 txdr_hyper(at
.va_filerev
, tl
);
3087 tl
= nfsm_build(&info
, 2 * NFSX_UNSIGNED
);
3090 kfree((caddr_t
)rbuf
, M_TEMP
);
3091 kfree((caddr_t
)cookies
, M_TEMP
);
3098 * Check for degenerate cases of nothing useful read.
3099 * If so go try again
3103 dp
= (struct dirent
*)cpos
;
3106 * For some reason FreeBSD's ufs_readdir() chooses to back the
3107 * directory offset up to a block boundary, so it is necessary to
3108 * skip over the records that preceed the requested offset. This
3109 * requires the assumption that file offset cookies monotonically
3112 while (cpos
< cend
&& ncookies
> 0 &&
3113 (dp
->d_ino
== 0 || dp
->d_type
== DT_WHT
||
3114 ((u_quad_t
)(*cookiep
)) <= toff
)) {
3115 dp
= _DIRENT_NEXT(dp
);
3120 if (cpos
>= cend
|| ncookies
== 0) {
3126 len
= 3 * NFSX_UNSIGNED
; /* paranoia, probably can be 0 */
3127 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3128 NFSX_POSTOPATTR(info
.v3
) +
3129 NFSX_COOKIEVERF(info
.v3
) + siz
,
3132 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3133 tl
= nfsm_build(&info
, 2 * NFSX_UNSIGNED
);
3134 txdr_hyper(at
.va_filerev
, tl
);
3136 mp1
= mp2
= info
.mb
;
3138 be
= bp
+ M_TRAILINGSPACE(mp1
);
3140 /* Loop through the records and build reply */
3141 while (cpos
< cend
&& ncookies
> 0) {
3142 if (dp
->d_ino
!= 0 && dp
->d_type
!= DT_WHT
) {
3143 nlen
= dp
->d_namlen
;
3144 rem
= nfsm_rndup(nlen
) - nlen
;
3145 len
+= (4 * NFSX_UNSIGNED
+ nlen
+ rem
);
3147 len
+= 2 * NFSX_UNSIGNED
;
3153 * Build the directory record xdr from
3156 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3158 bp
+= NFSX_UNSIGNED
;
3160 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3161 *tl
= txdr_unsigned(dp
->d_ino
>> 32);
3162 bp
+= NFSX_UNSIGNED
;
3164 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3165 *tl
= txdr_unsigned(dp
->d_ino
);
3166 bp
+= NFSX_UNSIGNED
;
3167 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3168 *tl
= txdr_unsigned(nlen
);
3169 bp
+= NFSX_UNSIGNED
;
3171 /* And loop around copying the name */
3175 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3180 bcopy(cp
, bp
, tsiz
);
3186 /* And null pad to a int32_t boundary */
3187 for (i
= 0; i
< rem
; i
++)
3189 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3191 /* Finish off the record */
3193 *tl
= txdr_unsigned(*cookiep
>> 32);
3194 bp
+= NFSX_UNSIGNED
;
3195 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3197 *tl
= txdr_unsigned(*cookiep
);
3198 bp
+= NFSX_UNSIGNED
;
3200 dp
= _DIRENT_NEXT(dp
);
3207 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3209 bp
+= NFSX_UNSIGNED
;
3210 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3215 bp
+= NFSX_UNSIGNED
;
3216 if (mp1
!= info
.mb
) {
3218 mp1
->m_len
= bp
- mtod(mp1
, caddr_t
);
3220 mp1
->m_len
+= bp
- info
.bpos
;
3221 kfree((caddr_t
)rbuf
, M_TEMP
);
3222 kfree((caddr_t
)cookies
, M_TEMP
);
3232 nfsrv_readdirplus(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3233 struct thread
*td
, struct mbuf
**mrq
)
3235 struct sockaddr
*nam
= nfsd
->nd_nam
;
3236 struct ucred
*cred
= &nfsd
->nd_cr
;
3241 struct mbuf
*mp1
, *mp2
;
3242 char *cpos
, *cend
, *rbuf
;
3243 struct vnode
*vp
= NULL
, *nvp
;
3244 struct mount
*mp
= NULL
;
3247 fhandle_t
*fhp
, *nfhp
= (fhandle_t
*)fl
.fl_nfh
;
3250 struct vattr va
, at
, *vap
= &va
;
3251 struct nfs_fattr
*fp
;
3252 int len
, nlen
, rem
, xfer
, tsiz
, i
, error
= 0, getret
= 1;
3253 int siz
, cnt
, fullsiz
, eofflag
, rdonly
, dirlen
, ncookies
;
3258 off_t
*cookies
= NULL
, *cookiep
; /* needs to be int64_t or off_t */
3259 struct nfsm_info info
;
3261 info
.mrep
= nfsd
->nd_mrep
;
3263 info
.md
= nfsd
->nd_md
;
3264 info
.dpos
= nfsd
->nd_dpos
;
3265 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3267 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3268 fhp
= &nfh
.fh_generic
;
3269 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
3270 NULLOUT(tl
= nfsm_dissect(&info
, 6 * NFSX_UNSIGNED
));
3271 toff
= fxdr_hyper(tl
);
3274 verf
= fxdr_hyper(tl
);
3277 siz
= fxdr_unsigned(int, *tl
++);
3278 cnt
= fxdr_unsigned(int, *tl
);
3280 siz
= roundup2(siz
, DIRBLKSIZ
);
3281 xfer
= NFS_SRVMAXDATA(nfsd
);
3282 if ((unsigned)cnt
> xfer
)
3284 if ((unsigned)siz
> xfer
)
3287 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3288 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3289 if (!error
&& vp
->v_type
!= VDIR
) {
3295 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_UNSIGNED
, &error
));
3296 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3300 error
= getret
= VOP_GETATTR(vp
, &at
);
3303 * XXX This check may be too strict for Solaris 2.5 clients.
3305 if (!error
&& toff
&& verf
&& verf
!= at
.va_filerev
)
3306 error
= NFSERR_BAD_COOKIE
;
3309 error
= nfsrv_access(mp
, vp
, VEXEC
, cred
, rdonly
, td
, 0);
3314 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3315 NFSX_V3POSTOPATTR
, &error
));
3316 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3321 rbuf
= kmalloc(siz
, M_TEMP
, M_WAITOK
);
3324 iv
.iov_len
= fullsiz
;
3327 io
.uio_offset
= (off_t
)off
;
3328 io
.uio_resid
= fullsiz
;
3329 io
.uio_segflg
= UIO_SYSSPACE
;
3330 io
.uio_rw
= UIO_READ
;
3334 kfree((caddr_t
)cookies
, M_TEMP
);
3337 error
= VOP_READDIR(vp
, &io
, cred
, &eofflag
, &ncookies
, &cookies
);
3338 off
= (u_quad_t
)io
.uio_offset
;
3339 getret
= VOP_GETATTR(vp
, &at
);
3340 if (!cookies
&& !error
)
3341 error
= NFSERR_PERM
;
3348 kfree((caddr_t
)cookies
, M_TEMP
);
3349 kfree((caddr_t
)rbuf
, M_TEMP
);
3350 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3351 NFSX_V3POSTOPATTR
, &error
));
3352 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3357 siz
-= io
.uio_resid
;
3360 * If nothing read, return eof
3366 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3371 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3372 tl
= nfsm_build(&info
, 4 * NFSX_UNSIGNED
);
3373 txdr_hyper(at
.va_filerev
, tl
);
3377 kfree((caddr_t
)cookies
, M_TEMP
);
3378 kfree((caddr_t
)rbuf
, M_TEMP
);
3385 * Check for degenerate cases of nothing useful read.
3386 * If so go try again
3390 dp
= (struct dirent
*)cpos
;
3393 * For some reason FreeBSD's ufs_readdir() chooses to back the
3394 * directory offset up to a block boundary, so it is necessary to
3395 * skip over the records that preceed the requested offset. This
3396 * requires the assumption that file offset cookies monotonically
3399 while (cpos
< cend
&& ncookies
> 0 &&
3400 (dp
->d_ino
== 0 || dp
->d_type
== DT_WHT
||
3401 ((u_quad_t
)(*cookiep
)) <= toff
)) {
3402 dp
= _DIRENT_NEXT(dp
);
3407 if (cpos
>= cend
|| ncookies
== 0) {
3414 * Probe one of the directory entries to see if the filesystem
3417 if (VFS_VGET(vp
->v_mount
, vp
, dp
->d_ino
, &nvp
) == EOPNOTSUPP
) {
3418 error
= NFSERR_NOTSUPP
;
3421 kfree((caddr_t
)cookies
, M_TEMP
);
3422 kfree((caddr_t
)rbuf
, M_TEMP
);
3423 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3424 NFSX_V3POSTOPATTR
, &error
));
3425 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3434 dirlen
= len
= NFSX_V3POSTOPATTR
+ NFSX_V3COOKIEVERF
+
3436 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, cnt
, &error
));
3437 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3438 tl
= nfsm_build(&info
, 2 * NFSX_UNSIGNED
);
3439 txdr_hyper(at
.va_filerev
, tl
);
3440 mp1
= mp2
= info
.mb
;
3442 be
= bp
+ M_TRAILINGSPACE(mp1
);
3444 /* Loop through the records and build reply */
3445 while (cpos
< cend
&& ncookies
> 0) {
3446 if (dp
->d_ino
!= 0 && dp
->d_type
!= DT_WHT
) {
3447 nlen
= dp
->d_namlen
;
3448 rem
= nfsm_rndup(nlen
) - nlen
;
3451 * For readdir_and_lookup get the vnode using
3454 if (VFS_VGET(vp
->v_mount
, vp
, dp
->d_ino
, &nvp
))
3456 bzero((caddr_t
)nfhp
, NFSX_V3FH
);
3457 nfhp
->fh_fsid
= fhp
->fh_fsid
;
3458 if (VFS_VPTOFH(nvp
, &nfhp
->fh_fid
)) {
3463 if (VOP_GETATTR(nvp
, vap
)) {
3472 * If either the dircount or maxcount will be
3473 * exceeded, get out now. Both of these lengths
3474 * are calculated conservatively, including all
3477 len
+= (8 * NFSX_UNSIGNED
+ nlen
+ rem
+ NFSX_V3FH
+
3479 dirlen
+= (6 * NFSX_UNSIGNED
+ nlen
+ rem
);
3480 if (len
> cnt
|| dirlen
> fullsiz
) {
3486 * Build the directory record xdr from
3489 fp
= (struct nfs_fattr
*)&fl
.fl_fattr
;
3490 nfsm_srvfattr(nfsd
, vap
, fp
);
3491 fl
.fl_off
.nfsuquad
[0] = txdr_unsigned(*cookiep
>> 32);
3492 fl
.fl_off
.nfsuquad
[1] = txdr_unsigned(*cookiep
);
3493 fl
.fl_postopok
= nfs_true
;
3494 fl
.fl_fhok
= nfs_true
;
3495 fl
.fl_fhsize
= txdr_unsigned(NFSX_V3FH
);
3497 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3499 bp
+= NFSX_UNSIGNED
;
3500 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3501 *tl
= txdr_unsigned(dp
->d_ino
>> 32);
3502 bp
+= NFSX_UNSIGNED
;
3503 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3504 *tl
= txdr_unsigned(dp
->d_ino
);
3505 bp
+= NFSX_UNSIGNED
;
3506 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3507 *tl
= txdr_unsigned(nlen
);
3508 bp
+= NFSX_UNSIGNED
;
3510 /* And loop around copying the name */
3514 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3515 if ((bp
+ xfer
) > be
)
3519 bcopy(cp
, bp
, tsiz
);
3524 /* And null pad to a int32_t boundary */
3525 for (i
= 0; i
< rem
; i
++)
3529 * Now copy the flrep structure out.
3531 xfer
= sizeof (struct flrep
);
3534 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3535 if ((bp
+ xfer
) > be
)
3539 bcopy(cp
, bp
, tsiz
);
3546 dp
= _DIRENT_NEXT(dp
);
3553 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3555 bp
+= NFSX_UNSIGNED
;
3556 tl
= nfsm_clget(&info
, mp1
, mp2
, bp
, be
);
3561 bp
+= NFSX_UNSIGNED
;
3562 if (mp1
!= info
.mb
) {
3564 mp1
->m_len
= bp
- mtod(mp1
, caddr_t
);
3566 mp1
->m_len
+= bp
- info
.bpos
;
3567 kfree((caddr_t
)cookies
, M_TEMP
);
3568 kfree((caddr_t
)rbuf
, M_TEMP
);
3577 * nfs commit service
3580 nfsrv_commit(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3581 struct thread
*td
, struct mbuf
**mrq
)
3583 struct sockaddr
*nam
= nfsd
->nd_nam
;
3584 struct ucred
*cred
= &nfsd
->nd_cr
;
3585 struct vattr bfor
, aft
;
3586 struct vnode
*vp
= NULL
;
3587 struct mount
*mp
= NULL
;
3591 int error
= 0, rdonly
, for_ret
= 1, aft_ret
= 1, cnt
;
3593 struct nfsm_info info
;
3595 info
.mrep
= nfsd
->nd_mrep
;
3597 info
.md
= nfsd
->nd_md
;
3598 info
.dpos
= nfsd
->nd_dpos
;
3600 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3601 fhp
= &nfh
.fh_generic
;
3602 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
3603 NULLOUT(tl
= nfsm_dissect(&info
, 3 * NFSX_UNSIGNED
));
3606 * XXX At this time VOP_FSYNC() does not accept offset and byte
3607 * count parameters, so these arguments are useless (someday maybe).
3609 off
= fxdr_hyper(tl
);
3611 cnt
= fxdr_unsigned(int, *tl
);
3612 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3613 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3615 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3616 2 * NFSX_UNSIGNED
, &error
));
3617 nfsm_srvwcc_data(&info
, nfsd
, for_ret
, &bfor
,
3622 for_ret
= VOP_GETATTR(vp
, &bfor
);
3625 * RFC 1813 3.3.21: If count is 0, a flush from offset to the end of
3626 * file is done. At this time VOP_FSYNC does not accept offset and
3627 * byte count parameters, so call VOP_FSYNC the whole file for now.
3629 if (cnt
== 0 || cnt
> MAX_COMMIT_COUNT
) {
3631 * Give up and do the whole thing
3634 (vp
->v_object
->flags
& OBJ_MIGHTBEDIRTY
)) {
3635 vm_object_page_clean(vp
->v_object
, 0, 0, OBJPC_SYNC
);
3637 error
= VOP_FSYNC(vp
, MNT_WAIT
, 0);
3640 * Locate and synchronously write any buffers that fall
3641 * into the requested range. Note: we are assuming that
3642 * f_iosize is a power of 2.
3644 int iosize
= vp
->v_mount
->mnt_stat
.f_iosize
;
3645 int iomask
= iosize
- 1;
3649 * Align to iosize boundry, super-align to page boundry.
3652 cnt
+= off
& iomask
;
3653 off
&= ~(u_quad_t
)iomask
;
3655 if (off
& PAGE_MASK
) {
3656 cnt
+= off
& PAGE_MASK
;
3657 off
&= ~(u_quad_t
)PAGE_MASK
;
3662 (vp
->v_object
->flags
& OBJ_MIGHTBEDIRTY
)) {
3663 vm_object_page_clean(vp
->v_object
, off
/ PAGE_SIZE
,
3664 (cnt
+ PAGE_MASK
) / PAGE_SIZE
, OBJPC_SYNC
);
3668 while (error
== 0 || cnt
> 0) {
3672 * If we have a buffer and it is marked B_DELWRI we
3673 * have to lock and write it. Otherwise the prior
3674 * write is assumed to have already been committed.
3676 * WARNING: FINDBLK_TEST buffers represent stable
3677 * storage but not necessarily stable
3678 * content. It is ok in this case.
3680 if ((bp
= findblk(vp
, loffset
, FINDBLK_TEST
)) != NULL
) {
3681 if (bp
->b_flags
& B_DELWRI
)
3682 bp
= findblk(vp
, loffset
, 0);
3687 if (bp
->b_flags
& B_DELWRI
) {
3704 aft_ret
= VOP_GETATTR(vp
, &aft
);
3707 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3708 NFSX_V3WCCDATA
+ NFSX_V3WRITEVERF
,
3710 nfsm_srvwcc_data(&info
, nfsd
, for_ret
, &bfor
,
3713 tl
= nfsm_build(&info
, NFSX_V3WRITEVERF
);
3714 if (nfsver
.tv_sec
== 0)
3716 *tl
++ = txdr_unsigned(nfsver
.tv_sec
);
3717 *tl
= txdr_unsigned(nfsver
.tv_nsec
/ 1000);
3729 * nfs statfs service
3732 nfsrv_statfs(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3733 struct thread
*td
, struct mbuf
**mrq
)
3735 struct sockaddr
*nam
= nfsd
->nd_nam
;
3736 struct ucred
*cred
= &nfsd
->nd_cr
;
3738 struct nfs_statfs
*sfp
;
3739 int error
= 0, rdonly
, getret
= 1;
3740 struct vnode
*vp
= NULL
;
3741 struct mount
*mp
= NULL
;
3745 struct statfs statfs
;
3747 struct nfsm_info info
;
3749 info
.mrep
= nfsd
->nd_mrep
;
3751 info
.md
= nfsd
->nd_md
;
3752 info
.dpos
= nfsd
->nd_dpos
;
3753 info
.v3
= (nfsd
->nd_flag
& ND_NFSV3
);
3755 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3756 fhp
= &nfh
.fh_generic
;
3757 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
3758 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3759 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3761 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_UNSIGNED
, &error
));
3762 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3767 error
= VFS_STATFS(vp
->v_mount
, sf
, proc0
.p_ucred
);
3768 getret
= VOP_GETATTR(vp
, &at
);
3771 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3772 NFSX_POSTOPATTR(info
.v3
) + NFSX_STATFS(info
.v3
),
3775 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3780 sfp
= nfsm_build(&info
, NFSX_STATFS(info
.v3
));
3782 tval
= (u_quad_t
)sf
->f_blocks
;
3783 tval
*= (u_quad_t
)sf
->f_bsize
;
3784 txdr_hyper(tval
, &sfp
->sf_tbytes
);
3785 tval
= (u_quad_t
)sf
->f_bfree
;
3786 tval
*= (u_quad_t
)sf
->f_bsize
;
3787 txdr_hyper(tval
, &sfp
->sf_fbytes
);
3788 tval
= (u_quad_t
)sf
->f_bavail
;
3789 tval
*= (u_quad_t
)sf
->f_bsize
;
3790 txdr_hyper(tval
, &sfp
->sf_abytes
);
3791 sfp
->sf_tfiles
.nfsuquad
[0] = 0;
3792 sfp
->sf_tfiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_files
);
3793 sfp
->sf_ffiles
.nfsuquad
[0] = 0;
3794 sfp
->sf_ffiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3795 sfp
->sf_afiles
.nfsuquad
[0] = 0;
3796 sfp
->sf_afiles
.nfsuquad
[1] = txdr_unsigned(sf
->f_ffree
);
3797 sfp
->sf_invarsec
= 0;
3799 sfp
->sf_tsize
= txdr_unsigned(NFS_MAXDGRAMDATA
);
3800 sfp
->sf_bsize
= txdr_unsigned(sf
->f_bsize
);
3801 sfp
->sf_blocks
= txdr_unsigned(sf
->f_blocks
);
3802 sfp
->sf_bfree
= txdr_unsigned(sf
->f_bfree
);
3803 sfp
->sf_bavail
= txdr_unsigned(sf
->f_bavail
);
3813 * nfs fsinfo service
3816 nfsrv_fsinfo(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3817 struct thread
*td
, struct mbuf
**mrq
)
3819 struct sockaddr
*nam
= nfsd
->nd_nam
;
3820 struct ucred
*cred
= &nfsd
->nd_cr
;
3821 struct nfsv3_fsinfo
*sip
;
3822 int error
= 0, rdonly
, getret
= 1, pref
;
3823 struct vnode
*vp
= NULL
;
3824 struct mount
*mp
= NULL
;
3830 struct nfsm_info info
;
3832 info
.mrep
= nfsd
->nd_mrep
;
3834 info
.md
= nfsd
->nd_md
;
3835 info
.dpos
= nfsd
->nd_dpos
;
3837 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3838 fhp
= &nfh
.fh_generic
;
3839 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
3840 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3841 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3843 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_UNSIGNED
, &error
));
3844 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3849 /* XXX Try to make a guess on the max file size. */
3850 VFS_STATFS(vp
->v_mount
, &sb
, proc0
.p_ucred
);
3851 maxfsize
= (u_quad_t
)0x80000000 * sb
.f_bsize
- 1;
3853 getret
= VOP_GETATTR(vp
, &at
);
3856 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3857 NFSX_V3POSTOPATTR
+ NFSX_V3FSINFO
, &error
));
3858 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3859 sip
= nfsm_build(&info
, NFSX_V3FSINFO
);
3863 * There should be file system VFS OP(s) to get this information.
3864 * For now, assume ufs.
3866 if (slp
->ns_so
->so_type
== SOCK_DGRAM
)
3867 pref
= NFS_MAXDGRAMDATA
;
3870 sip
->fs_rtmax
= txdr_unsigned(NFS_MAXDATA
);
3871 sip
->fs_rtpref
= txdr_unsigned(pref
);
3872 sip
->fs_rtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3873 sip
->fs_wtmax
= txdr_unsigned(NFS_MAXDATA
);
3874 sip
->fs_wtpref
= txdr_unsigned(pref
);
3875 sip
->fs_wtmult
= txdr_unsigned(NFS_FABLKSIZE
);
3876 sip
->fs_dtpref
= txdr_unsigned(pref
);
3877 txdr_hyper(maxfsize
, &sip
->fs_maxfilesize
);
3878 sip
->fs_timedelta
.nfsv3_sec
= 0;
3879 sip
->fs_timedelta
.nfsv3_nsec
= txdr_unsigned(1);
3880 sip
->fs_properties
= txdr_unsigned(NFSV3FSINFO_LINK
|
3881 NFSV3FSINFO_SYMLINK
| NFSV3FSINFO_HOMOGENEOUS
|
3882 NFSV3FSINFO_CANSETTIME
);
3891 * nfs pathconf service
3894 nfsrv_pathconf(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3895 struct thread
*td
, struct mbuf
**mrq
)
3897 struct sockaddr
*nam
= nfsd
->nd_nam
;
3898 struct ucred
*cred
= &nfsd
->nd_cr
;
3899 struct nfsv3_pathconf
*pc
;
3900 int error
= 0, rdonly
, getret
= 1;
3901 register_t linkmax
, namemax
, chownres
, notrunc
;
3902 struct vnode
*vp
= NULL
;
3903 struct mount
*mp
= NULL
;
3907 struct nfsm_info info
;
3909 info
.mrep
= nfsd
->nd_mrep
;
3911 info
.md
= nfsd
->nd_md
;
3912 info
.dpos
= nfsd
->nd_dpos
;
3914 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3915 fhp
= &nfh
.fh_generic
;
3916 NEGREPLYOUT(nfsm_srvmtofh(&info
, nfsd
, fhp
, &error
));
3917 error
= nfsrv_fhtovp(fhp
, 1, &mp
, &vp
, cred
, slp
, nam
,
3918 &rdonly
, (nfsd
->nd_flag
& ND_KERBAUTH
), TRUE
);
3920 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, NFSX_UNSIGNED
, &error
));
3921 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3925 error
= VOP_PATHCONF(vp
, _PC_LINK_MAX
, &linkmax
);
3927 error
= VOP_PATHCONF(vp
, _PC_NAME_MAX
, &namemax
);
3929 error
= VOP_PATHCONF(vp
, _PC_CHOWN_RESTRICTED
, &chownres
);
3931 error
= VOP_PATHCONF(vp
, _PC_NO_TRUNC
, ¬runc
);
3932 getret
= VOP_GETATTR(vp
, &at
);
3935 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
,
3936 NFSX_V3POSTOPATTR
+ NFSX_V3PATHCONF
,
3938 nfsm_srvpostop_attr(&info
, nfsd
, getret
, &at
);
3943 pc
= nfsm_build(&info
, NFSX_V3PATHCONF
);
3945 pc
->pc_linkmax
= txdr_unsigned(linkmax
);
3946 pc
->pc_namemax
= txdr_unsigned(namemax
);
3947 pc
->pc_notrunc
= txdr_unsigned(notrunc
);
3948 pc
->pc_chownrestricted
= txdr_unsigned(chownres
);
3951 * These should probably be supported by VOP_PATHCONF(), but
3952 * until msdosfs is exportable (why would you want to?), the
3953 * Unix defaults should be ok.
3955 pc
->pc_caseinsensitive
= nfs_false
;
3956 pc
->pc_casepreserving
= nfs_true
;
3965 * Null operation, used by clients to ping server
3969 nfsrv_null(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3970 struct thread
*td
, struct mbuf
**mrq
)
3972 struct nfsm_info info
;
3973 int error
= NFSERR_RETVOID
;
3975 info
.mrep
= nfsd
->nd_mrep
;
3978 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
3979 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, 0, &error
));
3986 * No operation, used for obsolete procedures
3990 nfsrv_noop(struct nfsrv_descript
*nfsd
, struct nfssvc_sock
*slp
,
3991 struct thread
*td
, struct mbuf
**mrq
)
3993 struct nfsm_info info
;
3996 info
.mrep
= nfsd
->nd_mrep
;
3999 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
4000 if (nfsd
->nd_repstat
)
4001 error
= nfsd
->nd_repstat
;
4003 error
= EPROCUNAVAIL
;
4004 NEGKEEPOUT(nfsm_reply(&info
, nfsd
, slp
, 0, &error
));
4012 * Perform access checking for vnodes obtained from file handles that would
4013 * refer to files already opened by a Unix client. You cannot just use
4014 * vn_writechk() and VOP_ACCESS() for two reasons:
4016 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4017 * 2 - The owner is to be given access irrespective of mode bits for some
4018 * operations, so that processes that chmod after opening a file don't
4019 * break. I don't like this because it opens a security hole, but since
4020 * the nfs server opens a security hole the size of a barn door anyhow,
4023 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
4024 * will return EPERM instead of EACCESS. EPERM is always an error.
4027 nfsrv_access(struct mount
*mp
, struct vnode
*vp
, int flags
, struct ucred
*cred
,
4028 int rdonly
, struct thread
*td
, int override
)
4033 nfsdbprintf(("%s %d\n", __FILE__
, __LINE__
));
4034 if (flags
& VWRITE
) {
4035 /* Just vn_writechk() changed to check rdonly */
4037 * Disallow write attempts on read-only file systems;
4038 * unless the file is a socket or a block or character
4039 * device resident on the file system.
4042 ((mp
->mnt_flag
| vp
->v_mount
->mnt_flag
) & MNT_RDONLY
)) {
4043 switch (vp
->v_type
) {
4053 * If there's shared text associated with
4054 * the inode, we can't allow writing.
4056 if (vp
->v_flag
& VTEXT
)
4059 error
= VOP_GETATTR(vp
, &vattr
);
4062 error
= VOP_ACCESS(vp
, flags
, cred
); /* XXX ruid/rgid vs uid/gid */
4064 * Allow certain operations for the owner (reads and writes
4065 * on files that are already open).
4067 if (override
&& error
== EACCES
&& cred
->cr_uid
== vattr
.va_uid
)
4071 #endif /* NFS_NOSERVER */