Deleted Added
full compact
nfs_serv.c (24381) nfs_serv.c (25663)
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)nfs_serv.c 8.3 (Berkeley) 1/12/94
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)nfs_serv.c 8.3 (Berkeley) 1/12/94
37 * $Id: nfs_serv.c,v 1.39 1997/03/25 05:13:40 peter Exp $
37 * $Id: nfs_serv.c,v 1.40 1997/03/29 12:40:18 bde Exp $
38 */
39
40/*
41 * nfs version 2 and 3 server calls to vnode ops
42 * - these routines generally have 3 phases
43 * 1 - break down and validate rpc request in mbuf list
44 * 2 - do the vnode ops for the request
45 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
46 * 3 - build the rpc reply in an mbuf list
47 * nb:
48 * - do not mix the phases, since the nfsm_?? macros can return failures
49 * on a bad rpc or similar and do not do any vrele() or vput()'s
50 *
51 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
52 * error number iff error != 0 whereas
53 * returning an error from the server function implies a fatal error
54 * such as a badly constructed rpc request that should be dropped without
55 * a reply.
56 * For Version 3, nfsm_reply() does not return for the error case, since
57 * most version 3 rpcs return more than the status for error cases.
58 */
59
60#include <sys/param.h>
61#include <sys/systm.h>
62#include <sys/proc.h>
63#include <sys/namei.h>
64#include <sys/unistd.h>
65#include <sys/vnode.h>
66#include <sys/mount.h>
67#include <sys/socket.h>
68#include <sys/socketvar.h>
69#include <sys/mbuf.h>
70#include <sys/dirent.h>
71#include <sys/stat.h>
72#include <sys/kernel.h>
73#include <sys/sysctl.h>
74
75#include <vm/vm.h>
76#include <vm/vm_param.h>
77#include <vm/vm_object.h>
78#include <vm/vm_extern.h>
79
80#include <nfs/nfsproto.h>
81#include <nfs/rpcv2.h>
82#include <nfs/nfs.h>
83#include <nfs/xdr_subs.h>
84#include <nfs/nfsm_subs.h>
85#include <nfs/nqnfs.h>
86
87nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
88 NFFIFO, NFNON };
89#ifndef NFS_NOSERVER
90nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
91 NFCHR, NFNON };
92/* Global vars */
93extern u_long nfs_xdrneg1;
94extern u_long nfs_false, nfs_true;
95extern enum vtype nv3tov_type[8];
96extern struct nfsstats nfsstats;
97
98int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
99
100int nfs_async;
101SYSCTL_INT(_vfs_nfs, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, "");
102
103static int nfsrv_access __P((struct vnode *,int,struct ucred *,int,
104 struct proc *));
105static void nfsrvw_coalesce __P((struct nfsrv_descript *,
106 struct nfsrv_descript *));
107
108/*
109 * nfs v3 access service
110 */
111int
112nfsrv3_access(nfsd, slp, procp, mrq)
113 struct nfsrv_descript *nfsd;
114 struct nfssvc_sock *slp;
115 struct proc *procp;
116 struct mbuf **mrq;
117{
118 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
119 struct mbuf *nam = nfsd->nd_nam;
120 caddr_t dpos = nfsd->nd_dpos;
121 struct ucred *cred = &nfsd->nd_cr;
122 struct vnode *vp;
123 nfsfh_t nfh;
124 fhandle_t *fhp;
125 register u_long *tl;
126 register long t1;
127 caddr_t bpos;
128 int error = 0, rdonly, cache, getret;
129 char *cp2;
130 struct mbuf *mb, *mreq, *mb2;
131 struct vattr vattr, *vap = &vattr;
132 u_long testmode, nfsmode;
133 u_quad_t frev;
134
135#ifndef nolint
136 cache = 0;
137#endif
138 fhp = &nfh.fh_generic;
139 nfsm_srvmtofh(fhp);
140 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
141 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
142 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
143 nfsm_reply(NFSX_UNSIGNED);
144 nfsm_srvpostop_attr(1, (struct vattr *)0);
145 return (0);
146 }
147 nfsmode = fxdr_unsigned(u_long, *tl);
148 if ((nfsmode & NFSV3ACCESS_READ) &&
149 nfsrv_access(vp, VREAD, cred, rdonly, procp))
150 nfsmode &= ~NFSV3ACCESS_READ;
151 if (vp->v_type == VDIR)
152 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
153 NFSV3ACCESS_DELETE);
154 else
155 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
156 if ((nfsmode & testmode) &&
157 nfsrv_access(vp, VWRITE, cred, rdonly, procp))
158 nfsmode &= ~testmode;
159 if (vp->v_type == VDIR)
160 testmode = NFSV3ACCESS_LOOKUP;
161 else
162 testmode = NFSV3ACCESS_EXECUTE;
163 if ((nfsmode & testmode) &&
164 nfsrv_access(vp, VEXEC, cred, rdonly, procp))
165 nfsmode &= ~testmode;
166 getret = VOP_GETATTR(vp, vap, cred, procp);
167 vput(vp);
168 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
169 nfsm_srvpostop_attr(getret, vap);
170 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
171 *tl = txdr_unsigned(nfsmode);
172 nfsm_srvdone;
173}
174
175/*
176 * nfs getattr service
177 */
178int
179nfsrv_getattr(nfsd, slp, procp, mrq)
180 struct nfsrv_descript *nfsd;
181 struct nfssvc_sock *slp;
182 struct proc *procp;
183 struct mbuf **mrq;
184{
185 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
186 struct mbuf *nam = nfsd->nd_nam;
187 caddr_t dpos = nfsd->nd_dpos;
188 struct ucred *cred = &nfsd->nd_cr;
189 register struct nfs_fattr *fp;
190 struct vattr va;
191 register struct vattr *vap = &va;
192 struct vnode *vp;
193 nfsfh_t nfh;
194 fhandle_t *fhp;
195 register u_long *tl;
196 register long t1;
197 caddr_t bpos;
198 int error = 0, rdonly, cache;
199 char *cp2;
200 struct mbuf *mb, *mb2, *mreq;
201 u_quad_t frev;
202
203 fhp = &nfh.fh_generic;
204 nfsm_srvmtofh(fhp);
205 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
206 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
207 nfsm_reply(0);
208 return (0);
209 }
210 nqsrv_getl(vp, ND_READ);
211 error = VOP_GETATTR(vp, vap, cred, procp);
212 vput(vp);
213 nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
214 if (error)
215 return (0);
216 nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
217 nfsm_srvfillattr(vap, fp);
218 nfsm_srvdone;
219}
220
221/*
222 * nfs setattr service
223 */
224int
225nfsrv_setattr(nfsd, slp, procp, mrq)
226 struct nfsrv_descript *nfsd;
227 struct nfssvc_sock *slp;
228 struct proc *procp;
229 struct mbuf **mrq;
230{
231 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
232 struct mbuf *nam = nfsd->nd_nam;
233 caddr_t dpos = nfsd->nd_dpos;
234 struct ucred *cred = &nfsd->nd_cr;
235 struct vattr va, preat;
236 register struct vattr *vap = &va;
237 register struct nfsv2_sattr *sp;
238 register struct nfs_fattr *fp;
239 struct vnode *vp;
240 nfsfh_t nfh;
241 fhandle_t *fhp;
242 register u_long *tl;
243 register long t1;
244 caddr_t bpos;
245 int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1;
246 int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
247 char *cp2;
248 struct mbuf *mb, *mb2, *mreq;
249 u_quad_t frev;
250 struct timespec guard;
251
252 fhp = &nfh.fh_generic;
253 nfsm_srvmtofh(fhp);
254 VATTR_NULL(vap);
255 if (v3) {
256 nfsm_srvsattr(vap);
257 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
258 gcheck = fxdr_unsigned(int, *tl);
259 if (gcheck) {
260 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
261 fxdr_nfsv3time(tl, &guard);
262 }
263 } else {
264 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
265 /*
266 * Nah nah nah nah na nah
267 * There is a bug in the Sun client that puts 0xffff in the mode
268 * field of sattr when it should put in 0xffffffff. The u_short
269 * doesn't sign extend.
270 * --> check the low order 2 bytes for 0xffff
271 */
272 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
273 vap->va_mode = nfstov_mode(sp->sa_mode);
274 if (sp->sa_uid != nfs_xdrneg1)
275 vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
276 if (sp->sa_gid != nfs_xdrneg1)
277 vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
278 if (sp->sa_size != nfs_xdrneg1)
279 vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
280 if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
281#ifdef notyet
282 fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime);
283#else
284 vap->va_atime.tv_sec =
285 fxdr_unsigned(long, sp->sa_atime.nfsv2_sec);
286 vap->va_atime.tv_nsec = 0;
287#endif
288 }
289 if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
290 fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
291
292 }
293
294 /*
295 * Now that we have all the fields, lets do it.
296 */
297 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
298 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
299 nfsm_reply(2 * NFSX_UNSIGNED);
300 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
301 return (0);
302 }
303 nqsrv_getl(vp, ND_WRITE);
304 if (v3) {
305 error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
306 if (!error && gcheck &&
307 (preat.va_ctime.tv_sec != guard.tv_sec ||
308 preat.va_ctime.tv_nsec != guard.tv_nsec))
309 error = NFSERR_NOT_SYNC;
310 if (error) {
311 vput(vp);
312 nfsm_reply(NFSX_WCCDATA(v3));
313 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
314 return (0);
315 }
316 }
317
318 /*
319 * If the size is being changed write acces is required, otherwise
320 * just check for a read only file system.
321 */
322 if (vap->va_size == ((u_quad_t)((quad_t) -1))) {
323 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
324 error = EROFS;
325 goto out;
326 }
327 } else {
328 if (vp->v_type == VDIR) {
329 error = EISDIR;
330 goto out;
331 } else if (error = nfsrv_access(vp, VWRITE, cred, rdonly,
332 procp))
333 goto out;
334 }
335 error = VOP_SETATTR(vp, vap, cred, procp);
336 postat_ret = VOP_GETATTR(vp, vap, cred, procp);
337 if (!error)
338 error = postat_ret;
339out:
340 vput(vp);
341 nfsm_reply(NFSX_WCCORFATTR(v3));
342 if (v3) {
343 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
344 return (0);
345 } else {
346 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
347 nfsm_srvfillattr(vap, fp);
348 }
349 nfsm_srvdone;
350}
351
352/*
353 * nfs lookup rpc
354 */
355int
356nfsrv_lookup(nfsd, slp, procp, mrq)
357 struct nfsrv_descript *nfsd;
358 struct nfssvc_sock *slp;
359 struct proc *procp;
360 struct mbuf **mrq;
361{
362 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
363 struct mbuf *nam = nfsd->nd_nam;
364 caddr_t dpos = nfsd->nd_dpos;
365 struct ucred *cred = &nfsd->nd_cr;
366 register struct nfs_fattr *fp;
367 struct nameidata nd;
368 struct vnode *vp, *dirp;
369 nfsfh_t nfh;
370 fhandle_t *fhp;
371 register caddr_t cp;
372 register u_long *tl;
373 register long t1;
374 caddr_t bpos;
375 int error = 0, cache, len, dirattr_ret = 1;
376 int v3 = (nfsd->nd_flag & ND_NFSV3);
377 char *cp2;
378 struct mbuf *mb, *mb2, *mreq;
379 struct vattr va, dirattr, *vap = &va;
380 u_quad_t frev;
381
382 fhp = &nfh.fh_generic;
383 nfsm_srvmtofh(fhp);
384 nfsm_srvnamesiz(len);
385 nd.ni_cnd.cn_cred = cred;
386 nd.ni_cnd.cn_nameiop = LOOKUP;
387 nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
388 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
389 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
390 if (dirp) {
391 if (v3)
392 dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
393 procp);
394 vrele(dirp);
395 }
396 if (error) {
397 nfsm_reply(NFSX_POSTOPATTR(v3));
398 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
399 return (0);
400 }
401 nqsrv_getl(nd.ni_startdir, ND_READ);
402 vrele(nd.ni_startdir);
403 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
404 vp = nd.ni_vp;
405 bzero((caddr_t)fhp, sizeof(nfh));
406 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
407 error = VFS_VPTOFH(vp, &fhp->fh_fid);
408 if (!error)
409 error = VOP_GETATTR(vp, vap, cred, procp);
410 vput(vp);
411 nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
412 if (error) {
413 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
414 return (0);
415 }
416 nfsm_srvfhtom(fhp, v3);
417 if (v3) {
418 nfsm_srvpostop_attr(0, vap);
419 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
420 } else {
421 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
422 nfsm_srvfillattr(vap, fp);
423 }
424 nfsm_srvdone;
425}
426
427/*
428 * nfs readlink service
429 */
430int
431nfsrv_readlink(nfsd, slp, procp, mrq)
432 struct nfsrv_descript *nfsd;
433 struct nfssvc_sock *slp;
434 struct proc *procp;
435 struct mbuf **mrq;
436{
437 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
438 struct mbuf *nam = nfsd->nd_nam;
439 caddr_t dpos = nfsd->nd_dpos;
440 struct ucred *cred = &nfsd->nd_cr;
441 struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
442 register struct iovec *ivp = iv;
443 register struct mbuf *mp;
444 register u_long *tl;
445 register long t1;
446 caddr_t bpos;
447 int error = 0, rdonly, cache, i, tlen, len, getret;
448 int v3 = (nfsd->nd_flag & ND_NFSV3);
449 char *cp2;
450 struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
451 struct vnode *vp;
452 struct vattr attr;
453 nfsfh_t nfh;
454 fhandle_t *fhp;
455 struct uio io, *uiop = &io;
456 u_quad_t frev;
457
458#ifndef nolint
459 mp2 = mp3 = (struct mbuf *)0;
460#endif
461 fhp = &nfh.fh_generic;
462 nfsm_srvmtofh(fhp);
463 len = 0;
464 i = 0;
465 while (len < NFS_MAXPATHLEN) {
466 MGET(mp, M_WAIT, MT_DATA);
467 MCLGET(mp, M_WAIT);
468 mp->m_len = NFSMSIZ(mp);
469 if (len == 0)
470 mp3 = mp2 = mp;
471 else {
472 mp2->m_next = mp;
473 mp2 = mp;
474 }
475 if ((len+mp->m_len) > NFS_MAXPATHLEN) {
476 mp->m_len = NFS_MAXPATHLEN-len;
477 len = NFS_MAXPATHLEN;
478 } else
479 len += mp->m_len;
480 ivp->iov_base = mtod(mp, caddr_t);
481 ivp->iov_len = mp->m_len;
482 i++;
483 ivp++;
484 }
485 uiop->uio_iov = iv;
486 uiop->uio_iovcnt = i;
487 uiop->uio_offset = 0;
488 uiop->uio_resid = len;
489 uiop->uio_rw = UIO_READ;
490 uiop->uio_segflg = UIO_SYSSPACE;
491 uiop->uio_procp = (struct proc *)0;
492 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
493 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
494 m_freem(mp3);
495 nfsm_reply(2 * NFSX_UNSIGNED);
496 nfsm_srvpostop_attr(1, (struct vattr *)0);
497 return (0);
498 }
499 if (vp->v_type != VLNK) {
500 if (v3)
501 error = EINVAL;
502 else
503 error = ENXIO;
504 goto out;
505 }
506 nqsrv_getl(vp, ND_READ);
507 error = VOP_READLINK(vp, uiop, cred);
508out:
509 getret = VOP_GETATTR(vp, &attr, cred, procp);
510 vput(vp);
511 if (error)
512 m_freem(mp3);
513 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
514 if (v3) {
515 nfsm_srvpostop_attr(getret, &attr);
516 if (error)
517 return (0);
518 }
519 if (uiop->uio_resid > 0) {
520 len -= uiop->uio_resid;
521 tlen = nfsm_rndup(len);
522 nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
523 }
524 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
525 *tl = txdr_unsigned(len);
526 mb->m_next = mp3;
527 nfsm_srvdone;
528}
529
530/*
531 * nfs read service
532 */
533int
534nfsrv_read(nfsd, slp, procp, mrq)
535 struct nfsrv_descript *nfsd;
536 struct nfssvc_sock *slp;
537 struct proc *procp;
538 struct mbuf **mrq;
539{
540 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
541 struct mbuf *nam = nfsd->nd_nam;
542 caddr_t dpos = nfsd->nd_dpos;
543 struct ucred *cred = &nfsd->nd_cr;
544 register struct iovec *iv;
545 struct iovec *iv2;
546 register struct mbuf *m;
547 register struct nfs_fattr *fp;
548 register u_long *tl;
549 register long t1;
550 register int i;
551 caddr_t bpos;
552 int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret;
553 int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen;
554 char *cp2;
555 struct mbuf *mb, *mb2, *mreq;
556 struct mbuf *m2;
557 struct vnode *vp;
558 nfsfh_t nfh;
559 fhandle_t *fhp;
560 struct uio io, *uiop = &io;
561 struct vattr va, *vap = &va;
562 off_t off;
563 u_quad_t frev;
564
565 fhp = &nfh.fh_generic;
566 nfsm_srvmtofh(fhp);
567 if (v3) {
568 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
569 fxdr_hyper(tl, &off);
570 } else {
571 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
572 off = (off_t)fxdr_unsigned(u_long, *tl);
573 }
574 nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
575 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
576 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
577 nfsm_reply(2 * NFSX_UNSIGNED);
578 nfsm_srvpostop_attr(1, (struct vattr *)0);
579 return (0);
580 }
581 if (vp->v_type != VREG) {
582 if (v3)
583 error = EINVAL;
584 else
585 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
586 }
587 if (!error) {
588 nqsrv_getl(vp, ND_READ);
589 if (error = nfsrv_access(vp, VREAD, cred, rdonly, procp))
590 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
591 }
592 getret = VOP_GETATTR(vp, vap, cred, procp);
593 if (!error)
594 error = getret;
595 if (error) {
596 vput(vp);
597 nfsm_reply(NFSX_POSTOPATTR(v3));
598 nfsm_srvpostop_attr(getret, vap);
599 return (0);
600 }
601 if (off >= vap->va_size)
602 cnt = 0;
603 else if ((off + reqlen) > vap->va_size)
604 cnt = nfsm_rndup(vap->va_size - off);
605 else
606 cnt = reqlen;
607 nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
608 if (v3) {
609 nfsm_build(tl, u_long *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
610 *tl++ = nfs_true;
611 fp = (struct nfs_fattr *)tl;
612 tl += (NFSX_V3FATTR / sizeof (u_long));
613 } else {
614 nfsm_build(tl, u_long *, NFSX_V2FATTR + NFSX_UNSIGNED);
615 fp = (struct nfs_fattr *)tl;
616 tl += (NFSX_V2FATTR / sizeof (u_long));
617 }
618 len = left = cnt;
619 if (cnt > 0) {
620 /*
621 * Generate the mbuf list with the uio_iov ref. to it.
622 */
623 i = 0;
624 m = m2 = mb;
625 while (left > 0) {
626 siz = min(M_TRAILINGSPACE(m), left);
627 if (siz > 0) {
628 left -= siz;
629 i++;
630 }
631 if (left > 0) {
632 MGET(m, M_WAIT, MT_DATA);
633 MCLGET(m, M_WAIT);
634 m->m_len = 0;
635 m2->m_next = m;
636 m2 = m;
637 }
638 }
639 MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
640 M_TEMP, M_WAITOK);
641 uiop->uio_iov = iv2 = iv;
642 m = mb;
643 left = cnt;
644 i = 0;
645 while (left > 0) {
646 if (m == NULL)
647 panic("nfsrv_read iov");
648 siz = min(M_TRAILINGSPACE(m), left);
649 if (siz > 0) {
650 iv->iov_base = mtod(m, caddr_t) + m->m_len;
651 iv->iov_len = siz;
652 m->m_len += siz;
653 left -= siz;
654 iv++;
655 i++;
656 }
657 m = m->m_next;
658 }
659 uiop->uio_iovcnt = i;
660 uiop->uio_offset = off;
661 uiop->uio_resid = cnt;
662 uiop->uio_rw = UIO_READ;
663 uiop->uio_segflg = UIO_SYSSPACE;
664 error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
665 off = uiop->uio_offset;
666 FREE((caddr_t)iv2, M_TEMP);
667 if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) {
668 if (!error)
669 error = getret;
670 m_freem(mreq);
671 vput(vp);
672 nfsm_reply(NFSX_POSTOPATTR(v3));
673 nfsm_srvpostop_attr(getret, vap);
674 return (0);
675 }
676 } else
677 uiop->uio_resid = 0;
678 vput(vp);
679 nfsm_srvfillattr(vap, fp);
680 len -= uiop->uio_resid;
681 tlen = nfsm_rndup(len);
682 if (cnt != tlen || tlen != len)
683 nfsm_adj(mb, cnt - tlen, tlen - len);
684 if (v3) {
685 *tl++ = txdr_unsigned(len);
686 if (len < reqlen)
687 *tl++ = nfs_true;
688 else
689 *tl++ = nfs_false;
690 }
691 *tl = txdr_unsigned(len);
692 nfsm_srvdone;
693}
694
695/*
696 * nfs write service
697 */
698int
699nfsrv_write(nfsd, slp, procp, mrq)
700 struct nfsrv_descript *nfsd;
701 struct nfssvc_sock *slp;
702 struct proc *procp;
703 struct mbuf **mrq;
704{
705 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
706 struct mbuf *nam = nfsd->nd_nam;
707 caddr_t dpos = nfsd->nd_dpos;
708 struct ucred *cred = &nfsd->nd_cr;
709 register struct iovec *ivp;
710 register int i, cnt;
711 register struct mbuf *mp;
712 register struct nfs_fattr *fp;
713 struct iovec *iv;
714 struct vattr va, forat;
715 register struct vattr *vap = &va;
716 register u_long *tl;
717 register long t1;
718 caddr_t bpos;
719 int error = 0, rdonly, cache, len, forat_ret = 1;
720 int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
721 int stable = NFSV3WRITE_FILESYNC;
722 int v3 = (nfsd->nd_flag & ND_NFSV3);
723 char *cp2;
724 struct mbuf *mb, *mb2, *mreq;
725 struct vnode *vp;
726 nfsfh_t nfh;
727 fhandle_t *fhp;
728 struct uio io, *uiop = &io;
729 off_t off;
730 u_quad_t frev;
731
732 if (mrep == NULL) {
733 *mrq = NULL;
734 return (0);
735 }
736 fhp = &nfh.fh_generic;
737 nfsm_srvmtofh(fhp);
738 if (v3) {
739 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
740 fxdr_hyper(tl, &off);
741 tl += 3;
742 stable = fxdr_unsigned(int, *tl++);
743 } else {
744 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
745 off = (off_t)fxdr_unsigned(u_long, *++tl);
746 tl += 2;
747 if (nfs_async)
748 stable = NFSV3WRITE_UNSTABLE;
749 }
750 retlen = len = fxdr_unsigned(long, *tl);
751 cnt = i = 0;
752
753 /*
754 * For NFS Version 2, it is not obvious what a write of zero length
755 * should do, but I might as well be consistent with Version 3,
756 * which is to return ok so long as there are no permission problems.
757 */
758 if (len > 0) {
759 zeroing = 1;
760 mp = mrep;
761 while (mp) {
762 if (mp == md) {
763 zeroing = 0;
764 adjust = dpos - mtod(mp, caddr_t);
765 mp->m_len -= adjust;
766 if (mp->m_len > 0 && adjust > 0)
767 NFSMADV(mp, adjust);
768 }
769 if (zeroing)
770 mp->m_len = 0;
771 else if (mp->m_len > 0) {
772 i += mp->m_len;
773 if (i > len) {
774 mp->m_len -= (i - len);
775 zeroing = 1;
776 }
777 if (mp->m_len > 0)
778 cnt++;
779 }
780 mp = mp->m_next;
781 }
782 }
783 if (len > NFS_MAXDATA || len < 0 || i < len) {
784 error = EIO;
785 nfsm_reply(2 * NFSX_UNSIGNED);
786 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
787 return (0);
788 }
789 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
790 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
791 nfsm_reply(2 * NFSX_UNSIGNED);
792 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
793 return (0);
794 }
795 if (v3)
796 forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
797 if (vp->v_type != VREG) {
798 if (v3)
799 error = EINVAL;
800 else
801 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
802 }
803 if (!error) {
804 nqsrv_getl(vp, ND_WRITE);
805 error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
806 }
807 if (error) {
808 vput(vp);
809 nfsm_reply(NFSX_WCCDATA(v3));
810 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
811 return (0);
812 }
813
814 if (len > 0) {
815 MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
816 M_WAITOK);
817 uiop->uio_iov = iv = ivp;
818 uiop->uio_iovcnt = cnt;
819 mp = mrep;
820 while (mp) {
821 if (mp->m_len > 0) {
822 ivp->iov_base = mtod(mp, caddr_t);
823 ivp->iov_len = mp->m_len;
824 ivp++;
825 }
826 mp = mp->m_next;
827 }
828
829 /*
830 * XXX
831 * The IO_METASYNC flag indicates that all metadata (and not just
832 * enough to ensure data integrity) mus be written to stable storage
833 * synchronously.
834 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
835 */
836 if (stable == NFSV3WRITE_UNSTABLE)
837 ioflags = IO_NODELOCKED;
838 else if (stable == NFSV3WRITE_DATASYNC)
839 ioflags = (IO_SYNC | IO_NODELOCKED);
840 else
841 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
842 uiop->uio_resid = len;
843 uiop->uio_rw = UIO_WRITE;
844 uiop->uio_segflg = UIO_SYSSPACE;
845 uiop->uio_procp = (struct proc *)0;
846 uiop->uio_offset = off;
847 error = VOP_WRITE(vp, uiop, ioflags, cred);
848 nfsstats.srvvop_writes++;
849 FREE((caddr_t)iv, M_TEMP);
850 }
851 aftat_ret = VOP_GETATTR(vp, vap, cred, procp);
852 vput(vp);
853 if (!error)
854 error = aftat_ret;
855 nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
856 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
857 if (v3) {
858 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
859 if (error)
860 return (0);
861 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
862 *tl++ = txdr_unsigned(retlen);
863 if (stable == NFSV3WRITE_UNSTABLE)
864 *tl++ = txdr_unsigned(stable);
865 else
866 *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
867 /*
868 * Actually, there is no need to txdr these fields,
869 * but it may make the values more human readable,
870 * for debugging purposes.
871 */
872 *tl++ = txdr_unsigned(boottime.tv_sec);
873 *tl = txdr_unsigned(boottime.tv_usec);
874 } else {
875 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
876 nfsm_srvfillattr(vap, fp);
877 }
878 nfsm_srvdone;
879}
880
881/*
882 * NFS write service with write gathering support. Called when
883 * nfsrvw_procrastinate > 0.
884 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
885 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
886 * Jan. 1994.
887 */
888int
889nfsrv_writegather(ndp, slp, procp, mrq)
890 struct nfsrv_descript **ndp;
891 struct nfssvc_sock *slp;
892 struct proc *procp;
893 struct mbuf **mrq;
894{
895 register struct iovec *ivp;
896 register struct mbuf *mp;
897 register struct nfsrv_descript *wp, *nfsd, *owp, *swp;
898 register struct nfs_fattr *fp;
899 register int i;
900 struct iovec *iov;
901 struct nfsrvw_delayhash *wpp;
902 struct ucred *cred;
903 struct vattr va, forat;
904 register u_long *tl;
905 register long t1;
906 caddr_t bpos, dpos;
907 int error = 0, rdonly, cache, len, forat_ret = 1;
908 int ioflags, aftat_ret = 1, s, adjust, v3, zeroing;
909 char *cp2;
910 struct mbuf *mb, *mb2, *mreq, *mrep, *md;
911 struct vnode *vp;
912 struct uio io, *uiop = &io;
913 u_quad_t frev, cur_usec;
914
915#ifndef nolint
916 i = 0;
917 len = 0;
918#endif
919 *mrq = NULL;
920 if (*ndp) {
921 nfsd = *ndp;
922 *ndp = NULL;
923 mrep = nfsd->nd_mrep;
924 md = nfsd->nd_md;
925 dpos = nfsd->nd_dpos;
926 cred = &nfsd->nd_cr;
927 v3 = (nfsd->nd_flag & ND_NFSV3);
928 LIST_INIT(&nfsd->nd_coalesce);
929 nfsd->nd_mreq = NULL;
930 nfsd->nd_stable = NFSV3WRITE_FILESYNC;
931 cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
932 nfsd->nd_time = cur_usec + nfsrvw_procrastinate;
933
934 /*
935 * Now, get the write header..
936 */
937 nfsm_srvmtofh(&nfsd->nd_fh);
938 if (v3) {
939 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
940 fxdr_hyper(tl, &nfsd->nd_off);
941 tl += 3;
942 nfsd->nd_stable = fxdr_unsigned(int, *tl++);
943 } else {
944 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
945 nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl);
946 tl += 2;
947 if (nfs_async)
948 nfsd->nd_stable = NFSV3WRITE_UNSTABLE;
949 }
950 len = fxdr_unsigned(long, *tl);
951 nfsd->nd_len = len;
952 nfsd->nd_eoff = nfsd->nd_off + len;
953
954 /*
955 * Trim the header out of the mbuf list and trim off any trailing
956 * junk so that the mbuf list has only the write data.
957 */
958 zeroing = 1;
959 i = 0;
960 mp = mrep;
961 while (mp) {
962 if (mp == md) {
963 zeroing = 0;
964 adjust = dpos - mtod(mp, caddr_t);
965 mp->m_len -= adjust;
966 if (mp->m_len > 0 && adjust > 0)
967 NFSMADV(mp, adjust);
968 }
969 if (zeroing)
970 mp->m_len = 0;
971 else {
972 i += mp->m_len;
973 if (i > len) {
974 mp->m_len -= (i - len);
975 zeroing = 1;
976 }
977 }
978 mp = mp->m_next;
979 }
980 if (len > NFS_MAXDATA || len < 0 || i < len) {
981nfsmout:
982 m_freem(mrep);
983 error = EIO;
984 nfsm_writereply(2 * NFSX_UNSIGNED, v3);
985 if (v3)
986 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
987 nfsd->nd_mreq = mreq;
988 nfsd->nd_mrep = NULL;
989 nfsd->nd_time = 0;
990 }
991
992 /*
993 * Add this entry to the hash and time queues.
994 */
995 s = splsoftclock();
996 owp = NULL;
997 wp = slp->ns_tq.lh_first;
998 while (wp && wp->nd_time < nfsd->nd_time) {
999 owp = wp;
1000 wp = wp->nd_tq.le_next;
1001 }
38 */
39
40/*
41 * nfs version 2 and 3 server calls to vnode ops
42 * - these routines generally have 3 phases
43 * 1 - break down and validate rpc request in mbuf list
44 * 2 - do the vnode ops for the request
45 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
46 * 3 - build the rpc reply in an mbuf list
47 * nb:
48 * - do not mix the phases, since the nfsm_?? macros can return failures
49 * on a bad rpc or similar and do not do any vrele() or vput()'s
50 *
51 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
52 * error number iff error != 0 whereas
53 * returning an error from the server function implies a fatal error
54 * such as a badly constructed rpc request that should be dropped without
55 * a reply.
56 * For Version 3, nfsm_reply() does not return for the error case, since
57 * most version 3 rpcs return more than the status for error cases.
58 */
59
60#include <sys/param.h>
61#include <sys/systm.h>
62#include <sys/proc.h>
63#include <sys/namei.h>
64#include <sys/unistd.h>
65#include <sys/vnode.h>
66#include <sys/mount.h>
67#include <sys/socket.h>
68#include <sys/socketvar.h>
69#include <sys/mbuf.h>
70#include <sys/dirent.h>
71#include <sys/stat.h>
72#include <sys/kernel.h>
73#include <sys/sysctl.h>
74
75#include <vm/vm.h>
76#include <vm/vm_param.h>
77#include <vm/vm_object.h>
78#include <vm/vm_extern.h>
79
80#include <nfs/nfsproto.h>
81#include <nfs/rpcv2.h>
82#include <nfs/nfs.h>
83#include <nfs/xdr_subs.h>
84#include <nfs/nfsm_subs.h>
85#include <nfs/nqnfs.h>
86
87nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
88 NFFIFO, NFNON };
89#ifndef NFS_NOSERVER
90nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
91 NFCHR, NFNON };
92/* Global vars */
93extern u_long nfs_xdrneg1;
94extern u_long nfs_false, nfs_true;
95extern enum vtype nv3tov_type[8];
96extern struct nfsstats nfsstats;
97
98int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
99
100int nfs_async;
101SYSCTL_INT(_vfs_nfs, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, "");
102
103static int nfsrv_access __P((struct vnode *,int,struct ucred *,int,
104 struct proc *));
105static void nfsrvw_coalesce __P((struct nfsrv_descript *,
106 struct nfsrv_descript *));
107
108/*
109 * nfs v3 access service
110 */
111int
112nfsrv3_access(nfsd, slp, procp, mrq)
113 struct nfsrv_descript *nfsd;
114 struct nfssvc_sock *slp;
115 struct proc *procp;
116 struct mbuf **mrq;
117{
118 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
119 struct mbuf *nam = nfsd->nd_nam;
120 caddr_t dpos = nfsd->nd_dpos;
121 struct ucred *cred = &nfsd->nd_cr;
122 struct vnode *vp;
123 nfsfh_t nfh;
124 fhandle_t *fhp;
125 register u_long *tl;
126 register long t1;
127 caddr_t bpos;
128 int error = 0, rdonly, cache, getret;
129 char *cp2;
130 struct mbuf *mb, *mreq, *mb2;
131 struct vattr vattr, *vap = &vattr;
132 u_long testmode, nfsmode;
133 u_quad_t frev;
134
135#ifndef nolint
136 cache = 0;
137#endif
138 fhp = &nfh.fh_generic;
139 nfsm_srvmtofh(fhp);
140 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
141 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
142 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
143 nfsm_reply(NFSX_UNSIGNED);
144 nfsm_srvpostop_attr(1, (struct vattr *)0);
145 return (0);
146 }
147 nfsmode = fxdr_unsigned(u_long, *tl);
148 if ((nfsmode & NFSV3ACCESS_READ) &&
149 nfsrv_access(vp, VREAD, cred, rdonly, procp))
150 nfsmode &= ~NFSV3ACCESS_READ;
151 if (vp->v_type == VDIR)
152 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
153 NFSV3ACCESS_DELETE);
154 else
155 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
156 if ((nfsmode & testmode) &&
157 nfsrv_access(vp, VWRITE, cred, rdonly, procp))
158 nfsmode &= ~testmode;
159 if (vp->v_type == VDIR)
160 testmode = NFSV3ACCESS_LOOKUP;
161 else
162 testmode = NFSV3ACCESS_EXECUTE;
163 if ((nfsmode & testmode) &&
164 nfsrv_access(vp, VEXEC, cred, rdonly, procp))
165 nfsmode &= ~testmode;
166 getret = VOP_GETATTR(vp, vap, cred, procp);
167 vput(vp);
168 nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
169 nfsm_srvpostop_attr(getret, vap);
170 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
171 *tl = txdr_unsigned(nfsmode);
172 nfsm_srvdone;
173}
174
175/*
176 * nfs getattr service
177 */
178int
179nfsrv_getattr(nfsd, slp, procp, mrq)
180 struct nfsrv_descript *nfsd;
181 struct nfssvc_sock *slp;
182 struct proc *procp;
183 struct mbuf **mrq;
184{
185 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
186 struct mbuf *nam = nfsd->nd_nam;
187 caddr_t dpos = nfsd->nd_dpos;
188 struct ucred *cred = &nfsd->nd_cr;
189 register struct nfs_fattr *fp;
190 struct vattr va;
191 register struct vattr *vap = &va;
192 struct vnode *vp;
193 nfsfh_t nfh;
194 fhandle_t *fhp;
195 register u_long *tl;
196 register long t1;
197 caddr_t bpos;
198 int error = 0, rdonly, cache;
199 char *cp2;
200 struct mbuf *mb, *mb2, *mreq;
201 u_quad_t frev;
202
203 fhp = &nfh.fh_generic;
204 nfsm_srvmtofh(fhp);
205 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
206 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
207 nfsm_reply(0);
208 return (0);
209 }
210 nqsrv_getl(vp, ND_READ);
211 error = VOP_GETATTR(vp, vap, cred, procp);
212 vput(vp);
213 nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
214 if (error)
215 return (0);
216 nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
217 nfsm_srvfillattr(vap, fp);
218 nfsm_srvdone;
219}
220
221/*
222 * nfs setattr service
223 */
224int
225nfsrv_setattr(nfsd, slp, procp, mrq)
226 struct nfsrv_descript *nfsd;
227 struct nfssvc_sock *slp;
228 struct proc *procp;
229 struct mbuf **mrq;
230{
231 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
232 struct mbuf *nam = nfsd->nd_nam;
233 caddr_t dpos = nfsd->nd_dpos;
234 struct ucred *cred = &nfsd->nd_cr;
235 struct vattr va, preat;
236 register struct vattr *vap = &va;
237 register struct nfsv2_sattr *sp;
238 register struct nfs_fattr *fp;
239 struct vnode *vp;
240 nfsfh_t nfh;
241 fhandle_t *fhp;
242 register u_long *tl;
243 register long t1;
244 caddr_t bpos;
245 int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1;
246 int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
247 char *cp2;
248 struct mbuf *mb, *mb2, *mreq;
249 u_quad_t frev;
250 struct timespec guard;
251
252 fhp = &nfh.fh_generic;
253 nfsm_srvmtofh(fhp);
254 VATTR_NULL(vap);
255 if (v3) {
256 nfsm_srvsattr(vap);
257 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
258 gcheck = fxdr_unsigned(int, *tl);
259 if (gcheck) {
260 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
261 fxdr_nfsv3time(tl, &guard);
262 }
263 } else {
264 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
265 /*
266 * Nah nah nah nah na nah
267 * There is a bug in the Sun client that puts 0xffff in the mode
268 * field of sattr when it should put in 0xffffffff. The u_short
269 * doesn't sign extend.
270 * --> check the low order 2 bytes for 0xffff
271 */
272 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
273 vap->va_mode = nfstov_mode(sp->sa_mode);
274 if (sp->sa_uid != nfs_xdrneg1)
275 vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
276 if (sp->sa_gid != nfs_xdrneg1)
277 vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
278 if (sp->sa_size != nfs_xdrneg1)
279 vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
280 if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
281#ifdef notyet
282 fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime);
283#else
284 vap->va_atime.tv_sec =
285 fxdr_unsigned(long, sp->sa_atime.nfsv2_sec);
286 vap->va_atime.tv_nsec = 0;
287#endif
288 }
289 if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
290 fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
291
292 }
293
294 /*
295 * Now that we have all the fields, lets do it.
296 */
297 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
298 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
299 nfsm_reply(2 * NFSX_UNSIGNED);
300 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
301 return (0);
302 }
303 nqsrv_getl(vp, ND_WRITE);
304 if (v3) {
305 error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
306 if (!error && gcheck &&
307 (preat.va_ctime.tv_sec != guard.tv_sec ||
308 preat.va_ctime.tv_nsec != guard.tv_nsec))
309 error = NFSERR_NOT_SYNC;
310 if (error) {
311 vput(vp);
312 nfsm_reply(NFSX_WCCDATA(v3));
313 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
314 return (0);
315 }
316 }
317
318 /*
319 * If the size is being changed write acces is required, otherwise
320 * just check for a read only file system.
321 */
322 if (vap->va_size == ((u_quad_t)((quad_t) -1))) {
323 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
324 error = EROFS;
325 goto out;
326 }
327 } else {
328 if (vp->v_type == VDIR) {
329 error = EISDIR;
330 goto out;
331 } else if (error = nfsrv_access(vp, VWRITE, cred, rdonly,
332 procp))
333 goto out;
334 }
335 error = VOP_SETATTR(vp, vap, cred, procp);
336 postat_ret = VOP_GETATTR(vp, vap, cred, procp);
337 if (!error)
338 error = postat_ret;
339out:
340 vput(vp);
341 nfsm_reply(NFSX_WCCORFATTR(v3));
342 if (v3) {
343 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
344 return (0);
345 } else {
346 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
347 nfsm_srvfillattr(vap, fp);
348 }
349 nfsm_srvdone;
350}
351
352/*
353 * nfs lookup rpc
354 */
355int
356nfsrv_lookup(nfsd, slp, procp, mrq)
357 struct nfsrv_descript *nfsd;
358 struct nfssvc_sock *slp;
359 struct proc *procp;
360 struct mbuf **mrq;
361{
362 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
363 struct mbuf *nam = nfsd->nd_nam;
364 caddr_t dpos = nfsd->nd_dpos;
365 struct ucred *cred = &nfsd->nd_cr;
366 register struct nfs_fattr *fp;
367 struct nameidata nd;
368 struct vnode *vp, *dirp;
369 nfsfh_t nfh;
370 fhandle_t *fhp;
371 register caddr_t cp;
372 register u_long *tl;
373 register long t1;
374 caddr_t bpos;
375 int error = 0, cache, len, dirattr_ret = 1;
376 int v3 = (nfsd->nd_flag & ND_NFSV3);
377 char *cp2;
378 struct mbuf *mb, *mb2, *mreq;
379 struct vattr va, dirattr, *vap = &va;
380 u_quad_t frev;
381
382 fhp = &nfh.fh_generic;
383 nfsm_srvmtofh(fhp);
384 nfsm_srvnamesiz(len);
385 nd.ni_cnd.cn_cred = cred;
386 nd.ni_cnd.cn_nameiop = LOOKUP;
387 nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
388 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
389 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
390 if (dirp) {
391 if (v3)
392 dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
393 procp);
394 vrele(dirp);
395 }
396 if (error) {
397 nfsm_reply(NFSX_POSTOPATTR(v3));
398 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
399 return (0);
400 }
401 nqsrv_getl(nd.ni_startdir, ND_READ);
402 vrele(nd.ni_startdir);
403 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
404 vp = nd.ni_vp;
405 bzero((caddr_t)fhp, sizeof(nfh));
406 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
407 error = VFS_VPTOFH(vp, &fhp->fh_fid);
408 if (!error)
409 error = VOP_GETATTR(vp, vap, cred, procp);
410 vput(vp);
411 nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
412 if (error) {
413 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
414 return (0);
415 }
416 nfsm_srvfhtom(fhp, v3);
417 if (v3) {
418 nfsm_srvpostop_attr(0, vap);
419 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
420 } else {
421 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
422 nfsm_srvfillattr(vap, fp);
423 }
424 nfsm_srvdone;
425}
426
427/*
428 * nfs readlink service
429 */
430int
431nfsrv_readlink(nfsd, slp, procp, mrq)
432 struct nfsrv_descript *nfsd;
433 struct nfssvc_sock *slp;
434 struct proc *procp;
435 struct mbuf **mrq;
436{
437 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
438 struct mbuf *nam = nfsd->nd_nam;
439 caddr_t dpos = nfsd->nd_dpos;
440 struct ucred *cred = &nfsd->nd_cr;
441 struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
442 register struct iovec *ivp = iv;
443 register struct mbuf *mp;
444 register u_long *tl;
445 register long t1;
446 caddr_t bpos;
447 int error = 0, rdonly, cache, i, tlen, len, getret;
448 int v3 = (nfsd->nd_flag & ND_NFSV3);
449 char *cp2;
450 struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
451 struct vnode *vp;
452 struct vattr attr;
453 nfsfh_t nfh;
454 fhandle_t *fhp;
455 struct uio io, *uiop = &io;
456 u_quad_t frev;
457
458#ifndef nolint
459 mp2 = mp3 = (struct mbuf *)0;
460#endif
461 fhp = &nfh.fh_generic;
462 nfsm_srvmtofh(fhp);
463 len = 0;
464 i = 0;
465 while (len < NFS_MAXPATHLEN) {
466 MGET(mp, M_WAIT, MT_DATA);
467 MCLGET(mp, M_WAIT);
468 mp->m_len = NFSMSIZ(mp);
469 if (len == 0)
470 mp3 = mp2 = mp;
471 else {
472 mp2->m_next = mp;
473 mp2 = mp;
474 }
475 if ((len+mp->m_len) > NFS_MAXPATHLEN) {
476 mp->m_len = NFS_MAXPATHLEN-len;
477 len = NFS_MAXPATHLEN;
478 } else
479 len += mp->m_len;
480 ivp->iov_base = mtod(mp, caddr_t);
481 ivp->iov_len = mp->m_len;
482 i++;
483 ivp++;
484 }
485 uiop->uio_iov = iv;
486 uiop->uio_iovcnt = i;
487 uiop->uio_offset = 0;
488 uiop->uio_resid = len;
489 uiop->uio_rw = UIO_READ;
490 uiop->uio_segflg = UIO_SYSSPACE;
491 uiop->uio_procp = (struct proc *)0;
492 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
493 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
494 m_freem(mp3);
495 nfsm_reply(2 * NFSX_UNSIGNED);
496 nfsm_srvpostop_attr(1, (struct vattr *)0);
497 return (0);
498 }
499 if (vp->v_type != VLNK) {
500 if (v3)
501 error = EINVAL;
502 else
503 error = ENXIO;
504 goto out;
505 }
506 nqsrv_getl(vp, ND_READ);
507 error = VOP_READLINK(vp, uiop, cred);
508out:
509 getret = VOP_GETATTR(vp, &attr, cred, procp);
510 vput(vp);
511 if (error)
512 m_freem(mp3);
513 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
514 if (v3) {
515 nfsm_srvpostop_attr(getret, &attr);
516 if (error)
517 return (0);
518 }
519 if (uiop->uio_resid > 0) {
520 len -= uiop->uio_resid;
521 tlen = nfsm_rndup(len);
522 nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
523 }
524 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
525 *tl = txdr_unsigned(len);
526 mb->m_next = mp3;
527 nfsm_srvdone;
528}
529
530/*
531 * nfs read service
532 */
533int
534nfsrv_read(nfsd, slp, procp, mrq)
535 struct nfsrv_descript *nfsd;
536 struct nfssvc_sock *slp;
537 struct proc *procp;
538 struct mbuf **mrq;
539{
540 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
541 struct mbuf *nam = nfsd->nd_nam;
542 caddr_t dpos = nfsd->nd_dpos;
543 struct ucred *cred = &nfsd->nd_cr;
544 register struct iovec *iv;
545 struct iovec *iv2;
546 register struct mbuf *m;
547 register struct nfs_fattr *fp;
548 register u_long *tl;
549 register long t1;
550 register int i;
551 caddr_t bpos;
552 int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret;
553 int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen;
554 char *cp2;
555 struct mbuf *mb, *mb2, *mreq;
556 struct mbuf *m2;
557 struct vnode *vp;
558 nfsfh_t nfh;
559 fhandle_t *fhp;
560 struct uio io, *uiop = &io;
561 struct vattr va, *vap = &va;
562 off_t off;
563 u_quad_t frev;
564
565 fhp = &nfh.fh_generic;
566 nfsm_srvmtofh(fhp);
567 if (v3) {
568 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
569 fxdr_hyper(tl, &off);
570 } else {
571 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
572 off = (off_t)fxdr_unsigned(u_long, *tl);
573 }
574 nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
575 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
576 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
577 nfsm_reply(2 * NFSX_UNSIGNED);
578 nfsm_srvpostop_attr(1, (struct vattr *)0);
579 return (0);
580 }
581 if (vp->v_type != VREG) {
582 if (v3)
583 error = EINVAL;
584 else
585 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
586 }
587 if (!error) {
588 nqsrv_getl(vp, ND_READ);
589 if (error = nfsrv_access(vp, VREAD, cred, rdonly, procp))
590 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
591 }
592 getret = VOP_GETATTR(vp, vap, cred, procp);
593 if (!error)
594 error = getret;
595 if (error) {
596 vput(vp);
597 nfsm_reply(NFSX_POSTOPATTR(v3));
598 nfsm_srvpostop_attr(getret, vap);
599 return (0);
600 }
601 if (off >= vap->va_size)
602 cnt = 0;
603 else if ((off + reqlen) > vap->va_size)
604 cnt = nfsm_rndup(vap->va_size - off);
605 else
606 cnt = reqlen;
607 nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
608 if (v3) {
609 nfsm_build(tl, u_long *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
610 *tl++ = nfs_true;
611 fp = (struct nfs_fattr *)tl;
612 tl += (NFSX_V3FATTR / sizeof (u_long));
613 } else {
614 nfsm_build(tl, u_long *, NFSX_V2FATTR + NFSX_UNSIGNED);
615 fp = (struct nfs_fattr *)tl;
616 tl += (NFSX_V2FATTR / sizeof (u_long));
617 }
618 len = left = cnt;
619 if (cnt > 0) {
620 /*
621 * Generate the mbuf list with the uio_iov ref. to it.
622 */
623 i = 0;
624 m = m2 = mb;
625 while (left > 0) {
626 siz = min(M_TRAILINGSPACE(m), left);
627 if (siz > 0) {
628 left -= siz;
629 i++;
630 }
631 if (left > 0) {
632 MGET(m, M_WAIT, MT_DATA);
633 MCLGET(m, M_WAIT);
634 m->m_len = 0;
635 m2->m_next = m;
636 m2 = m;
637 }
638 }
639 MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
640 M_TEMP, M_WAITOK);
641 uiop->uio_iov = iv2 = iv;
642 m = mb;
643 left = cnt;
644 i = 0;
645 while (left > 0) {
646 if (m == NULL)
647 panic("nfsrv_read iov");
648 siz = min(M_TRAILINGSPACE(m), left);
649 if (siz > 0) {
650 iv->iov_base = mtod(m, caddr_t) + m->m_len;
651 iv->iov_len = siz;
652 m->m_len += siz;
653 left -= siz;
654 iv++;
655 i++;
656 }
657 m = m->m_next;
658 }
659 uiop->uio_iovcnt = i;
660 uiop->uio_offset = off;
661 uiop->uio_resid = cnt;
662 uiop->uio_rw = UIO_READ;
663 uiop->uio_segflg = UIO_SYSSPACE;
664 error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
665 off = uiop->uio_offset;
666 FREE((caddr_t)iv2, M_TEMP);
667 if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) {
668 if (!error)
669 error = getret;
670 m_freem(mreq);
671 vput(vp);
672 nfsm_reply(NFSX_POSTOPATTR(v3));
673 nfsm_srvpostop_attr(getret, vap);
674 return (0);
675 }
676 } else
677 uiop->uio_resid = 0;
678 vput(vp);
679 nfsm_srvfillattr(vap, fp);
680 len -= uiop->uio_resid;
681 tlen = nfsm_rndup(len);
682 if (cnt != tlen || tlen != len)
683 nfsm_adj(mb, cnt - tlen, tlen - len);
684 if (v3) {
685 *tl++ = txdr_unsigned(len);
686 if (len < reqlen)
687 *tl++ = nfs_true;
688 else
689 *tl++ = nfs_false;
690 }
691 *tl = txdr_unsigned(len);
692 nfsm_srvdone;
693}
694
695/*
696 * nfs write service
697 */
698int
699nfsrv_write(nfsd, slp, procp, mrq)
700 struct nfsrv_descript *nfsd;
701 struct nfssvc_sock *slp;
702 struct proc *procp;
703 struct mbuf **mrq;
704{
705 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
706 struct mbuf *nam = nfsd->nd_nam;
707 caddr_t dpos = nfsd->nd_dpos;
708 struct ucred *cred = &nfsd->nd_cr;
709 register struct iovec *ivp;
710 register int i, cnt;
711 register struct mbuf *mp;
712 register struct nfs_fattr *fp;
713 struct iovec *iv;
714 struct vattr va, forat;
715 register struct vattr *vap = &va;
716 register u_long *tl;
717 register long t1;
718 caddr_t bpos;
719 int error = 0, rdonly, cache, len, forat_ret = 1;
720 int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
721 int stable = NFSV3WRITE_FILESYNC;
722 int v3 = (nfsd->nd_flag & ND_NFSV3);
723 char *cp2;
724 struct mbuf *mb, *mb2, *mreq;
725 struct vnode *vp;
726 nfsfh_t nfh;
727 fhandle_t *fhp;
728 struct uio io, *uiop = &io;
729 off_t off;
730 u_quad_t frev;
731
732 if (mrep == NULL) {
733 *mrq = NULL;
734 return (0);
735 }
736 fhp = &nfh.fh_generic;
737 nfsm_srvmtofh(fhp);
738 if (v3) {
739 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
740 fxdr_hyper(tl, &off);
741 tl += 3;
742 stable = fxdr_unsigned(int, *tl++);
743 } else {
744 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
745 off = (off_t)fxdr_unsigned(u_long, *++tl);
746 tl += 2;
747 if (nfs_async)
748 stable = NFSV3WRITE_UNSTABLE;
749 }
750 retlen = len = fxdr_unsigned(long, *tl);
751 cnt = i = 0;
752
753 /*
754 * For NFS Version 2, it is not obvious what a write of zero length
755 * should do, but I might as well be consistent with Version 3,
756 * which is to return ok so long as there are no permission problems.
757 */
758 if (len > 0) {
759 zeroing = 1;
760 mp = mrep;
761 while (mp) {
762 if (mp == md) {
763 zeroing = 0;
764 adjust = dpos - mtod(mp, caddr_t);
765 mp->m_len -= adjust;
766 if (mp->m_len > 0 && adjust > 0)
767 NFSMADV(mp, adjust);
768 }
769 if (zeroing)
770 mp->m_len = 0;
771 else if (mp->m_len > 0) {
772 i += mp->m_len;
773 if (i > len) {
774 mp->m_len -= (i - len);
775 zeroing = 1;
776 }
777 if (mp->m_len > 0)
778 cnt++;
779 }
780 mp = mp->m_next;
781 }
782 }
783 if (len > NFS_MAXDATA || len < 0 || i < len) {
784 error = EIO;
785 nfsm_reply(2 * NFSX_UNSIGNED);
786 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
787 return (0);
788 }
789 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
790 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
791 nfsm_reply(2 * NFSX_UNSIGNED);
792 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
793 return (0);
794 }
795 if (v3)
796 forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
797 if (vp->v_type != VREG) {
798 if (v3)
799 error = EINVAL;
800 else
801 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
802 }
803 if (!error) {
804 nqsrv_getl(vp, ND_WRITE);
805 error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
806 }
807 if (error) {
808 vput(vp);
809 nfsm_reply(NFSX_WCCDATA(v3));
810 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
811 return (0);
812 }
813
814 if (len > 0) {
815 MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
816 M_WAITOK);
817 uiop->uio_iov = iv = ivp;
818 uiop->uio_iovcnt = cnt;
819 mp = mrep;
820 while (mp) {
821 if (mp->m_len > 0) {
822 ivp->iov_base = mtod(mp, caddr_t);
823 ivp->iov_len = mp->m_len;
824 ivp++;
825 }
826 mp = mp->m_next;
827 }
828
829 /*
830 * XXX
831 * The IO_METASYNC flag indicates that all metadata (and not just
832 * enough to ensure data integrity) mus be written to stable storage
833 * synchronously.
834 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
835 */
836 if (stable == NFSV3WRITE_UNSTABLE)
837 ioflags = IO_NODELOCKED;
838 else if (stable == NFSV3WRITE_DATASYNC)
839 ioflags = (IO_SYNC | IO_NODELOCKED);
840 else
841 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
842 uiop->uio_resid = len;
843 uiop->uio_rw = UIO_WRITE;
844 uiop->uio_segflg = UIO_SYSSPACE;
845 uiop->uio_procp = (struct proc *)0;
846 uiop->uio_offset = off;
847 error = VOP_WRITE(vp, uiop, ioflags, cred);
848 nfsstats.srvvop_writes++;
849 FREE((caddr_t)iv, M_TEMP);
850 }
851 aftat_ret = VOP_GETATTR(vp, vap, cred, procp);
852 vput(vp);
853 if (!error)
854 error = aftat_ret;
855 nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
856 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
857 if (v3) {
858 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
859 if (error)
860 return (0);
861 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
862 *tl++ = txdr_unsigned(retlen);
863 if (stable == NFSV3WRITE_UNSTABLE)
864 *tl++ = txdr_unsigned(stable);
865 else
866 *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
867 /*
868 * Actually, there is no need to txdr these fields,
869 * but it may make the values more human readable,
870 * for debugging purposes.
871 */
872 *tl++ = txdr_unsigned(boottime.tv_sec);
873 *tl = txdr_unsigned(boottime.tv_usec);
874 } else {
875 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
876 nfsm_srvfillattr(vap, fp);
877 }
878 nfsm_srvdone;
879}
880
881/*
882 * NFS write service with write gathering support. Called when
883 * nfsrvw_procrastinate > 0.
884 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
885 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
886 * Jan. 1994.
887 */
888int
889nfsrv_writegather(ndp, slp, procp, mrq)
890 struct nfsrv_descript **ndp;
891 struct nfssvc_sock *slp;
892 struct proc *procp;
893 struct mbuf **mrq;
894{
895 register struct iovec *ivp;
896 register struct mbuf *mp;
897 register struct nfsrv_descript *wp, *nfsd, *owp, *swp;
898 register struct nfs_fattr *fp;
899 register int i;
900 struct iovec *iov;
901 struct nfsrvw_delayhash *wpp;
902 struct ucred *cred;
903 struct vattr va, forat;
904 register u_long *tl;
905 register long t1;
906 caddr_t bpos, dpos;
907 int error = 0, rdonly, cache, len, forat_ret = 1;
908 int ioflags, aftat_ret = 1, s, adjust, v3, zeroing;
909 char *cp2;
910 struct mbuf *mb, *mb2, *mreq, *mrep, *md;
911 struct vnode *vp;
912 struct uio io, *uiop = &io;
913 u_quad_t frev, cur_usec;
914
915#ifndef nolint
916 i = 0;
917 len = 0;
918#endif
919 *mrq = NULL;
920 if (*ndp) {
921 nfsd = *ndp;
922 *ndp = NULL;
923 mrep = nfsd->nd_mrep;
924 md = nfsd->nd_md;
925 dpos = nfsd->nd_dpos;
926 cred = &nfsd->nd_cr;
927 v3 = (nfsd->nd_flag & ND_NFSV3);
928 LIST_INIT(&nfsd->nd_coalesce);
929 nfsd->nd_mreq = NULL;
930 nfsd->nd_stable = NFSV3WRITE_FILESYNC;
931 cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
932 nfsd->nd_time = cur_usec + nfsrvw_procrastinate;
933
934 /*
935 * Now, get the write header..
936 */
937 nfsm_srvmtofh(&nfsd->nd_fh);
938 if (v3) {
939 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
940 fxdr_hyper(tl, &nfsd->nd_off);
941 tl += 3;
942 nfsd->nd_stable = fxdr_unsigned(int, *tl++);
943 } else {
944 nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
945 nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl);
946 tl += 2;
947 if (nfs_async)
948 nfsd->nd_stable = NFSV3WRITE_UNSTABLE;
949 }
950 len = fxdr_unsigned(long, *tl);
951 nfsd->nd_len = len;
952 nfsd->nd_eoff = nfsd->nd_off + len;
953
954 /*
955 * Trim the header out of the mbuf list and trim off any trailing
956 * junk so that the mbuf list has only the write data.
957 */
958 zeroing = 1;
959 i = 0;
960 mp = mrep;
961 while (mp) {
962 if (mp == md) {
963 zeroing = 0;
964 adjust = dpos - mtod(mp, caddr_t);
965 mp->m_len -= adjust;
966 if (mp->m_len > 0 && adjust > 0)
967 NFSMADV(mp, adjust);
968 }
969 if (zeroing)
970 mp->m_len = 0;
971 else {
972 i += mp->m_len;
973 if (i > len) {
974 mp->m_len -= (i - len);
975 zeroing = 1;
976 }
977 }
978 mp = mp->m_next;
979 }
980 if (len > NFS_MAXDATA || len < 0 || i < len) {
981nfsmout:
982 m_freem(mrep);
983 error = EIO;
984 nfsm_writereply(2 * NFSX_UNSIGNED, v3);
985 if (v3)
986 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
987 nfsd->nd_mreq = mreq;
988 nfsd->nd_mrep = NULL;
989 nfsd->nd_time = 0;
990 }
991
992 /*
993 * Add this entry to the hash and time queues.
994 */
995 s = splsoftclock();
996 owp = NULL;
997 wp = slp->ns_tq.lh_first;
998 while (wp && wp->nd_time < nfsd->nd_time) {
999 owp = wp;
1000 wp = wp->nd_tq.le_next;
1001 }
1002 NFS_DPF(WG, ("Q%03x", nfsd->nd_retxid & 0xfff));
1002 if (owp) {
1003 LIST_INSERT_AFTER(owp, nfsd, nd_tq);
1004 } else {
1005 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1006 }
1007 if (nfsd->nd_mrep) {
1008 wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
1009 owp = NULL;
1010 wp = wpp->lh_first;
1011 while (wp &&
1012 bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
1013 owp = wp;
1014 wp = wp->nd_hash.le_next;
1015 }
1016 while (wp && wp->nd_off < nfsd->nd_off &&
1017 !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
1018 owp = wp;
1019 wp = wp->nd_hash.le_next;
1020 }
1021 if (owp) {
1022 LIST_INSERT_AFTER(owp, nfsd, nd_hash);
1023
1024 /*
1025 * Search the hash list for overlapping entries and
1026 * coalesce.
1027 */
1028 for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
1029 wp = nfsd->nd_hash.le_next;
1030 if (NFSW_SAMECRED(owp, nfsd))
1031 nfsrvw_coalesce(owp, nfsd);
1032 }
1033 } else {
1034 LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
1035 }
1036 }
1037 splx(s);
1038 }
1039
1040 /*
1041 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1042 * and generate the associated reply mbuf list(s).
1043 */
1044loop1:
1045 cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
1046 s = splsoftclock();
1047 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
1048 owp = nfsd->nd_tq.le_next;
1049 if (nfsd->nd_time > cur_usec)
1050 break;
1051 if (nfsd->nd_mreq)
1052 continue;
1003 if (owp) {
1004 LIST_INSERT_AFTER(owp, nfsd, nd_tq);
1005 } else {
1006 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1007 }
1008 if (nfsd->nd_mrep) {
1009 wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
1010 owp = NULL;
1011 wp = wpp->lh_first;
1012 while (wp &&
1013 bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
1014 owp = wp;
1015 wp = wp->nd_hash.le_next;
1016 }
1017 while (wp && wp->nd_off < nfsd->nd_off &&
1018 !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
1019 owp = wp;
1020 wp = wp->nd_hash.le_next;
1021 }
1022 if (owp) {
1023 LIST_INSERT_AFTER(owp, nfsd, nd_hash);
1024
1025 /*
1026 * Search the hash list for overlapping entries and
1027 * coalesce.
1028 */
1029 for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
1030 wp = nfsd->nd_hash.le_next;
1031 if (NFSW_SAMECRED(owp, nfsd))
1032 nfsrvw_coalesce(owp, nfsd);
1033 }
1034 } else {
1035 LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
1036 }
1037 }
1038 splx(s);
1039 }
1040
1041 /*
1042 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1043 * and generate the associated reply mbuf list(s).
1044 */
1045loop1:
1046 cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
1047 s = splsoftclock();
1048 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
1049 owp = nfsd->nd_tq.le_next;
1050 if (nfsd->nd_time > cur_usec)
1051 break;
1052 if (nfsd->nd_mreq)
1053 continue;
1054 NFS_DPF(WG, ("P%03x", nfsd->nd_retxid & 0xfff));
1053 LIST_REMOVE(nfsd, nd_tq);
1054 LIST_REMOVE(nfsd, nd_hash);
1055 splx(s);
1056 mrep = nfsd->nd_mrep;
1057 nfsd->nd_mrep = NULL;
1058 cred = &nfsd->nd_cr;
1059 v3 = (nfsd->nd_flag & ND_NFSV3);
1060 forat_ret = aftat_ret = 1;
1061 error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
1062 nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
1063 if (!error) {
1064 if (v3)
1065 forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
1066 if (vp->v_type != VREG) {
1067 if (v3)
1068 error = EINVAL;
1069 else
1070 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1071 }
1072 } else
1073 vp = NULL;
1074 if (!error) {
1075 nqsrv_getl(vp, ND_WRITE);
1076 error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
1077 }
1078
1079 if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1080 ioflags = IO_NODELOCKED;
1081 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1082 ioflags = (IO_SYNC | IO_NODELOCKED);
1083 else
1084 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1085 uiop->uio_rw = UIO_WRITE;
1086 uiop->uio_segflg = UIO_SYSSPACE;
1087 uiop->uio_procp = (struct proc *)0;
1088 uiop->uio_offset = nfsd->nd_off;
1089 uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
1090 if (uiop->uio_resid > 0) {
1091 mp = mrep;
1092 i = 0;
1093 while (mp) {
1094 if (mp->m_len > 0)
1095 i++;
1096 mp = mp->m_next;
1097 }
1098 uiop->uio_iovcnt = i;
1099 MALLOC(iov, struct iovec *, i * sizeof (struct iovec),
1100 M_TEMP, M_WAITOK);
1101 uiop->uio_iov = ivp = iov;
1102 mp = mrep;
1103 while (mp) {
1104 if (mp->m_len > 0) {
1105 ivp->iov_base = mtod(mp, caddr_t);
1106 ivp->iov_len = mp->m_len;
1107 ivp++;
1108 }
1109 mp = mp->m_next;
1110 }
1111 if (!error) {
1112 error = VOP_WRITE(vp, uiop, ioflags, cred);
1113 nfsstats.srvvop_writes++;
1114 }
1115 FREE((caddr_t)iov, M_TEMP);
1116 }
1117 m_freem(mrep);
1118 if (vp) {
1119 aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
1120 vput(vp);
1121 }
1122
1123 /*
1124 * Loop around generating replies for all write rpcs that have
1125 * now been completed.
1126 */
1127 swp = nfsd;
1128 do {
1055 LIST_REMOVE(nfsd, nd_tq);
1056 LIST_REMOVE(nfsd, nd_hash);
1057 splx(s);
1058 mrep = nfsd->nd_mrep;
1059 nfsd->nd_mrep = NULL;
1060 cred = &nfsd->nd_cr;
1061 v3 = (nfsd->nd_flag & ND_NFSV3);
1062 forat_ret = aftat_ret = 1;
1063 error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
1064 nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
1065 if (!error) {
1066 if (v3)
1067 forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
1068 if (vp->v_type != VREG) {
1069 if (v3)
1070 error = EINVAL;
1071 else
1072 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1073 }
1074 } else
1075 vp = NULL;
1076 if (!error) {
1077 nqsrv_getl(vp, ND_WRITE);
1078 error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
1079 }
1080
1081 if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1082 ioflags = IO_NODELOCKED;
1083 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1084 ioflags = (IO_SYNC | IO_NODELOCKED);
1085 else
1086 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1087 uiop->uio_rw = UIO_WRITE;
1088 uiop->uio_segflg = UIO_SYSSPACE;
1089 uiop->uio_procp = (struct proc *)0;
1090 uiop->uio_offset = nfsd->nd_off;
1091 uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
1092 if (uiop->uio_resid > 0) {
1093 mp = mrep;
1094 i = 0;
1095 while (mp) {
1096 if (mp->m_len > 0)
1097 i++;
1098 mp = mp->m_next;
1099 }
1100 uiop->uio_iovcnt = i;
1101 MALLOC(iov, struct iovec *, i * sizeof (struct iovec),
1102 M_TEMP, M_WAITOK);
1103 uiop->uio_iov = ivp = iov;
1104 mp = mrep;
1105 while (mp) {
1106 if (mp->m_len > 0) {
1107 ivp->iov_base = mtod(mp, caddr_t);
1108 ivp->iov_len = mp->m_len;
1109 ivp++;
1110 }
1111 mp = mp->m_next;
1112 }
1113 if (!error) {
1114 error = VOP_WRITE(vp, uiop, ioflags, cred);
1115 nfsstats.srvvop_writes++;
1116 }
1117 FREE((caddr_t)iov, M_TEMP);
1118 }
1119 m_freem(mrep);
1120 if (vp) {
1121 aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
1122 vput(vp);
1123 }
1124
1125 /*
1126 * Loop around generating replies for all write rpcs that have
1127 * now been completed.
1128 */
1129 swp = nfsd;
1130 do {
1131 NFS_DPF(WG, ("R%03x", nfsd->nd_retxid & 0xfff));
1129 if (error) {
1130 nfsm_writereply(NFSX_WCCDATA(v3), v3);
1131 if (v3) {
1132 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1133 }
1134 } else {
1135 nfsm_writereply(NFSX_PREOPATTR(v3) +
1136 NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
1137 NFSX_WRITEVERF(v3), v3);
1138 if (v3) {
1139 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1140 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1141 *tl++ = txdr_unsigned(nfsd->nd_len);
1142 *tl++ = txdr_unsigned(swp->nd_stable);
1143 /*
1144 * Actually, there is no need to txdr these fields,
1145 * but it may make the values more human readable,
1146 * for debugging purposes.
1147 */
1148 *tl++ = txdr_unsigned(boottime.tv_sec);
1149 *tl = txdr_unsigned(boottime.tv_usec);
1150 } else {
1151 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1152 nfsm_srvfillattr(&va, fp);
1153 }
1154 }
1155 nfsd->nd_mreq = mreq;
1156 if (nfsd->nd_mrep)
1157 panic("nfsrv_write: nd_mrep not free");
1158
1159 /*
1160 * Done. Put it at the head of the timer queue so that
1161 * the final phase can return the reply.
1162 */
1163 s = splsoftclock();
1164 if (nfsd != swp) {
1165 nfsd->nd_time = 0;
1166 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1167 }
1168 nfsd = swp->nd_coalesce.lh_first;
1169 if (nfsd) {
1170 LIST_REMOVE(nfsd, nd_tq);
1171 }
1172 splx(s);
1173 } while (nfsd);
1174 s = splsoftclock();
1175 swp->nd_time = 0;
1176 LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
1177 splx(s);
1178 goto loop1;
1179 }
1180 splx(s);
1181
1182 /*
1183 * Search for a reply to return.
1184 */
1185 s = splsoftclock();
1186 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
1187 if (nfsd->nd_mreq) {
1132 if (error) {
1133 nfsm_writereply(NFSX_WCCDATA(v3), v3);
1134 if (v3) {
1135 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1136 }
1137 } else {
1138 nfsm_writereply(NFSX_PREOPATTR(v3) +
1139 NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
1140 NFSX_WRITEVERF(v3), v3);
1141 if (v3) {
1142 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1143 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1144 *tl++ = txdr_unsigned(nfsd->nd_len);
1145 *tl++ = txdr_unsigned(swp->nd_stable);
1146 /*
1147 * Actually, there is no need to txdr these fields,
1148 * but it may make the values more human readable,
1149 * for debugging purposes.
1150 */
1151 *tl++ = txdr_unsigned(boottime.tv_sec);
1152 *tl = txdr_unsigned(boottime.tv_usec);
1153 } else {
1154 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1155 nfsm_srvfillattr(&va, fp);
1156 }
1157 }
1158 nfsd->nd_mreq = mreq;
1159 if (nfsd->nd_mrep)
1160 panic("nfsrv_write: nd_mrep not free");
1161
1162 /*
1163 * Done. Put it at the head of the timer queue so that
1164 * the final phase can return the reply.
1165 */
1166 s = splsoftclock();
1167 if (nfsd != swp) {
1168 nfsd->nd_time = 0;
1169 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1170 }
1171 nfsd = swp->nd_coalesce.lh_first;
1172 if (nfsd) {
1173 LIST_REMOVE(nfsd, nd_tq);
1174 }
1175 splx(s);
1176 } while (nfsd);
1177 s = splsoftclock();
1178 swp->nd_time = 0;
1179 LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
1180 splx(s);
1181 goto loop1;
1182 }
1183 splx(s);
1184
1185 /*
1186 * Search for a reply to return.
1187 */
1188 s = splsoftclock();
1189 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
1190 if (nfsd->nd_mreq) {
1191 NFS_DPF(WG, ("X%03x", nfsd->nd_retxid & 0xfff));
1188 LIST_REMOVE(nfsd, nd_tq);
1189 *mrq = nfsd->nd_mreq;
1190 *ndp = nfsd;
1191 break;
1192 }
1193 splx(s);
1194 return (0);
1195}
1196
1197/*
1198 * Coalesce the write request nfsd into owp. To do this we must:
1199 * - remove nfsd from the queues
1200 * - merge nfsd->nd_mrep into owp->nd_mrep
1201 * - update the nd_eoff and nd_stable for owp
1202 * - put nfsd on owp's nd_coalesce list
1203 * NB: Must be called at splsoftclock().
1204 */
1205static void
1206nfsrvw_coalesce(owp, nfsd)
1207 register struct nfsrv_descript *owp;
1208 register struct nfsrv_descript *nfsd;
1209{
1210 register int overlap;
1211 register struct mbuf *mp;
1192 LIST_REMOVE(nfsd, nd_tq);
1193 *mrq = nfsd->nd_mreq;
1194 *ndp = nfsd;
1195 break;
1196 }
1197 splx(s);
1198 return (0);
1199}
1200
1201/*
1202 * Coalesce the write request nfsd into owp. To do this we must:
1203 * - remove nfsd from the queues
1204 * - merge nfsd->nd_mrep into owp->nd_mrep
1205 * - update the nd_eoff and nd_stable for owp
1206 * - put nfsd on owp's nd_coalesce list
1207 * NB: Must be called at splsoftclock().
1208 */
1209static void
1210nfsrvw_coalesce(owp, nfsd)
1211 register struct nfsrv_descript *owp;
1212 register struct nfsrv_descript *nfsd;
1213{
1214 register int overlap;
1215 register struct mbuf *mp;
1216 struct nfsrv_descript *p;
1212
1217
1218 NFS_DPF(WG, ("C%03x-%03x",
1219 nfsd->nd_retxid & 0xfff, owp->nd_retxid & 0xfff));
1213 LIST_REMOVE(nfsd, nd_hash);
1214 LIST_REMOVE(nfsd, nd_tq);
1215 if (owp->nd_eoff < nfsd->nd_eoff) {
1216 overlap = owp->nd_eoff - nfsd->nd_off;
1217 if (overlap < 0)
1218 panic("nfsrv_coalesce: bad off");
1219 if (overlap > 0)
1220 m_adj(nfsd->nd_mrep, overlap);
1221 mp = owp->nd_mrep;
1222 while (mp->m_next)
1223 mp = mp->m_next;
1224 mp->m_next = nfsd->nd_mrep;
1225 owp->nd_eoff = nfsd->nd_eoff;
1226 } else
1227 m_freem(nfsd->nd_mrep);
1228 nfsd->nd_mrep = NULL;
1229 if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1230 owp->nd_stable = NFSV3WRITE_FILESYNC;
1231 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1232 owp->nd_stable == NFSV3WRITE_UNSTABLE)
1233 owp->nd_stable = NFSV3WRITE_DATASYNC;
1234 LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1220 LIST_REMOVE(nfsd, nd_hash);
1221 LIST_REMOVE(nfsd, nd_tq);
1222 if (owp->nd_eoff < nfsd->nd_eoff) {
1223 overlap = owp->nd_eoff - nfsd->nd_off;
1224 if (overlap < 0)
1225 panic("nfsrv_coalesce: bad off");
1226 if (overlap > 0)
1227 m_adj(nfsd->nd_mrep, overlap);
1228 mp = owp->nd_mrep;
1229 while (mp->m_next)
1230 mp = mp->m_next;
1231 mp->m_next = nfsd->nd_mrep;
1232 owp->nd_eoff = nfsd->nd_eoff;
1233 } else
1234 m_freem(nfsd->nd_mrep);
1235 nfsd->nd_mrep = NULL;
1236 if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1237 owp->nd_stable = NFSV3WRITE_FILESYNC;
1238 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1239 owp->nd_stable == NFSV3WRITE_UNSTABLE)
1240 owp->nd_stable = NFSV3WRITE_DATASYNC;
1241 LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1242
1243 /*
1244 * If nfsd had anything else coalesced into it, transfer them
1245 * to owp, otherwise their replies will never get sent.
1246 */
1247 for (p = nfsd->nd_coalesce.lh_first; p;
1248 p = nfsd->nd_coalesce.lh_first) {
1249 LIST_REMOVE(p, nd_tq);
1250 LIST_INSERT_HEAD(&owp->nd_coalesce, p, nd_tq);
1251 }
1235}
1236
1237/*
1238 * Sort the group list in increasing numerical order.
1239 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1240 * that used to be here.)
1241 */
1242void
1243nfsrvw_sort(list, num)
1244 register gid_t *list;
1245 register int num;
1246{
1247 register int i, j;
1248 gid_t v;
1249
1250 /* Insertion sort. */
1251 for (i = 1; i < num; i++) {
1252 v = list[i];
1253 /* find correct slot for value v, moving others up */
1254 for (j = i; --j >= 0 && v < list[j];)
1255 list[j + 1] = list[j];
1256 list[j + 1] = v;
1257 }
1258}
1259
1260/*
1261 * copy credentials making sure that the result can be compared with bcmp().
1262 */
1263void
1264nfsrv_setcred(incred, outcred)
1265 register struct ucred *incred, *outcred;
1266{
1267 register int i;
1268
1269 bzero((caddr_t)outcred, sizeof (struct ucred));
1270 outcred->cr_ref = 1;
1271 outcred->cr_uid = incred->cr_uid;
1272 outcred->cr_ngroups = incred->cr_ngroups;
1273 for (i = 0; i < incred->cr_ngroups; i++)
1274 outcred->cr_groups[i] = incred->cr_groups[i];
1275 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1276}
1277
1278/*
1279 * nfs create service
1280 * now does a truncate to 0 length via. setattr if it already exists
1281 */
1282int
1283nfsrv_create(nfsd, slp, procp, mrq)
1284 struct nfsrv_descript *nfsd;
1285 struct nfssvc_sock *slp;
1286 struct proc *procp;
1287 struct mbuf **mrq;
1288{
1289 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1290 struct mbuf *nam = nfsd->nd_nam;
1291 caddr_t dpos = nfsd->nd_dpos;
1292 struct ucred *cred = &nfsd->nd_cr;
1293 register struct nfs_fattr *fp;
1294 struct vattr va, dirfor, diraft;
1295 register struct vattr *vap = &va;
1296 register struct nfsv2_sattr *sp;
1297 register u_long *tl;
1298 struct nameidata nd;
1299 register caddr_t cp;
1300 register long t1;
1301 caddr_t bpos;
1302 int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1303 int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
1304 char *cp2;
1305 struct mbuf *mb, *mb2, *mreq;
1306 struct vnode *vp, *dirp = (struct vnode *)0;
1307 nfsfh_t nfh;
1308 fhandle_t *fhp;
1309 u_quad_t frev, tempsize;
1310 u_char cverf[NFSX_V3CREATEVERF];
1311
1312#ifndef nolint
1313 rdev = 0;
1314#endif
1315 nd.ni_cnd.cn_nameiop = 0;
1316 fhp = &nfh.fh_generic;
1317 nfsm_srvmtofh(fhp);
1318 nfsm_srvnamesiz(len);
1319 nd.ni_cnd.cn_cred = cred;
1320 nd.ni_cnd.cn_nameiop = CREATE;
1321 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1322 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1323 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1324 if (dirp) {
1325 if (v3)
1326 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1327 procp);
1328 else {
1329 vrele(dirp);
1330 dirp = (struct vnode *)0;
1331 }
1332 }
1333 if (error) {
1334 nfsm_reply(NFSX_WCCDATA(v3));
1335 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1336 if (dirp)
1337 vrele(dirp);
1338 return (0);
1339 }
1340 VATTR_NULL(vap);
1341 if (v3) {
1342 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1343 how = fxdr_unsigned(int, *tl);
1344 switch (how) {
1345 case NFSV3CREATE_GUARDED:
1346 if (nd.ni_vp) {
1347 error = EEXIST;
1348 break;
1349 }
1350 case NFSV3CREATE_UNCHECKED:
1351 nfsm_srvsattr(vap);
1352 break;
1353 case NFSV3CREATE_EXCLUSIVE:
1354 nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
1355 bcopy(cp, cverf, NFSX_V3CREATEVERF);
1356 exclusive_flag = 1;
1357 if (nd.ni_vp == NULL)
1358 vap->va_mode = 0;
1359 break;
1360 };
1361 vap->va_type = VREG;
1362 } else {
1363 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1364 vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
1365 if (vap->va_type == VNON)
1366 vap->va_type = VREG;
1367 vap->va_mode = nfstov_mode(sp->sa_mode);
1368 switch (vap->va_type) {
1369 case VREG:
1370 tsize = fxdr_unsigned(long, sp->sa_size);
1371 if (tsize != -1)
1372 vap->va_size = (u_quad_t)tsize;
1373 break;
1374 case VCHR:
1375 case VBLK:
1376 case VFIFO:
1377 rdev = fxdr_unsigned(long, sp->sa_size);
1378 break;
1379 };
1380 }
1381
1382 /*
1383 * Iff doesn't exist, create it
1384 * otherwise just truncate to 0 length
1385 * should I set the mode too ??
1386 */
1387 if (nd.ni_vp == NULL) {
1388 if (vap->va_type == VREG || vap->va_type == VSOCK) {
1389 vrele(nd.ni_startdir);
1390 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1391 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1392 if (!error) {
1393 nfsrv_object_create(nd.ni_vp);
1394 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1395 if (exclusive_flag) {
1396 exclusive_flag = 0;
1397 VATTR_NULL(vap);
1398 bcopy(cverf, (caddr_t)&vap->va_atime,
1399 NFSX_V3CREATEVERF);
1400 error = VOP_SETATTR(nd.ni_vp, vap, cred,
1401 procp);
1402 }
1403 }
1404 } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
1405 vap->va_type == VFIFO) {
1406 if (vap->va_type == VCHR && rdev == 0xffffffff)
1407 vap->va_type = VFIFO;
1408 if (error = suser(cred, (u_short *)0)) {
1409 vrele(nd.ni_startdir);
1410 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1411 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1412 vput(nd.ni_dvp);
1413 nfsm_reply(0);
1414 return (error);
1415 } else
1416 vap->va_rdev = (dev_t)rdev;
1417 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1418 if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
1419 vrele(nd.ni_startdir);
1420 nfsm_reply(0);
1421 }
1422 nd.ni_cnd.cn_nameiop = LOOKUP;
1423 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1424 nd.ni_cnd.cn_proc = procp;
1425 nd.ni_cnd.cn_cred = cred;
1426 if (error = lookup(&nd)) {
1427 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1428 nfsm_reply(0);
1429 }
1430 nfsrv_object_create(nd.ni_vp);
1431 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1432 if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1433 vrele(nd.ni_dvp);
1434 vput(nd.ni_vp);
1435 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1436 error = EINVAL;
1437 nfsm_reply(0);
1438 }
1439 } else {
1440 vrele(nd.ni_startdir);
1441 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1442 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1443 vput(nd.ni_dvp);
1444 error = ENXIO;
1445 }
1446 vp = nd.ni_vp;
1447 } else {
1448 vrele(nd.ni_startdir);
1449 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1450 vp = nd.ni_vp;
1451 if (nd.ni_dvp == vp)
1452 vrele(nd.ni_dvp);
1453 else
1454 vput(nd.ni_dvp);
1455 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1456 if (vap->va_size != -1) {
1457 error = nfsrv_access(vp, VWRITE, cred,
1458 (nd.ni_cnd.cn_flags & RDONLY), procp);
1459 if (!error) {
1460 nqsrv_getl(vp, ND_WRITE);
1461 tempsize = vap->va_size;
1462 VATTR_NULL(vap);
1463 vap->va_size = tempsize;
1464 error = VOP_SETATTR(vp, vap, cred,
1465 procp);
1466 }
1467 if (error)
1468 vput(vp);
1469 }
1470 }
1471 if (!error) {
1472 bzero((caddr_t)fhp, sizeof(nfh));
1473 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1474 error = VFS_VPTOFH(vp, &fhp->fh_fid);
1475 if (!error)
1476 error = VOP_GETATTR(vp, vap, cred, procp);
1477 vput(vp);
1478 }
1479 if (v3) {
1480 if (exclusive_flag && !error &&
1481 bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF))
1482 error = EEXIST;
1483 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1484 vrele(dirp);
1485 }
1486 nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
1487 if (v3) {
1488 if (!error) {
1489 nfsm_srvpostop_fh(fhp);
1490 nfsm_srvpostop_attr(0, vap);
1491 }
1492 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1493 } else {
1494 nfsm_srvfhtom(fhp, v3);
1495 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1496 nfsm_srvfillattr(vap, fp);
1497 }
1498 return (0);
1499nfsmout:
1500 if (dirp)
1501 vrele(dirp);
1502 if (nd.ni_cnd.cn_nameiop) {
1503 vrele(nd.ni_startdir);
1504 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1505 }
1506 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1507 if (nd.ni_dvp == nd.ni_vp)
1508 vrele(nd.ni_dvp);
1509 else
1510 vput(nd.ni_dvp);
1511 if (nd.ni_vp)
1512 vput(nd.ni_vp);
1513 return (error);
1514}
1515
1516/*
1517 * nfs v3 mknod service
1518 */
1519int
1520nfsrv_mknod(nfsd, slp, procp, mrq)
1521 struct nfsrv_descript *nfsd;
1522 struct nfssvc_sock *slp;
1523 struct proc *procp;
1524 struct mbuf **mrq;
1525{
1526 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1527 struct mbuf *nam = nfsd->nd_nam;
1528 caddr_t dpos = nfsd->nd_dpos;
1529 struct ucred *cred = &nfsd->nd_cr;
1530 struct vattr va, dirfor, diraft;
1531 register struct vattr *vap = &va;
1532 register u_long *tl;
1533 struct nameidata nd;
1534 register long t1;
1535 caddr_t bpos;
1536 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
1537 u_long major, minor;
1538 enum vtype vtyp;
1539 char *cp2;
1540 struct mbuf *mb, *mb2, *mreq;
1541 struct vnode *vp, *dirp = (struct vnode *)0;
1542 nfsfh_t nfh;
1543 fhandle_t *fhp;
1544 u_quad_t frev;
1545
1546 nd.ni_cnd.cn_nameiop = 0;
1547 fhp = &nfh.fh_generic;
1548 nfsm_srvmtofh(fhp);
1549 nfsm_srvnamesiz(len);
1550 nd.ni_cnd.cn_cred = cred;
1551 nd.ni_cnd.cn_nameiop = CREATE;
1552 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1553 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1554 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1555 if (dirp)
1556 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
1557 if (error) {
1558 nfsm_reply(NFSX_WCCDATA(1));
1559 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1560 if (dirp)
1561 vrele(dirp);
1562 return (0);
1563 }
1564 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1565 vtyp = nfsv3tov_type(*tl);
1566 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1567 vrele(nd.ni_startdir);
1568 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1569 error = NFSERR_BADTYPE;
1570 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1571 vput(nd.ni_dvp);
1572 goto out;
1573 }
1574 VATTR_NULL(vap);
1575 nfsm_srvsattr(vap);
1576 if (vtyp == VCHR || vtyp == VBLK) {
1577 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1578 major = fxdr_unsigned(u_long, *tl++);
1579 minor = fxdr_unsigned(u_long, *tl);
1580 vap->va_rdev = makedev(major, minor);
1581 }
1582
1583 /*
1584 * Iff doesn't exist, create it.
1585 */
1586 if (nd.ni_vp) {
1587 vrele(nd.ni_startdir);
1588 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1589 error = EEXIST;
1590 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1591 vput(nd.ni_dvp);
1592 goto out;
1593 }
1594 vap->va_type = vtyp;
1595 if (vtyp == VSOCK) {
1596 vrele(nd.ni_startdir);
1597 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1598 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1599 if (!error)
1600 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1601 } else {
1602 if (error = suser(cred, (u_short *)0)) {
1603 vrele(nd.ni_startdir);
1604 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1605 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1606 vput(nd.ni_dvp);
1607 goto out;
1608 }
1609 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1610 if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
1611 vrele(nd.ni_startdir);
1612 goto out;
1613 }
1614 nd.ni_cnd.cn_nameiop = LOOKUP;
1615 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1616 nd.ni_cnd.cn_proc = procp;
1617 nd.ni_cnd.cn_cred = procp->p_ucred;
1618 error = lookup(&nd);
1619 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1620 if (error)
1621 goto out;
1622 if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1623 vrele(nd.ni_dvp);
1624 vput(nd.ni_vp);
1625 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1626 error = EINVAL;
1627 }
1628 }
1629out:
1630 vp = nd.ni_vp;
1631 if (!error) {
1632 bzero((caddr_t)fhp, sizeof(nfh));
1633 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1634 error = VFS_VPTOFH(vp, &fhp->fh_fid);
1635 if (!error)
1636 error = VOP_GETATTR(vp, vap, cred, procp);
1637 vput(vp);
1638 }
1639 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1640 vrele(dirp);
1641 nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
1642 if (!error) {
1643 nfsm_srvpostop_fh(fhp);
1644 nfsm_srvpostop_attr(0, vap);
1645 }
1646 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1647 return (0);
1648nfsmout:
1649 if (dirp)
1650 vrele(dirp);
1651 if (nd.ni_cnd.cn_nameiop) {
1652 vrele(nd.ni_startdir);
1653 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1654 }
1655 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1656 if (nd.ni_dvp == nd.ni_vp)
1657 vrele(nd.ni_dvp);
1658 else
1659 vput(nd.ni_dvp);
1660 if (nd.ni_vp)
1661 vput(nd.ni_vp);
1662 return (error);
1663}
1664
1665/*
1666 * nfs remove service
1667 */
1668int
1669nfsrv_remove(nfsd, slp, procp, mrq)
1670 struct nfsrv_descript *nfsd;
1671 struct nfssvc_sock *slp;
1672 struct proc *procp;
1673 struct mbuf **mrq;
1674{
1675 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1676 struct mbuf *nam = nfsd->nd_nam;
1677 caddr_t dpos = nfsd->nd_dpos;
1678 struct ucred *cred = &nfsd->nd_cr;
1679 struct nameidata nd;
1680 register u_long *tl;
1681 register long t1;
1682 caddr_t bpos;
1683 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
1684 int v3 = (nfsd->nd_flag & ND_NFSV3);
1685 char *cp2;
1686 struct mbuf *mb, *mreq;
1687 struct vnode *vp, *dirp;
1688 struct vattr dirfor, diraft;
1689 nfsfh_t nfh;
1690 fhandle_t *fhp;
1691 u_quad_t frev;
1692
1693#ifndef nolint
1694 vp = (struct vnode *)0;
1695#endif
1696 fhp = &nfh.fh_generic;
1697 nfsm_srvmtofh(fhp);
1698 nfsm_srvnamesiz(len);
1699 nd.ni_cnd.cn_cred = cred;
1700 nd.ni_cnd.cn_nameiop = DELETE;
1701 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1702 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1703 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1704 if (dirp) {
1705 if (v3)
1706 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1707 procp);
1708 else
1709 vrele(dirp);
1710 }
1711 if (!error) {
1712 vp = nd.ni_vp;
1713 if (vp->v_type == VDIR) {
1714 error = EPERM; /* POSIX */
1715 goto out;
1716 }
1717 /*
1718 * The root of a mounted filesystem cannot be deleted.
1719 */
1720 if (vp->v_flag & VROOT) {
1721 error = EBUSY;
1722 goto out;
1723 }
1724out:
1725 if (!error) {
1726 vnode_pager_uncache(vp, procp);
1727 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1728 nqsrv_getl(vp, ND_WRITE);
1729
1730 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1731
1732 } else {
1733 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1734 if (nd.ni_dvp == vp)
1735 vrele(nd.ni_dvp);
1736 else
1737 vput(nd.ni_dvp);
1738 vput(vp);
1739 }
1740 }
1741 if (dirp && v3) {
1742 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1743 vrele(dirp);
1744 }
1745 nfsm_reply(NFSX_WCCDATA(v3));
1746 if (v3) {
1747 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1748 return (0);
1749 }
1750 nfsm_srvdone;
1751}
1752
1753/*
1754 * nfs rename service
1755 */
1756int
1757nfsrv_rename(nfsd, slp, procp, mrq)
1758 struct nfsrv_descript *nfsd;
1759 struct nfssvc_sock *slp;
1760 struct proc *procp;
1761 struct mbuf **mrq;
1762{
1763 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1764 struct mbuf *nam = nfsd->nd_nam;
1765 caddr_t dpos = nfsd->nd_dpos;
1766 struct ucred *cred = &nfsd->nd_cr;
1767 register u_long *tl;
1768 register long t1;
1769 caddr_t bpos;
1770 int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
1771 int tdirfor_ret = 1, tdiraft_ret = 1;
1772 int v3 = (nfsd->nd_flag & ND_NFSV3);
1773 char *cp2;
1774 struct mbuf *mb, *mreq;
1775 struct nameidata fromnd, tond;
1776 struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0;
1777 struct vnode *tdirp = (struct vnode *)0;
1778 struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
1779 nfsfh_t fnfh, tnfh;
1780 fhandle_t *ffhp, *tfhp;
1781 u_quad_t frev;
1782 uid_t saved_uid;
1783
1784#ifndef nolint
1785 fvp = (struct vnode *)0;
1786#endif
1787 ffhp = &fnfh.fh_generic;
1788 tfhp = &tnfh.fh_generic;
1789 fromnd.ni_cnd.cn_nameiop = 0;
1790 tond.ni_cnd.cn_nameiop = 0;
1791 nfsm_srvmtofh(ffhp);
1792 nfsm_srvnamesiz(len);
1793 /*
1794 * Remember our original uid so that we can reset cr_uid before
1795 * the second nfs_namei() call, in case it is remapped.
1796 */
1797 saved_uid = cred->cr_uid;
1798 fromnd.ni_cnd.cn_cred = cred;
1799 fromnd.ni_cnd.cn_nameiop = DELETE;
1800 fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
1801 error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
1802 &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1803 if (fdirp) {
1804 if (v3)
1805 fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred,
1806 procp);
1807 else {
1808 vrele(fdirp);
1809 fdirp = (struct vnode *)0;
1810 }
1811 }
1812 if (error) {
1813 nfsm_reply(2 * NFSX_WCCDATA(v3));
1814 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1815 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1816 if (fdirp)
1817 vrele(fdirp);
1818 return (0);
1819 }
1820 fvp = fromnd.ni_vp;
1821 nfsm_srvmtofh(tfhp);
1822 nfsm_strsiz(len2, NFS_MAXNAMLEN);
1823 cred->cr_uid = saved_uid;
1824 tond.ni_cnd.cn_cred = cred;
1825 tond.ni_cnd.cn_nameiop = RENAME;
1826 tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
1827 error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
1828 &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1829 if (tdirp) {
1830 if (v3)
1831 tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred,
1832 procp);
1833 else {
1834 vrele(tdirp);
1835 tdirp = (struct vnode *)0;
1836 }
1837 }
1838 if (error) {
1839 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1840 vrele(fromnd.ni_dvp);
1841 vrele(fvp);
1842 goto out1;
1843 }
1844 tdvp = tond.ni_dvp;
1845 tvp = tond.ni_vp;
1846 if (tvp != NULL) {
1847 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1848 if (v3)
1849 error = EEXIST;
1850 else
1851 error = EISDIR;
1852 goto out;
1853 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1854 if (v3)
1855 error = EEXIST;
1856 else
1857 error = ENOTDIR;
1858 goto out;
1859 }
1860 if (tvp->v_type == VDIR && tvp->v_mountedhere) {
1861 if (v3)
1862 error = EXDEV;
1863 else
1864 error = ENOTEMPTY;
1865 goto out;
1866 }
1867 }
1868 if (fvp->v_type == VDIR && fvp->v_mountedhere) {
1869 if (v3)
1870 error = EXDEV;
1871 else
1872 error = ENOTEMPTY;
1873 goto out;
1874 }
1875 if (fvp->v_mount != tdvp->v_mount) {
1876 if (v3)
1877 error = EXDEV;
1878 else
1879 error = ENOTEMPTY;
1880 goto out;
1881 }
1882 if (fvp == tdvp)
1883 if (v3)
1884 error = EINVAL;
1885 else
1886 error = ENOTEMPTY;
1887 /*
1888 * If source is the same as the destination (that is the
1889 * same vnode with the same name in the same directory),
1890 * then there is nothing to do.
1891 */
1892 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
1893 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1894 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
1895 fromnd.ni_cnd.cn_namelen))
1896 error = -1;
1897out:
1898 if (!error) {
1899 nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
1900 nqsrv_getl(tdvp, ND_WRITE);
1901 if (tvp) {
1902 nqsrv_getl(tvp, ND_WRITE);
1903 (void) vnode_pager_uncache(tvp, procp);
1904 }
1905 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
1906 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
1907 } else {
1908 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
1909 if (tdvp == tvp)
1910 vrele(tdvp);
1911 else
1912 vput(tdvp);
1913 if (tvp)
1914 vput(tvp);
1915 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1916 vrele(fromnd.ni_dvp);
1917 vrele(fvp);
1918 if (error == -1)
1919 error = 0;
1920 }
1921 vrele(tond.ni_startdir);
1922 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1923out1:
1924 if (fdirp) {
1925 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp);
1926 vrele(fdirp);
1927 }
1928 if (tdirp) {
1929 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp);
1930 vrele(tdirp);
1931 }
1932 vrele(fromnd.ni_startdir);
1933 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1934 nfsm_reply(2 * NFSX_WCCDATA(v3));
1935 if (v3) {
1936 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1937 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1938 }
1939 return (0);
1940
1941nfsmout:
1942 if (fdirp)
1943 vrele(fdirp);
1944 if (tdirp)
1945 vrele(tdirp);
1946 if (tond.ni_cnd.cn_nameiop) {
1947 vrele(tond.ni_startdir);
1948 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1949 }
1950 if (fromnd.ni_cnd.cn_nameiop) {
1951 vrele(fromnd.ni_startdir);
1952 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1953 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1954 vrele(fromnd.ni_dvp);
1955 vrele(fvp);
1956 }
1957 return (error);
1958}
1959
1960/*
1961 * nfs link service
1962 */
1963int
1964nfsrv_link(nfsd, slp, procp, mrq)
1965 struct nfsrv_descript *nfsd;
1966 struct nfssvc_sock *slp;
1967 struct proc *procp;
1968 struct mbuf **mrq;
1969{
1970 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1971 struct mbuf *nam = nfsd->nd_nam;
1972 caddr_t dpos = nfsd->nd_dpos;
1973 struct ucred *cred = &nfsd->nd_cr;
1974 struct nameidata nd;
1975 register u_long *tl;
1976 register long t1;
1977 caddr_t bpos;
1978 int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1;
1979 int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
1980 char *cp2;
1981 struct mbuf *mb, *mreq;
1982 struct vnode *vp, *xp, *dirp = (struct vnode *)0;
1983 struct vattr dirfor, diraft, at;
1984 nfsfh_t nfh, dnfh;
1985 fhandle_t *fhp, *dfhp;
1986 u_quad_t frev;
1987
1988 fhp = &nfh.fh_generic;
1989 dfhp = &dnfh.fh_generic;
1990 nfsm_srvmtofh(fhp);
1991 nfsm_srvmtofh(dfhp);
1992 nfsm_srvnamesiz(len);
1993 if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
1994 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
1995 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
1996 nfsm_srvpostop_attr(getret, &at);
1997 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1998 return (0);
1999 }
2000 if (vp->v_type == VDIR) {
2001 error = EPERM; /* POSIX */
2002 goto out1;
2003 }
2004 nd.ni_cnd.cn_cred = cred;
2005 nd.ni_cnd.cn_nameiop = CREATE;
2006 nd.ni_cnd.cn_flags = LOCKPARENT;
2007 error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
2008 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2009 if (dirp) {
2010 if (v3)
2011 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2012 procp);
2013 else {
2014 vrele(dirp);
2015 dirp = (struct vnode *)0;
2016 }
2017 }
2018 if (error)
2019 goto out1;
2020 xp = nd.ni_vp;
2021 if (xp != NULL) {
2022 error = EEXIST;
2023 goto out;
2024 }
2025 xp = nd.ni_dvp;
2026 if (vp->v_mount != xp->v_mount)
2027 error = EXDEV;
2028out:
2029 if (!error) {
2030 nqsrv_getl(vp, ND_WRITE);
2031 nqsrv_getl(xp, ND_WRITE);
2032#if defined(__NetBSD__) || defined(__FreeBSD__)
2033 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
2034#else /* Lite2 version */
2035 error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
2036#endif
2037 } else {
2038 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2039 if (nd.ni_dvp == nd.ni_vp)
2040 vrele(nd.ni_dvp);
2041 else
2042 vput(nd.ni_dvp);
2043 if (nd.ni_vp)
2044 vrele(nd.ni_vp);
2045 }
2046out1:
2047 if (v3)
2048 getret = VOP_GETATTR(vp, &at, cred, procp);
2049 if (dirp) {
2050 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2051 vrele(dirp);
2052 }
2053 vrele(vp);
2054 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2055 if (v3) {
2056 nfsm_srvpostop_attr(getret, &at);
2057 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2058 return (0);
2059 }
2060 nfsm_srvdone;
2061}
2062
2063/*
2064 * nfs symbolic link service
2065 */
2066int
2067nfsrv_symlink(nfsd, slp, procp, mrq)
2068 struct nfsrv_descript *nfsd;
2069 struct nfssvc_sock *slp;
2070 struct proc *procp;
2071 struct mbuf **mrq;
2072{
2073 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2074 struct mbuf *nam = nfsd->nd_nam;
2075 caddr_t dpos = nfsd->nd_dpos;
2076 struct ucred *cred = &nfsd->nd_cr;
2077 struct vattr va, dirfor, diraft;
2078 struct nameidata nd;
2079 register struct vattr *vap = &va;
2080 register u_long *tl;
2081 register long t1;
2082 struct nfsv2_sattr *sp;
2083 char *bpos, *pathcp = (char *)0, *cp2;
2084 struct uio io;
2085 struct iovec iv;
2086 int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1;
2087 int v3 = (nfsd->nd_flag & ND_NFSV3);
2088 struct mbuf *mb, *mreq, *mb2;
2089 struct vnode *dirp = (struct vnode *)0;
2090 nfsfh_t nfh;
2091 fhandle_t *fhp;
2092 u_quad_t frev;
2093
2094 nd.ni_cnd.cn_nameiop = 0;
2095 fhp = &nfh.fh_generic;
2096 nfsm_srvmtofh(fhp);
2097 nfsm_srvnamesiz(len);
2098 nd.ni_cnd.cn_cred = cred;
2099 nd.ni_cnd.cn_nameiop = CREATE;
2100 nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART;
2101 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2102 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2103 if (dirp) {
2104 if (v3)
2105 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2106 procp);
2107 else {
2108 vrele(dirp);
2109 dirp = (struct vnode *)0;
2110 }
2111 }
2112 if (error)
2113 goto out;
2114 VATTR_NULL(vap);
2115 if (v3)
2116 nfsm_srvsattr(vap);
2117 nfsm_strsiz(len2, NFS_MAXPATHLEN);
2118 MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
2119 iv.iov_base = pathcp;
2120 iv.iov_len = len2;
2121 io.uio_resid = len2;
2122 io.uio_offset = 0;
2123 io.uio_iov = &iv;
2124 io.uio_iovcnt = 1;
2125 io.uio_segflg = UIO_SYSSPACE;
2126 io.uio_rw = UIO_READ;
2127 io.uio_procp = (struct proc *)0;
2128 nfsm_mtouio(&io, len2);
2129 if (!v3) {
2130 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2131 vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
2132 }
2133 *(pathcp + len2) = '\0';
2134 if (nd.ni_vp) {
2135 vrele(nd.ni_startdir);
2136 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2137 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2138 if (nd.ni_dvp == nd.ni_vp)
2139 vrele(nd.ni_dvp);
2140 else
2141 vput(nd.ni_dvp);
2142 vrele(nd.ni_vp);
2143 error = EEXIST;
2144 goto out;
2145 }
2146 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2147 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
2148 if (error)
2149 vrele(nd.ni_startdir);
2150 else {
2151 if (v3) {
2152 nd.ni_cnd.cn_nameiop = LOOKUP;
2153 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW);
2154 nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
2155 nd.ni_cnd.cn_proc = procp;
2156 nd.ni_cnd.cn_cred = cred;
2157 error = lookup(&nd);
2158 if (!error) {
2159 bzero((caddr_t)fhp, sizeof(nfh));
2160 fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
2161 error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
2162 if (!error)
2163 error = VOP_GETATTR(nd.ni_vp, vap, cred,
2164 procp);
2165 vput(nd.ni_vp);
2166 }
2167 } else
2168 vrele(nd.ni_startdir);
2169 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2170 }
2171out:
2172 if (pathcp)
2173 FREE(pathcp, M_TEMP);
2174 if (dirp) {
2175 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2176 vrele(dirp);
2177 }
2178 nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2179 if (v3) {
2180 if (!error) {
2181 nfsm_srvpostop_fh(fhp);
2182 nfsm_srvpostop_attr(0, vap);
2183 }
2184 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2185 }
2186 return (0);
2187nfsmout:
2188 if (nd.ni_cnd.cn_nameiop) {
2189 vrele(nd.ni_startdir);
2190 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2191 }
2192 if (dirp)
2193 vrele(dirp);
2194 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2195 if (nd.ni_dvp == nd.ni_vp)
2196 vrele(nd.ni_dvp);
2197 else
2198 vput(nd.ni_dvp);
2199 if (nd.ni_vp)
2200 vrele(nd.ni_vp);
2201 if (pathcp)
2202 FREE(pathcp, M_TEMP);
2203 return (error);
2204}
2205
2206/*
2207 * nfs mkdir service
2208 */
2209int
2210nfsrv_mkdir(nfsd, slp, procp, mrq)
2211 struct nfsrv_descript *nfsd;
2212 struct nfssvc_sock *slp;
2213 struct proc *procp;
2214 struct mbuf **mrq;
2215{
2216 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2217 struct mbuf *nam = nfsd->nd_nam;
2218 caddr_t dpos = nfsd->nd_dpos;
2219 struct ucred *cred = &nfsd->nd_cr;
2220 struct vattr va, dirfor, diraft;
2221 register struct vattr *vap = &va;
2222 register struct nfs_fattr *fp;
2223 struct nameidata nd;
2224 register caddr_t cp;
2225 register u_long *tl;
2226 register long t1;
2227 caddr_t bpos;
2228 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2229 int v3 = (nfsd->nd_flag & ND_NFSV3);
2230 char *cp2;
2231 struct mbuf *mb, *mb2, *mreq;
2232 struct vnode *vp, *dirp = (struct vnode *)0;
2233 nfsfh_t nfh;
2234 fhandle_t *fhp;
2235 u_quad_t frev;
2236
2237 fhp = &nfh.fh_generic;
2238 nfsm_srvmtofh(fhp);
2239 nfsm_srvnamesiz(len);
2240 nd.ni_cnd.cn_cred = cred;
2241 nd.ni_cnd.cn_nameiop = CREATE;
2242 nd.ni_cnd.cn_flags = LOCKPARENT;
2243 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2244 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2245 if (dirp) {
2246 if (v3)
2247 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2248 procp);
2249 else {
2250 vrele(dirp);
2251 dirp = (struct vnode *)0;
2252 }
2253 }
2254 if (error) {
2255 nfsm_reply(NFSX_WCCDATA(v3));
2256 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2257 if (dirp)
2258 vrele(dirp);
2259 return (0);
2260 }
2261 VATTR_NULL(vap);
2262 if (v3) {
2263 nfsm_srvsattr(vap);
2264 } else {
2265 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2266 vap->va_mode = nfstov_mode(*tl++);
2267 }
2268 vap->va_type = VDIR;
2269 vp = nd.ni_vp;
2270 if (vp != NULL) {
2271 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2272 if (nd.ni_dvp == vp)
2273 vrele(nd.ni_dvp);
2274 else
2275 vput(nd.ni_dvp);
2276 vrele(vp);
2277 error = EEXIST;
2278 goto out;
2279 }
2280 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2281 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
2282 if (!error) {
2283 vp = nd.ni_vp;
2284 bzero((caddr_t)fhp, sizeof(nfh));
2285 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
2286 error = VFS_VPTOFH(vp, &fhp->fh_fid);
2287 if (!error)
2288 error = VOP_GETATTR(vp, vap, cred, procp);
2289 vput(vp);
2290 }
2291out:
2292 if (dirp) {
2293 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2294 vrele(dirp);
2295 }
2296 nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2297 if (v3) {
2298 if (!error) {
2299 nfsm_srvpostop_fh(fhp);
2300 nfsm_srvpostop_attr(0, vap);
2301 }
2302 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2303 } else {
2304 nfsm_srvfhtom(fhp, v3);
2305 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
2306 nfsm_srvfillattr(vap, fp);
2307 }
2308 return (0);
2309nfsmout:
2310 if (dirp)
2311 vrele(dirp);
2312 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2313 if (nd.ni_dvp == nd.ni_vp)
2314 vrele(nd.ni_dvp);
2315 else
2316 vput(nd.ni_dvp);
2317 if (nd.ni_vp)
2318 vrele(nd.ni_vp);
2319 return (error);
2320}
2321
2322/*
2323 * nfs rmdir service
2324 */
2325int
2326nfsrv_rmdir(nfsd, slp, procp, mrq)
2327 struct nfsrv_descript *nfsd;
2328 struct nfssvc_sock *slp;
2329 struct proc *procp;
2330 struct mbuf **mrq;
2331{
2332 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2333 struct mbuf *nam = nfsd->nd_nam;
2334 caddr_t dpos = nfsd->nd_dpos;
2335 struct ucred *cred = &nfsd->nd_cr;
2336 register u_long *tl;
2337 register long t1;
2338 caddr_t bpos;
2339 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2340 int v3 = (nfsd->nd_flag & ND_NFSV3);
2341 char *cp2;
2342 struct mbuf *mb, *mreq;
2343 struct vnode *vp, *dirp = (struct vnode *)0;
2344 struct vattr dirfor, diraft;
2345 nfsfh_t nfh;
2346 fhandle_t *fhp;
2347 struct nameidata nd;
2348 u_quad_t frev;
2349
2350 fhp = &nfh.fh_generic;
2351 nfsm_srvmtofh(fhp);
2352 nfsm_srvnamesiz(len);
2353 nd.ni_cnd.cn_cred = cred;
2354 nd.ni_cnd.cn_nameiop = DELETE;
2355 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2356 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2357 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2358 if (dirp) {
2359 if (v3)
2360 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2361 procp);
2362 else {
2363 vrele(dirp);
2364 dirp = (struct vnode *)0;
2365 }
2366 }
2367 if (error) {
2368 nfsm_reply(NFSX_WCCDATA(v3));
2369 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2370 if (dirp)
2371 vrele(dirp);
2372 return (0);
2373 }
2374 vp = nd.ni_vp;
2375 if (vp->v_type != VDIR) {
2376 error = ENOTDIR;
2377 goto out;
2378 }
2379 /*
2380 * No rmdir "." please.
2381 */
2382 if (nd.ni_dvp == vp) {
2383 error = EINVAL;
2384 goto out;
2385 }
2386 /*
2387 * The root of a mounted filesystem cannot be deleted.
2388 */
2389 if (vp->v_flag & VROOT)
2390 error = EBUSY;
2391out:
2392 if (!error) {
2393 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2394 nqsrv_getl(vp, ND_WRITE);
2395 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2396 } else {
2397 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2398 if (nd.ni_dvp == nd.ni_vp)
2399 vrele(nd.ni_dvp);
2400 else
2401 vput(nd.ni_dvp);
2402 vput(vp);
2403 }
2404 if (dirp) {
2405 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2406 vrele(dirp);
2407 }
2408 nfsm_reply(NFSX_WCCDATA(v3));
2409 if (v3) {
2410 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2411 return (0);
2412 }
2413 nfsm_srvdone;
2414}
2415
2416/*
2417 * nfs readdir service
2418 * - mallocs what it thinks is enough to read
2419 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2420 * - calls VOP_READDIR()
2421 * - loops around building the reply
2422 * if the output generated exceeds count break out of loop
2423 * The nfsm_clget macro is used here so that the reply will be packed
2424 * tightly in mbuf clusters.
2425 * - it only knows that it has encountered eof when the VOP_READDIR()
2426 * reads nothing
2427 * - as such one readdir rpc will return eof false although you are there
2428 * and then the next will return eof
2429 * - it trims out records with d_fileno == 0
2430 * this doesn't matter for Unix clients, but they might confuse clients
2431 * for other os'.
2432 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2433 * than requested, but this may not apply to all filesystems. For
2434 * example, client NFS does not { although it is never remote mounted
2435 * anyhow }
2436 * The alternate call nfsrv_readdirplus() does lookups as well.
2437 * PS: The NFS protocol spec. does not clarify what the "count" byte
2438 * argument is a count of.. just name strings and file id's or the
2439 * entire reply rpc or ...
2440 * I tried just file name and id sizes and it confused the Sun client,
2441 * so I am using the full rpc size now. The "paranoia.." comment refers
2442 * to including the status longwords that are not a part of the dir.
2443 * "entry" structures, but are in the rpc.
2444 */
2445struct flrep {
2446 nfsuint64 fl_off;
2447 u_long fl_postopok;
2448 u_long fl_fattr[NFSX_V3FATTR / sizeof (u_long)];
2449 u_long fl_fhok;
2450 u_long fl_fhsize;
2451 u_long fl_nfh[NFSX_V3FH / sizeof (u_long)];
2452};
2453
2454int
2455nfsrv_readdir(nfsd, slp, procp, mrq)
2456 struct nfsrv_descript *nfsd;
2457 struct nfssvc_sock *slp;
2458 struct proc *procp;
2459 struct mbuf **mrq;
2460{
2461 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2462 struct mbuf *nam = nfsd->nd_nam;
2463 caddr_t dpos = nfsd->nd_dpos;
2464 struct ucred *cred = &nfsd->nd_cr;
2465 register char *bp, *be;
2466 register struct mbuf *mp;
2467 register struct dirent *dp;
2468 register caddr_t cp;
2469 register u_long *tl;
2470 register long t1;
2471 caddr_t bpos;
2472 struct mbuf *mb, *mb2, *mreq, *mp2;
2473 char *cpos, *cend, *cp2, *rbuf;
2474 struct vnode *vp;
2475 struct vattr at;
2476 nfsfh_t nfh;
2477 fhandle_t *fhp;
2478 struct uio io;
2479 struct iovec iv;
2480 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2481 int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies;
2482 int v3 = (nfsd->nd_flag & ND_NFSV3);
2483 u_quad_t frev, off, toff, verf;
2484 u_long *cookies = NULL, *cookiep;
2485
2486 fhp = &nfh.fh_generic;
2487 nfsm_srvmtofh(fhp);
2488 if (v3) {
2489 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
2490 fxdr_hyper(tl, &toff);
2491 tl += 2;
2492 fxdr_hyper(tl, &verf);
2493 tl += 2;
2494 } else {
2495 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2496 toff = fxdr_unsigned(u_quad_t, *tl++);
2497 }
2498 off = toff;
2499 cnt = fxdr_unsigned(int, *tl);
2500 siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2501 xfer = NFS_SRVMAXDATA(nfsd);
2502 if (siz > xfer)
2503 siz = xfer;
2504 fullsiz = siz;
2505 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2506 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
2507 nfsm_reply(NFSX_UNSIGNED);
2508 nfsm_srvpostop_attr(getret, &at);
2509 return (0);
2510 }
2511 nqsrv_getl(vp, ND_READ);
2512 if (v3) {
2513 error = getret = VOP_GETATTR(vp, &at, cred, procp);
2514 if (!error && toff && verf != at.va_filerev)
2515 error = NFSERR_BAD_COOKIE;
2516 }
2517 if (!error)
2518 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
2519 if (error) {
2520 vput(vp);
2521 nfsm_reply(NFSX_POSTOPATTR(v3));
2522 nfsm_srvpostop_attr(getret, &at);
2523 return (0);
2524 }
2525 VOP_UNLOCK(vp, 0, procp);
2526 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
2527#ifdef __NetBSD__
2528 ncookies = siz / (5 * NFSX_UNSIGNED); /*7 for V3, but it's an est. so*/
2529 MALLOC(cookies, u_long *, ncookies * sizeof (u_long *), M_TEMP,
2530 M_WAITOK);
2531#endif
2532again:
2533 iv.iov_base = rbuf;
2534 iv.iov_len = fullsiz;
2535 io.uio_iov = &iv;
2536 io.uio_iovcnt = 1;
2537 io.uio_offset = (off_t)off;
2538 io.uio_resid = fullsiz;
2539 io.uio_segflg = UIO_SYSSPACE;
2540 io.uio_rw = UIO_READ;
2541 io.uio_procp = (struct proc *)0;
2542 eofflag = 0;
2543 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp);
2544 if (cookies) {
2545 free((caddr_t)cookies, M_TEMP);
2546 cookies = NULL;
2547 }
2548 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
2549 off = (off_t)io.uio_offset;
2550 if (!cookies && !error)
2551 error = NFSERR_PERM;
2552 if (v3) {
2553 getret = VOP_GETATTR(vp, &at, cred, procp);
2554 if (!error)
2555 error = getret;
2556 }
2557 VOP_UNLOCK(vp, 0, procp);
2558 if (error) {
2559 vrele(vp);
2560 free((caddr_t)rbuf, M_TEMP);
2561 if (cookies)
2562 free((caddr_t)cookies, M_TEMP);
2563 nfsm_reply(NFSX_POSTOPATTR(v3));
2564 nfsm_srvpostop_attr(getret, &at);
2565 return (0);
2566 }
2567 if (io.uio_resid) {
2568 siz -= io.uio_resid;
2569
2570 /*
2571 * If nothing read, return eof
2572 * rpc reply
2573 */
2574 if (siz == 0) {
2575 vrele(vp);
2576 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
2577 2 * NFSX_UNSIGNED);
2578 if (v3) {
2579 nfsm_srvpostop_attr(getret, &at);
2580 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
2581 txdr_hyper(&at.va_filerev, tl);
2582 tl += 2;
2583 } else
2584 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2585 *tl++ = nfs_false;
2586 *tl = nfs_true;
2587 FREE((caddr_t)rbuf, M_TEMP);
2588 FREE((caddr_t)cookies, M_TEMP);
2589 return (0);
2590 }
2591 }
2592
2593 /*
2594 * Check for degenerate cases of nothing useful read.
2595 * If so go try again
2596 */
2597 cpos = rbuf;
2598 cend = rbuf + siz;
2599 dp = (struct dirent *)cpos;
2600 cookiep = cookies;
2601#ifdef __FreeBSD__
2602 /*
2603 * For some reason FreeBSD's ufs_readdir() chooses to back the
2604 * directory offset up to a block boundary, so it is necessary to
2605 * skip over the records that preceed the requested offset. This
2606 * requires the assumption that file offset cookies monotonically
2607 * increase.
2608 */
2609 while (cpos < cend && ncookies > 0 &&
2610 (dp->d_fileno == 0 || ((u_quad_t)(*cookiep)) <= toff)) {
2611#else
2612 while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
2613#endif
2614 cpos += dp->d_reclen;
2615 dp = (struct dirent *)cpos;
2616 cookiep++;
2617 ncookies--;
2618 }
2619 if (cpos >= cend || ncookies == 0) {
2620 toff = off;
2621 siz = fullsiz;
2622 goto again;
2623 }
2624
2625 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
2626 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
2627 if (v3) {
2628 nfsm_srvpostop_attr(getret, &at);
2629 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2630 txdr_hyper(&at.va_filerev, tl);
2631 }
2632 mp = mp2 = mb;
2633 bp = bpos;
2634 be = bp + M_TRAILINGSPACE(mp);
2635
2636 /* Loop through the records and build reply */
2637 while (cpos < cend && ncookies > 0) {
2638 if (dp->d_fileno != 0) {
2639 nlen = dp->d_namlen;
2640 rem = nfsm_rndup(nlen)-nlen;
2641 len += (4 * NFSX_UNSIGNED + nlen + rem);
2642 if (v3)
2643 len += 2 * NFSX_UNSIGNED;
2644 if (len > cnt) {
2645 eofflag = 0;
2646 break;
2647 }
2648 /*
2649 * Build the directory record xdr from
2650 * the dirent entry.
2651 */
2652 nfsm_clget;
2653 *tl = nfs_true;
2654 bp += NFSX_UNSIGNED;
2655 if (v3) {
2656 nfsm_clget;
2657 *tl = 0;
2658 bp += NFSX_UNSIGNED;
2659 }
2660 nfsm_clget;
2661 *tl = txdr_unsigned(dp->d_fileno);
2662 bp += NFSX_UNSIGNED;
2663 nfsm_clget;
2664 *tl = txdr_unsigned(nlen);
2665 bp += NFSX_UNSIGNED;
2666
2667 /* And loop around copying the name */
2668 xfer = nlen;
2669 cp = dp->d_name;
2670 while (xfer > 0) {
2671 nfsm_clget;
2672 if ((bp+xfer) > be)
2673 tsiz = be-bp;
2674 else
2675 tsiz = xfer;
2676 bcopy(cp, bp, tsiz);
2677 bp += tsiz;
2678 xfer -= tsiz;
2679 if (xfer > 0)
2680 cp += tsiz;
2681 }
2682 /* And null pad to a long boundary */
2683 for (i = 0; i < rem; i++)
2684 *bp++ = '\0';
2685 nfsm_clget;
2686
2687 /* Finish off the record */
2688 if (v3) {
2689 *tl = 0;
2690 bp += NFSX_UNSIGNED;
2691 nfsm_clget;
2692 }
2693 *tl = txdr_unsigned(*cookiep);
2694 bp += NFSX_UNSIGNED;
2695 }
2696 cpos += dp->d_reclen;
2697 dp = (struct dirent *)cpos;
2698 cookiep++;
2699 ncookies--;
2700 }
2701 vrele(vp);
2702 nfsm_clget;
2703 *tl = nfs_false;
2704 bp += NFSX_UNSIGNED;
2705 nfsm_clget;
2706 if (eofflag)
2707 *tl = nfs_true;
2708 else
2709 *tl = nfs_false;
2710 bp += NFSX_UNSIGNED;
2711 if (mp != mb) {
2712 if (bp < be)
2713 mp->m_len = bp - mtod(mp, caddr_t);
2714 } else
2715 mp->m_len += bp - bpos;
2716 FREE((caddr_t)rbuf, M_TEMP);
2717 FREE((caddr_t)cookies, M_TEMP);
2718 nfsm_srvdone;
2719}
2720
2721int
2722nfsrv_readdirplus(nfsd, slp, procp, mrq)
2723 struct nfsrv_descript *nfsd;
2724 struct nfssvc_sock *slp;
2725 struct proc *procp;
2726 struct mbuf **mrq;
2727{
2728 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2729 struct mbuf *nam = nfsd->nd_nam;
2730 caddr_t dpos = nfsd->nd_dpos;
2731 struct ucred *cred = &nfsd->nd_cr;
2732 register char *bp, *be;
2733 register struct mbuf *mp;
2734 register struct dirent *dp;
2735 register caddr_t cp;
2736 register u_long *tl;
2737 register long t1;
2738 caddr_t bpos;
2739 struct mbuf *mb, *mb2, *mreq, *mp2;
2740 char *cpos, *cend, *cp2, *rbuf;
2741 struct vnode *vp, *nvp;
2742 struct flrep fl;
2743 nfsfh_t nfh;
2744 fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
2745 struct uio io;
2746 struct iovec iv;
2747 struct vattr va, at, *vap = &va;
2748 struct nfs_fattr *fp;
2749 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2750 int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies;
2751 u_quad_t frev, off, toff, verf;
2752 u_long *cookies = NULL, *cookiep;
2753
2754 fhp = &nfh.fh_generic;
2755 nfsm_srvmtofh(fhp);
2756 nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED);
2757 fxdr_hyper(tl, &toff);
2758 tl += 2;
2759 fxdr_hyper(tl, &verf);
2760 tl += 2;
2761 siz = fxdr_unsigned(int, *tl++);
2762 cnt = fxdr_unsigned(int, *tl);
2763 off = toff;
2764 siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2765 xfer = NFS_SRVMAXDATA(nfsd);
2766 if (siz > xfer)
2767 siz = xfer;
2768 fullsiz = siz;
2769 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2770 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
2771 nfsm_reply(NFSX_UNSIGNED);
2772 nfsm_srvpostop_attr(getret, &at);
2773 return (0);
2774 }
2775 error = getret = VOP_GETATTR(vp, &at, cred, procp);
2776 if (!error && toff && verf != at.va_filerev)
2777 error = NFSERR_BAD_COOKIE;
2778 if (!error) {
2779 nqsrv_getl(vp, ND_READ);
2780 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
2781 }
2782 if (error) {
2783 vput(vp);
2784 nfsm_reply(NFSX_V3POSTOPATTR);
2785 nfsm_srvpostop_attr(getret, &at);
2786 return (0);
2787 }
2788 VOP_UNLOCK(vp, 0, procp);
2789 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
2790#ifdef __NetBSD__
2791 ncookies = siz / (7 * NFSX_UNSIGNED);
2792 MALLOC(cookies, u_long *, ncookies * sizeof (u_long *), M_TEMP,
2793 M_WAITOK);
2794#endif
2795again:
2796 iv.iov_base = rbuf;
2797 iv.iov_len = fullsiz;
2798 io.uio_iov = &iv;
2799 io.uio_iovcnt = 1;
2800 io.uio_offset = (off_t)off;
2801 io.uio_resid = fullsiz;
2802 io.uio_segflg = UIO_SYSSPACE;
2803 io.uio_rw = UIO_READ;
2804 io.uio_procp = (struct proc *)0;
2805 eofflag = 0;
2806 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp);
2807 if (cookies) {
2808 free((caddr_t)cookies, M_TEMP);
2809 cookies = NULL;
2810 }
2811 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
2812 off = (u_quad_t)io.uio_offset;
2813 getret = VOP_GETATTR(vp, &at, cred, procp);
2814 VOP_UNLOCK(vp, 0, procp);
2815 if (!cookies && !error)
2816 error = NFSERR_PERM;
2817 if (!error)
2818 error = getret;
2819 if (error) {
2820 vrele(vp);
2821 if (cookies)
2822 free((caddr_t)cookies, M_TEMP);
2823 free((caddr_t)rbuf, M_TEMP);
2824 nfsm_reply(NFSX_V3POSTOPATTR);
2825 nfsm_srvpostop_attr(getret, &at);
2826 return (0);
2827 }
2828 if (io.uio_resid) {
2829 siz -= io.uio_resid;
2830
2831 /*
2832 * If nothing read, return eof
2833 * rpc reply
2834 */
2835 if (siz == 0) {
2836 vrele(vp);
2837 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
2838 2 * NFSX_UNSIGNED);
2839 nfsm_srvpostop_attr(getret, &at);
2840 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
2841 txdr_hyper(&at.va_filerev, tl);
2842 tl += 2;
2843 *tl++ = nfs_false;
2844 *tl = nfs_true;
2845 FREE((caddr_t)cookies, M_TEMP);
2846 FREE((caddr_t)rbuf, M_TEMP);
2847 return (0);
2848 }
2849 }
2850
2851 /*
2852 * Check for degenerate cases of nothing useful read.
2853 * If so go try again
2854 */
2855 cpos = rbuf;
2856 cend = rbuf + siz;
2857 dp = (struct dirent *)cpos;
2858 cookiep = cookies;
2859#ifdef __FreeBSD__
2860 /*
2861 * For some reason FreeBSD's ufs_readdir() chooses to back the
2862 * directory offset up to a block boundary, so it is necessary to
2863 * skip over the records that preceed the requested offset. This
2864 * requires the assumption that file offset cookies monotonically
2865 * increase.
2866 */
2867 while (cpos < cend && ncookies > 0 &&
2868 (dp->d_fileno == 0 || ((u_quad_t)(*cookiep)) <= toff)) {
2869#else
2870 while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
2871#endif
2872 cpos += dp->d_reclen;
2873 dp = (struct dirent *)cpos;
2874 cookiep++;
2875 ncookies--;
2876 }
2877 if (cpos >= cend || ncookies == 0) {
2878 toff = off;
2879 siz = fullsiz;
2880 goto again;
2881 }
2882
2883 /*
2884 * Probe one of the directory entries to see if the filesystem
2885 * supports VGET.
2886 */
2887 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp) == EOPNOTSUPP) {
2888 error = NFSERR_NOTSUPP;
2889 vrele(vp);
2890 free((caddr_t)cookies, M_TEMP);
2891 free((caddr_t)rbuf, M_TEMP);
2892 nfsm_reply(NFSX_V3POSTOPATTR);
2893 nfsm_srvpostop_attr(getret, &at);
2894 return (0);
2895 }
2896 vput(nvp);
2897
2898 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
2899 nfsm_reply(cnt);
2900 nfsm_srvpostop_attr(getret, &at);
2901 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2902 txdr_hyper(&at.va_filerev, tl);
2903 mp = mp2 = mb;
2904 bp = bpos;
2905 be = bp + M_TRAILINGSPACE(mp);
2906
2907 /* Loop through the records and build reply */
2908 while (cpos < cend && ncookies > 0) {
2909 if (dp->d_fileno != 0) {
2910 nlen = dp->d_namlen;
2911 rem = nfsm_rndup(nlen)-nlen;
2912
2913 /*
2914 * For readdir_and_lookup get the vnode using
2915 * the file number.
2916 */
2917 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
2918 goto invalid;
2919 bzero((caddr_t)nfhp, NFSX_V3FH);
2920 nfhp->fh_fsid =
2921 nvp->v_mount->mnt_stat.f_fsid;
2922 if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
2923 vput(nvp);
2924 goto invalid;
2925 }
2926 if (VOP_GETATTR(nvp, vap, cred, procp)) {
2927 vput(nvp);
2928 goto invalid;
2929 }
2930 vput(nvp);
2931
2932 /*
2933 * If either the dircount or maxcount will be
2934 * exceeded, get out now. Both of these lengths
2935 * are calculated conservatively, including all
2936 * XDR overheads.
2937 */
2938 len += (7 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
2939 NFSX_V3POSTOPATTR);
2940 dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
2941 if (len > cnt || dirlen > fullsiz) {
2942 eofflag = 0;
2943 break;
2944 }
2945
2946 /*
2947 * Build the directory record xdr from
2948 * the dirent entry.
2949 */
2950 fp = (struct nfs_fattr *)&fl.fl_fattr;
2951 nfsm_srvfillattr(vap, fp);
2952 fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
2953 fl.fl_fhok = nfs_true;
2954 fl.fl_postopok = nfs_true;
2955 fl.fl_off.nfsuquad[0] = 0;
2956 fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
2957
2958 nfsm_clget;
2959 *tl = nfs_true;
2960 bp += NFSX_UNSIGNED;
2961 nfsm_clget;
2962 *tl = 0;
2963 bp += NFSX_UNSIGNED;
2964 nfsm_clget;
2965 *tl = txdr_unsigned(dp->d_fileno);
2966 bp += NFSX_UNSIGNED;
2967 nfsm_clget;
2968 *tl = txdr_unsigned(nlen);
2969 bp += NFSX_UNSIGNED;
2970
2971 /* And loop around copying the name */
2972 xfer = nlen;
2973 cp = dp->d_name;
2974 while (xfer > 0) {
2975 nfsm_clget;
2976 if ((bp + xfer) > be)
2977 tsiz = be - bp;
2978 else
2979 tsiz = xfer;
2980 bcopy(cp, bp, tsiz);
2981 bp += tsiz;
2982 xfer -= tsiz;
2983 if (xfer > 0)
2984 cp += tsiz;
2985 }
2986 /* And null pad to a long boundary */
2987 for (i = 0; i < rem; i++)
2988 *bp++ = '\0';
2989
2990 /*
2991 * Now copy the flrep structure out.
2992 */
2993 xfer = sizeof (struct flrep);
2994 cp = (caddr_t)&fl;
2995 while (xfer > 0) {
2996 nfsm_clget;
2997 if ((bp + xfer) > be)
2998 tsiz = be - bp;
2999 else
3000 tsiz = xfer;
3001 bcopy(cp, bp, tsiz);
3002 bp += tsiz;
3003 xfer -= tsiz;
3004 if (xfer > 0)
3005 cp += tsiz;
3006 }
3007 }
3008invalid:
3009 cpos += dp->d_reclen;
3010 dp = (struct dirent *)cpos;
3011 cookiep++;
3012 ncookies--;
3013 }
3014 vrele(vp);
3015 nfsm_clget;
3016 *tl = nfs_false;
3017 bp += NFSX_UNSIGNED;
3018 nfsm_clget;
3019 if (eofflag)
3020 *tl = nfs_true;
3021 else
3022 *tl = nfs_false;
3023 bp += NFSX_UNSIGNED;
3024 if (mp != mb) {
3025 if (bp < be)
3026 mp->m_len = bp - mtod(mp, caddr_t);
3027 } else
3028 mp->m_len += bp - bpos;
3029 FREE((caddr_t)cookies, M_TEMP);
3030 FREE((caddr_t)rbuf, M_TEMP);
3031 nfsm_srvdone;
3032}
3033
3034/*
3035 * nfs commit service
3036 */
3037int
3038nfsrv_commit(nfsd, slp, procp, mrq)
3039 struct nfsrv_descript *nfsd;
3040 struct nfssvc_sock *slp;
3041 struct proc *procp;
3042 struct mbuf **mrq;
3043{
3044 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3045 struct mbuf *nam = nfsd->nd_nam;
3046 caddr_t dpos = nfsd->nd_dpos;
3047 struct ucred *cred = &nfsd->nd_cr;
3048 struct vattr bfor, aft;
3049 struct vnode *vp;
3050 nfsfh_t nfh;
3051 fhandle_t *fhp;
3052 register u_long *tl;
3053 register long t1;
3054 caddr_t bpos;
3055 int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache;
3056 char *cp2;
3057 struct mbuf *mb, *mb2, *mreq;
3058 u_quad_t frev, off;
3059
3060#ifndef nolint
3061 cache = 0;
3062#endif
3063 fhp = &nfh.fh_generic;
3064 nfsm_srvmtofh(fhp);
3065 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
3066
3067 /*
3068 * XXX At this time VOP_FSYNC() does not accept offset and byte
3069 * count parameters, so these arguments are useless (someday maybe).
3070 */
3071 fxdr_hyper(tl, &off);
3072 tl += 2;
3073 cnt = fxdr_unsigned(int, *tl);
3074 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3075 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3076 nfsm_reply(2 * NFSX_UNSIGNED);
3077 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3078 return (0);
3079 }
3080 for_ret = VOP_GETATTR(vp, &bfor, cred, procp);
3081 error = VOP_FSYNC(vp, cred, MNT_WAIT, procp);
3082 aft_ret = VOP_GETATTR(vp, &aft, cred, procp);
3083 vput(vp);
3084 nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
3085 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3086 if (!error) {
3087 nfsm_build(tl, u_long *, NFSX_V3WRITEVERF);
3088 *tl++ = txdr_unsigned(boottime.tv_sec);
3089 *tl = txdr_unsigned(boottime.tv_usec);
3090 } else
3091 return (0);
3092 nfsm_srvdone;
3093}
3094
3095/*
3096 * nfs statfs service
3097 */
3098int
3099nfsrv_statfs(nfsd, slp, procp, mrq)
3100 struct nfsrv_descript *nfsd;
3101 struct nfssvc_sock *slp;
3102 struct proc *procp;
3103 struct mbuf **mrq;
3104{
3105 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3106 struct mbuf *nam = nfsd->nd_nam;
3107 caddr_t dpos = nfsd->nd_dpos;
3108 struct ucred *cred = &nfsd->nd_cr;
3109 register struct statfs *sf;
3110 register struct nfs_statfs *sfp;
3111 register u_long *tl;
3112 register long t1;
3113 caddr_t bpos;
3114 int error = 0, rdonly, cache, getret = 1;
3115 int v3 = (nfsd->nd_flag & ND_NFSV3);
3116 char *cp2;
3117 struct mbuf *mb, *mb2, *mreq;
3118 struct vnode *vp;
3119 struct vattr at;
3120 nfsfh_t nfh;
3121 fhandle_t *fhp;
3122 struct statfs statfs;
3123 u_quad_t frev, tval;
3124
3125#ifndef nolint
3126 cache = 0;
3127#endif
3128 fhp = &nfh.fh_generic;
3129 nfsm_srvmtofh(fhp);
3130 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3131 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3132 nfsm_reply(NFSX_UNSIGNED);
3133 nfsm_srvpostop_attr(getret, &at);
3134 return (0);
3135 }
3136 sf = &statfs;
3137 error = VFS_STATFS(vp->v_mount, sf, procp);
3138 getret = VOP_GETATTR(vp, &at, cred, procp);
3139 vput(vp);
3140 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
3141 if (v3)
3142 nfsm_srvpostop_attr(getret, &at);
3143 if (error)
3144 return (0);
3145 nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
3146 if (v3) {
3147 tval = (u_quad_t)sf->f_blocks;
3148 tval *= (u_quad_t)sf->f_bsize;
3149 txdr_hyper(&tval, &sfp->sf_tbytes);
3150 tval = (u_quad_t)sf->f_bfree;
3151 tval *= (u_quad_t)sf->f_bsize;
3152 txdr_hyper(&tval, &sfp->sf_fbytes);
3153 tval = (u_quad_t)sf->f_bavail;
3154 tval *= (u_quad_t)sf->f_bsize;
3155 txdr_hyper(&tval, &sfp->sf_abytes);
3156 sfp->sf_tfiles.nfsuquad[0] = 0;
3157 sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
3158 sfp->sf_ffiles.nfsuquad[0] = 0;
3159 sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3160 sfp->sf_afiles.nfsuquad[0] = 0;
3161 sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3162 sfp->sf_invarsec = 0;
3163 } else {
3164 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
3165 sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
3166 sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
3167 sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
3168 sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
3169 }
3170 nfsm_srvdone;
3171}
3172
3173/*
3174 * nfs fsinfo service
3175 */
3176int
3177nfsrv_fsinfo(nfsd, slp, procp, mrq)
3178 struct nfsrv_descript *nfsd;
3179 struct nfssvc_sock *slp;
3180 struct proc *procp;
3181 struct mbuf **mrq;
3182{
3183 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3184 struct mbuf *nam = nfsd->nd_nam;
3185 caddr_t dpos = nfsd->nd_dpos;
3186 struct ucred *cred = &nfsd->nd_cr;
3187 register u_long *tl;
3188 register struct nfsv3_fsinfo *sip;
3189 register long t1;
3190 caddr_t bpos;
3191 int error = 0, rdonly, cache, getret = 1, pref;
3192 char *cp2;
3193 struct mbuf *mb, *mb2, *mreq;
3194 struct vnode *vp;
3195 struct vattr at;
3196 nfsfh_t nfh;
3197 fhandle_t *fhp;
3198 u_quad_t frev;
3199
3200#ifndef nolint
3201 cache = 0;
3202#endif
3203 fhp = &nfh.fh_generic;
3204 nfsm_srvmtofh(fhp);
3205 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3206 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3207 nfsm_reply(NFSX_UNSIGNED);
3208 nfsm_srvpostop_attr(getret, &at);
3209 return (0);
3210 }
3211 getret = VOP_GETATTR(vp, &at, cred, procp);
3212 vput(vp);
3213 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
3214 nfsm_srvpostop_attr(getret, &at);
3215 nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
3216
3217 /*
3218 * XXX
3219 * There should be file system VFS OP(s) to get this information.
3220 * For now, assume ufs.
3221 */
3222 if (slp->ns_so->so_type == SOCK_DGRAM)
3223 pref = NFS_MAXDGRAMDATA;
3224 else
3225 pref = NFS_MAXDATA;
3226 sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
3227 sip->fs_rtpref = txdr_unsigned(pref);
3228 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3229 sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
3230 sip->fs_wtpref = txdr_unsigned(pref);
3231 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3232 sip->fs_dtpref = txdr_unsigned(pref);
3233 sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
3234 sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
3235 sip->fs_timedelta.nfsv3_sec = 0;
3236 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3237 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3238 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3239 NFSV3FSINFO_CANSETTIME);
3240 nfsm_srvdone;
3241}
3242
3243/*
3244 * nfs pathconf service
3245 */
3246int
3247nfsrv_pathconf(nfsd, slp, procp, mrq)
3248 struct nfsrv_descript *nfsd;
3249 struct nfssvc_sock *slp;
3250 struct proc *procp;
3251 struct mbuf **mrq;
3252{
3253 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3254 struct mbuf *nam = nfsd->nd_nam;
3255 caddr_t dpos = nfsd->nd_dpos;
3256 struct ucred *cred = &nfsd->nd_cr;
3257 register u_long *tl;
3258 register struct nfsv3_pathconf *pc;
3259 register long t1;
3260 caddr_t bpos;
3261 int error = 0, rdonly, cache, getret = 1, linkmax, namemax;
3262 int chownres, notrunc;
3263 char *cp2;
3264 struct mbuf *mb, *mb2, *mreq;
3265 struct vnode *vp;
3266 struct vattr at;
3267 nfsfh_t nfh;
3268 fhandle_t *fhp;
3269 u_quad_t frev;
3270
3271#ifndef nolint
3272 cache = 0;
3273#endif
3274 fhp = &nfh.fh_generic;
3275 nfsm_srvmtofh(fhp);
3276 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3277 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3278 nfsm_reply(NFSX_UNSIGNED);
3279 nfsm_srvpostop_attr(getret, &at);
3280 return (0);
3281 }
3282 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
3283 if (!error)
3284 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
3285 if (!error)
3286 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
3287 if (!error)
3288 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc);
3289 getret = VOP_GETATTR(vp, &at, cred, procp);
3290 vput(vp);
3291 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
3292 nfsm_srvpostop_attr(getret, &at);
3293 if (error)
3294 return (0);
3295 nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
3296
3297 pc->pc_linkmax = txdr_unsigned(linkmax);
3298 pc->pc_namemax = txdr_unsigned(namemax);
3299 pc->pc_notrunc = txdr_unsigned(notrunc);
3300 pc->pc_chownrestricted = txdr_unsigned(chownres);
3301
3302 /*
3303 * These should probably be supported by VOP_PATHCONF(), but
3304 * until msdosfs is exportable (why would you want to?), the
3305 * Unix defaults should be ok.
3306 */
3307 pc->pc_caseinsensitive = nfs_false;
3308 pc->pc_casepreserving = nfs_true;
3309 nfsm_srvdone;
3310}
3311
3312/*
3313 * Null operation, used by clients to ping server
3314 */
3315/* ARGSUSED */
3316int
3317nfsrv_null(nfsd, slp, procp, mrq)
3318 struct nfsrv_descript *nfsd;
3319 struct nfssvc_sock *slp;
3320 struct proc *procp;
3321 struct mbuf **mrq;
3322{
3323 struct mbuf *mrep = nfsd->nd_mrep;
3324 caddr_t bpos;
3325 int error = NFSERR_RETVOID, cache;
3326 struct mbuf *mb, *mreq;
3327 u_quad_t frev;
3328
3329#ifndef nolint
3330 cache = 0;
3331#endif
3332 nfsm_reply(0);
3333 return (0);
3334}
3335
3336/*
3337 * No operation, used for obsolete procedures
3338 */
3339/* ARGSUSED */
3340int
3341nfsrv_noop(nfsd, slp, procp, mrq)
3342 struct nfsrv_descript *nfsd;
3343 struct nfssvc_sock *slp;
3344 struct proc *procp;
3345 struct mbuf **mrq;
3346{
3347 struct mbuf *mrep = nfsd->nd_mrep;
3348 caddr_t bpos;
3349 int error, cache;
3350 struct mbuf *mb, *mreq;
3351 u_quad_t frev;
3352
3353#ifndef nolint
3354 cache = 0;
3355#endif
3356 if (nfsd->nd_repstat)
3357 error = nfsd->nd_repstat;
3358 else
3359 error = EPROCUNAVAIL;
3360 nfsm_reply(0);
3361 return (0);
3362}
3363
3364/*
3365 * Perform access checking for vnodes obtained from file handles that would
3366 * refer to files already opened by a Unix client. You cannot just use
3367 * vn_writechk() and VOP_ACCESS() for two reasons.
3368 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3369 * 2 - The owner is to be given access irrespective of mode bits so that
3370 * processes that chmod after opening a file don't break. I don't like
3371 * this because it opens a security hole, but since the nfs server opens
3372 * a security hole the size of a barn door anyhow, what the heck.
3373 */
3374static int
3375nfsrv_access(vp, flags, cred, rdonly, p)
3376 register struct vnode *vp;
3377 int flags;
3378 register struct ucred *cred;
3379 int rdonly;
3380 struct proc *p;
3381{
3382 struct vattr vattr;
3383 int error;
3384 if (flags & VWRITE) {
3385 /* Just vn_writechk() changed to check rdonly */
3386 /*
3387 * Disallow write attempts on read-only file systems;
3388 * unless the file is a socket or a block or character
3389 * device resident on the file system.
3390 */
3391 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3392 switch (vp->v_type) {
3393 case VREG: case VDIR: case VLNK:
3394 return (EROFS);
3395 }
3396 }
3397 /*
3398 * If there's shared text associated with
3399 * the inode, we can't allow writing.
3400 */
3401 if (vp->v_flag & VTEXT)
3402 return (ETXTBSY);
3403 }
3404 if (error = VOP_GETATTR(vp, &vattr, cred, p))
3405 return (error);
3406 if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
3407 cred->cr_uid != vattr.va_uid)
3408 return (error);
3409 return (0);
3410}
3411#endif /* NFS_NOSERVER */
3412
1252}
1253
1254/*
1255 * Sort the group list in increasing numerical order.
1256 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1257 * that used to be here.)
1258 */
1259void
1260nfsrvw_sort(list, num)
1261 register gid_t *list;
1262 register int num;
1263{
1264 register int i, j;
1265 gid_t v;
1266
1267 /* Insertion sort. */
1268 for (i = 1; i < num; i++) {
1269 v = list[i];
1270 /* find correct slot for value v, moving others up */
1271 for (j = i; --j >= 0 && v < list[j];)
1272 list[j + 1] = list[j];
1273 list[j + 1] = v;
1274 }
1275}
1276
1277/*
1278 * copy credentials making sure that the result can be compared with bcmp().
1279 */
1280void
1281nfsrv_setcred(incred, outcred)
1282 register struct ucred *incred, *outcred;
1283{
1284 register int i;
1285
1286 bzero((caddr_t)outcred, sizeof (struct ucred));
1287 outcred->cr_ref = 1;
1288 outcred->cr_uid = incred->cr_uid;
1289 outcred->cr_ngroups = incred->cr_ngroups;
1290 for (i = 0; i < incred->cr_ngroups; i++)
1291 outcred->cr_groups[i] = incred->cr_groups[i];
1292 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1293}
1294
1295/*
1296 * nfs create service
1297 * now does a truncate to 0 length via. setattr if it already exists
1298 */
1299int
1300nfsrv_create(nfsd, slp, procp, mrq)
1301 struct nfsrv_descript *nfsd;
1302 struct nfssvc_sock *slp;
1303 struct proc *procp;
1304 struct mbuf **mrq;
1305{
1306 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1307 struct mbuf *nam = nfsd->nd_nam;
1308 caddr_t dpos = nfsd->nd_dpos;
1309 struct ucred *cred = &nfsd->nd_cr;
1310 register struct nfs_fattr *fp;
1311 struct vattr va, dirfor, diraft;
1312 register struct vattr *vap = &va;
1313 register struct nfsv2_sattr *sp;
1314 register u_long *tl;
1315 struct nameidata nd;
1316 register caddr_t cp;
1317 register long t1;
1318 caddr_t bpos;
1319 int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1320 int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
1321 char *cp2;
1322 struct mbuf *mb, *mb2, *mreq;
1323 struct vnode *vp, *dirp = (struct vnode *)0;
1324 nfsfh_t nfh;
1325 fhandle_t *fhp;
1326 u_quad_t frev, tempsize;
1327 u_char cverf[NFSX_V3CREATEVERF];
1328
1329#ifndef nolint
1330 rdev = 0;
1331#endif
1332 nd.ni_cnd.cn_nameiop = 0;
1333 fhp = &nfh.fh_generic;
1334 nfsm_srvmtofh(fhp);
1335 nfsm_srvnamesiz(len);
1336 nd.ni_cnd.cn_cred = cred;
1337 nd.ni_cnd.cn_nameiop = CREATE;
1338 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1339 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1340 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1341 if (dirp) {
1342 if (v3)
1343 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1344 procp);
1345 else {
1346 vrele(dirp);
1347 dirp = (struct vnode *)0;
1348 }
1349 }
1350 if (error) {
1351 nfsm_reply(NFSX_WCCDATA(v3));
1352 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1353 if (dirp)
1354 vrele(dirp);
1355 return (0);
1356 }
1357 VATTR_NULL(vap);
1358 if (v3) {
1359 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1360 how = fxdr_unsigned(int, *tl);
1361 switch (how) {
1362 case NFSV3CREATE_GUARDED:
1363 if (nd.ni_vp) {
1364 error = EEXIST;
1365 break;
1366 }
1367 case NFSV3CREATE_UNCHECKED:
1368 nfsm_srvsattr(vap);
1369 break;
1370 case NFSV3CREATE_EXCLUSIVE:
1371 nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
1372 bcopy(cp, cverf, NFSX_V3CREATEVERF);
1373 exclusive_flag = 1;
1374 if (nd.ni_vp == NULL)
1375 vap->va_mode = 0;
1376 break;
1377 };
1378 vap->va_type = VREG;
1379 } else {
1380 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1381 vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
1382 if (vap->va_type == VNON)
1383 vap->va_type = VREG;
1384 vap->va_mode = nfstov_mode(sp->sa_mode);
1385 switch (vap->va_type) {
1386 case VREG:
1387 tsize = fxdr_unsigned(long, sp->sa_size);
1388 if (tsize != -1)
1389 vap->va_size = (u_quad_t)tsize;
1390 break;
1391 case VCHR:
1392 case VBLK:
1393 case VFIFO:
1394 rdev = fxdr_unsigned(long, sp->sa_size);
1395 break;
1396 };
1397 }
1398
1399 /*
1400 * Iff doesn't exist, create it
1401 * otherwise just truncate to 0 length
1402 * should I set the mode too ??
1403 */
1404 if (nd.ni_vp == NULL) {
1405 if (vap->va_type == VREG || vap->va_type == VSOCK) {
1406 vrele(nd.ni_startdir);
1407 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1408 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1409 if (!error) {
1410 nfsrv_object_create(nd.ni_vp);
1411 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1412 if (exclusive_flag) {
1413 exclusive_flag = 0;
1414 VATTR_NULL(vap);
1415 bcopy(cverf, (caddr_t)&vap->va_atime,
1416 NFSX_V3CREATEVERF);
1417 error = VOP_SETATTR(nd.ni_vp, vap, cred,
1418 procp);
1419 }
1420 }
1421 } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
1422 vap->va_type == VFIFO) {
1423 if (vap->va_type == VCHR && rdev == 0xffffffff)
1424 vap->va_type = VFIFO;
1425 if (error = suser(cred, (u_short *)0)) {
1426 vrele(nd.ni_startdir);
1427 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1428 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1429 vput(nd.ni_dvp);
1430 nfsm_reply(0);
1431 return (error);
1432 } else
1433 vap->va_rdev = (dev_t)rdev;
1434 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1435 if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
1436 vrele(nd.ni_startdir);
1437 nfsm_reply(0);
1438 }
1439 nd.ni_cnd.cn_nameiop = LOOKUP;
1440 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1441 nd.ni_cnd.cn_proc = procp;
1442 nd.ni_cnd.cn_cred = cred;
1443 if (error = lookup(&nd)) {
1444 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1445 nfsm_reply(0);
1446 }
1447 nfsrv_object_create(nd.ni_vp);
1448 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1449 if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1450 vrele(nd.ni_dvp);
1451 vput(nd.ni_vp);
1452 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1453 error = EINVAL;
1454 nfsm_reply(0);
1455 }
1456 } else {
1457 vrele(nd.ni_startdir);
1458 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1459 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1460 vput(nd.ni_dvp);
1461 error = ENXIO;
1462 }
1463 vp = nd.ni_vp;
1464 } else {
1465 vrele(nd.ni_startdir);
1466 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1467 vp = nd.ni_vp;
1468 if (nd.ni_dvp == vp)
1469 vrele(nd.ni_dvp);
1470 else
1471 vput(nd.ni_dvp);
1472 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1473 if (vap->va_size != -1) {
1474 error = nfsrv_access(vp, VWRITE, cred,
1475 (nd.ni_cnd.cn_flags & RDONLY), procp);
1476 if (!error) {
1477 nqsrv_getl(vp, ND_WRITE);
1478 tempsize = vap->va_size;
1479 VATTR_NULL(vap);
1480 vap->va_size = tempsize;
1481 error = VOP_SETATTR(vp, vap, cred,
1482 procp);
1483 }
1484 if (error)
1485 vput(vp);
1486 }
1487 }
1488 if (!error) {
1489 bzero((caddr_t)fhp, sizeof(nfh));
1490 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1491 error = VFS_VPTOFH(vp, &fhp->fh_fid);
1492 if (!error)
1493 error = VOP_GETATTR(vp, vap, cred, procp);
1494 vput(vp);
1495 }
1496 if (v3) {
1497 if (exclusive_flag && !error &&
1498 bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF))
1499 error = EEXIST;
1500 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1501 vrele(dirp);
1502 }
1503 nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
1504 if (v3) {
1505 if (!error) {
1506 nfsm_srvpostop_fh(fhp);
1507 nfsm_srvpostop_attr(0, vap);
1508 }
1509 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1510 } else {
1511 nfsm_srvfhtom(fhp, v3);
1512 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1513 nfsm_srvfillattr(vap, fp);
1514 }
1515 return (0);
1516nfsmout:
1517 if (dirp)
1518 vrele(dirp);
1519 if (nd.ni_cnd.cn_nameiop) {
1520 vrele(nd.ni_startdir);
1521 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1522 }
1523 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1524 if (nd.ni_dvp == nd.ni_vp)
1525 vrele(nd.ni_dvp);
1526 else
1527 vput(nd.ni_dvp);
1528 if (nd.ni_vp)
1529 vput(nd.ni_vp);
1530 return (error);
1531}
1532
1533/*
1534 * nfs v3 mknod service
1535 */
1536int
1537nfsrv_mknod(nfsd, slp, procp, mrq)
1538 struct nfsrv_descript *nfsd;
1539 struct nfssvc_sock *slp;
1540 struct proc *procp;
1541 struct mbuf **mrq;
1542{
1543 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1544 struct mbuf *nam = nfsd->nd_nam;
1545 caddr_t dpos = nfsd->nd_dpos;
1546 struct ucred *cred = &nfsd->nd_cr;
1547 struct vattr va, dirfor, diraft;
1548 register struct vattr *vap = &va;
1549 register u_long *tl;
1550 struct nameidata nd;
1551 register long t1;
1552 caddr_t bpos;
1553 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
1554 u_long major, minor;
1555 enum vtype vtyp;
1556 char *cp2;
1557 struct mbuf *mb, *mb2, *mreq;
1558 struct vnode *vp, *dirp = (struct vnode *)0;
1559 nfsfh_t nfh;
1560 fhandle_t *fhp;
1561 u_quad_t frev;
1562
1563 nd.ni_cnd.cn_nameiop = 0;
1564 fhp = &nfh.fh_generic;
1565 nfsm_srvmtofh(fhp);
1566 nfsm_srvnamesiz(len);
1567 nd.ni_cnd.cn_cred = cred;
1568 nd.ni_cnd.cn_nameiop = CREATE;
1569 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1570 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1571 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1572 if (dirp)
1573 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
1574 if (error) {
1575 nfsm_reply(NFSX_WCCDATA(1));
1576 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1577 if (dirp)
1578 vrele(dirp);
1579 return (0);
1580 }
1581 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1582 vtyp = nfsv3tov_type(*tl);
1583 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1584 vrele(nd.ni_startdir);
1585 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1586 error = NFSERR_BADTYPE;
1587 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1588 vput(nd.ni_dvp);
1589 goto out;
1590 }
1591 VATTR_NULL(vap);
1592 nfsm_srvsattr(vap);
1593 if (vtyp == VCHR || vtyp == VBLK) {
1594 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1595 major = fxdr_unsigned(u_long, *tl++);
1596 minor = fxdr_unsigned(u_long, *tl);
1597 vap->va_rdev = makedev(major, minor);
1598 }
1599
1600 /*
1601 * Iff doesn't exist, create it.
1602 */
1603 if (nd.ni_vp) {
1604 vrele(nd.ni_startdir);
1605 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1606 error = EEXIST;
1607 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1608 vput(nd.ni_dvp);
1609 goto out;
1610 }
1611 vap->va_type = vtyp;
1612 if (vtyp == VSOCK) {
1613 vrele(nd.ni_startdir);
1614 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1615 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1616 if (!error)
1617 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1618 } else {
1619 if (error = suser(cred, (u_short *)0)) {
1620 vrele(nd.ni_startdir);
1621 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1622 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1623 vput(nd.ni_dvp);
1624 goto out;
1625 }
1626 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1627 if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
1628 vrele(nd.ni_startdir);
1629 goto out;
1630 }
1631 nd.ni_cnd.cn_nameiop = LOOKUP;
1632 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1633 nd.ni_cnd.cn_proc = procp;
1634 nd.ni_cnd.cn_cred = procp->p_ucred;
1635 error = lookup(&nd);
1636 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1637 if (error)
1638 goto out;
1639 if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1640 vrele(nd.ni_dvp);
1641 vput(nd.ni_vp);
1642 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1643 error = EINVAL;
1644 }
1645 }
1646out:
1647 vp = nd.ni_vp;
1648 if (!error) {
1649 bzero((caddr_t)fhp, sizeof(nfh));
1650 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1651 error = VFS_VPTOFH(vp, &fhp->fh_fid);
1652 if (!error)
1653 error = VOP_GETATTR(vp, vap, cred, procp);
1654 vput(vp);
1655 }
1656 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1657 vrele(dirp);
1658 nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
1659 if (!error) {
1660 nfsm_srvpostop_fh(fhp);
1661 nfsm_srvpostop_attr(0, vap);
1662 }
1663 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1664 return (0);
1665nfsmout:
1666 if (dirp)
1667 vrele(dirp);
1668 if (nd.ni_cnd.cn_nameiop) {
1669 vrele(nd.ni_startdir);
1670 free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1671 }
1672 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1673 if (nd.ni_dvp == nd.ni_vp)
1674 vrele(nd.ni_dvp);
1675 else
1676 vput(nd.ni_dvp);
1677 if (nd.ni_vp)
1678 vput(nd.ni_vp);
1679 return (error);
1680}
1681
1682/*
1683 * nfs remove service
1684 */
1685int
1686nfsrv_remove(nfsd, slp, procp, mrq)
1687 struct nfsrv_descript *nfsd;
1688 struct nfssvc_sock *slp;
1689 struct proc *procp;
1690 struct mbuf **mrq;
1691{
1692 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1693 struct mbuf *nam = nfsd->nd_nam;
1694 caddr_t dpos = nfsd->nd_dpos;
1695 struct ucred *cred = &nfsd->nd_cr;
1696 struct nameidata nd;
1697 register u_long *tl;
1698 register long t1;
1699 caddr_t bpos;
1700 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
1701 int v3 = (nfsd->nd_flag & ND_NFSV3);
1702 char *cp2;
1703 struct mbuf *mb, *mreq;
1704 struct vnode *vp, *dirp;
1705 struct vattr dirfor, diraft;
1706 nfsfh_t nfh;
1707 fhandle_t *fhp;
1708 u_quad_t frev;
1709
1710#ifndef nolint
1711 vp = (struct vnode *)0;
1712#endif
1713 fhp = &nfh.fh_generic;
1714 nfsm_srvmtofh(fhp);
1715 nfsm_srvnamesiz(len);
1716 nd.ni_cnd.cn_cred = cred;
1717 nd.ni_cnd.cn_nameiop = DELETE;
1718 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1719 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1720 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1721 if (dirp) {
1722 if (v3)
1723 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1724 procp);
1725 else
1726 vrele(dirp);
1727 }
1728 if (!error) {
1729 vp = nd.ni_vp;
1730 if (vp->v_type == VDIR) {
1731 error = EPERM; /* POSIX */
1732 goto out;
1733 }
1734 /*
1735 * The root of a mounted filesystem cannot be deleted.
1736 */
1737 if (vp->v_flag & VROOT) {
1738 error = EBUSY;
1739 goto out;
1740 }
1741out:
1742 if (!error) {
1743 vnode_pager_uncache(vp, procp);
1744 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1745 nqsrv_getl(vp, ND_WRITE);
1746
1747 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1748
1749 } else {
1750 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1751 if (nd.ni_dvp == vp)
1752 vrele(nd.ni_dvp);
1753 else
1754 vput(nd.ni_dvp);
1755 vput(vp);
1756 }
1757 }
1758 if (dirp && v3) {
1759 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1760 vrele(dirp);
1761 }
1762 nfsm_reply(NFSX_WCCDATA(v3));
1763 if (v3) {
1764 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1765 return (0);
1766 }
1767 nfsm_srvdone;
1768}
1769
1770/*
1771 * nfs rename service
1772 */
1773int
1774nfsrv_rename(nfsd, slp, procp, mrq)
1775 struct nfsrv_descript *nfsd;
1776 struct nfssvc_sock *slp;
1777 struct proc *procp;
1778 struct mbuf **mrq;
1779{
1780 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1781 struct mbuf *nam = nfsd->nd_nam;
1782 caddr_t dpos = nfsd->nd_dpos;
1783 struct ucred *cred = &nfsd->nd_cr;
1784 register u_long *tl;
1785 register long t1;
1786 caddr_t bpos;
1787 int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
1788 int tdirfor_ret = 1, tdiraft_ret = 1;
1789 int v3 = (nfsd->nd_flag & ND_NFSV3);
1790 char *cp2;
1791 struct mbuf *mb, *mreq;
1792 struct nameidata fromnd, tond;
1793 struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0;
1794 struct vnode *tdirp = (struct vnode *)0;
1795 struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
1796 nfsfh_t fnfh, tnfh;
1797 fhandle_t *ffhp, *tfhp;
1798 u_quad_t frev;
1799 uid_t saved_uid;
1800
1801#ifndef nolint
1802 fvp = (struct vnode *)0;
1803#endif
1804 ffhp = &fnfh.fh_generic;
1805 tfhp = &tnfh.fh_generic;
1806 fromnd.ni_cnd.cn_nameiop = 0;
1807 tond.ni_cnd.cn_nameiop = 0;
1808 nfsm_srvmtofh(ffhp);
1809 nfsm_srvnamesiz(len);
1810 /*
1811 * Remember our original uid so that we can reset cr_uid before
1812 * the second nfs_namei() call, in case it is remapped.
1813 */
1814 saved_uid = cred->cr_uid;
1815 fromnd.ni_cnd.cn_cred = cred;
1816 fromnd.ni_cnd.cn_nameiop = DELETE;
1817 fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
1818 error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
1819 &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1820 if (fdirp) {
1821 if (v3)
1822 fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred,
1823 procp);
1824 else {
1825 vrele(fdirp);
1826 fdirp = (struct vnode *)0;
1827 }
1828 }
1829 if (error) {
1830 nfsm_reply(2 * NFSX_WCCDATA(v3));
1831 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1832 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1833 if (fdirp)
1834 vrele(fdirp);
1835 return (0);
1836 }
1837 fvp = fromnd.ni_vp;
1838 nfsm_srvmtofh(tfhp);
1839 nfsm_strsiz(len2, NFS_MAXNAMLEN);
1840 cred->cr_uid = saved_uid;
1841 tond.ni_cnd.cn_cred = cred;
1842 tond.ni_cnd.cn_nameiop = RENAME;
1843 tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
1844 error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
1845 &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1846 if (tdirp) {
1847 if (v3)
1848 tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred,
1849 procp);
1850 else {
1851 vrele(tdirp);
1852 tdirp = (struct vnode *)0;
1853 }
1854 }
1855 if (error) {
1856 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1857 vrele(fromnd.ni_dvp);
1858 vrele(fvp);
1859 goto out1;
1860 }
1861 tdvp = tond.ni_dvp;
1862 tvp = tond.ni_vp;
1863 if (tvp != NULL) {
1864 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1865 if (v3)
1866 error = EEXIST;
1867 else
1868 error = EISDIR;
1869 goto out;
1870 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1871 if (v3)
1872 error = EEXIST;
1873 else
1874 error = ENOTDIR;
1875 goto out;
1876 }
1877 if (tvp->v_type == VDIR && tvp->v_mountedhere) {
1878 if (v3)
1879 error = EXDEV;
1880 else
1881 error = ENOTEMPTY;
1882 goto out;
1883 }
1884 }
1885 if (fvp->v_type == VDIR && fvp->v_mountedhere) {
1886 if (v3)
1887 error = EXDEV;
1888 else
1889 error = ENOTEMPTY;
1890 goto out;
1891 }
1892 if (fvp->v_mount != tdvp->v_mount) {
1893 if (v3)
1894 error = EXDEV;
1895 else
1896 error = ENOTEMPTY;
1897 goto out;
1898 }
1899 if (fvp == tdvp)
1900 if (v3)
1901 error = EINVAL;
1902 else
1903 error = ENOTEMPTY;
1904 /*
1905 * If source is the same as the destination (that is the
1906 * same vnode with the same name in the same directory),
1907 * then there is nothing to do.
1908 */
1909 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
1910 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1911 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
1912 fromnd.ni_cnd.cn_namelen))
1913 error = -1;
1914out:
1915 if (!error) {
1916 nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
1917 nqsrv_getl(tdvp, ND_WRITE);
1918 if (tvp) {
1919 nqsrv_getl(tvp, ND_WRITE);
1920 (void) vnode_pager_uncache(tvp, procp);
1921 }
1922 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
1923 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
1924 } else {
1925 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
1926 if (tdvp == tvp)
1927 vrele(tdvp);
1928 else
1929 vput(tdvp);
1930 if (tvp)
1931 vput(tvp);
1932 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1933 vrele(fromnd.ni_dvp);
1934 vrele(fvp);
1935 if (error == -1)
1936 error = 0;
1937 }
1938 vrele(tond.ni_startdir);
1939 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1940out1:
1941 if (fdirp) {
1942 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp);
1943 vrele(fdirp);
1944 }
1945 if (tdirp) {
1946 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp);
1947 vrele(tdirp);
1948 }
1949 vrele(fromnd.ni_startdir);
1950 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1951 nfsm_reply(2 * NFSX_WCCDATA(v3));
1952 if (v3) {
1953 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1954 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1955 }
1956 return (0);
1957
1958nfsmout:
1959 if (fdirp)
1960 vrele(fdirp);
1961 if (tdirp)
1962 vrele(tdirp);
1963 if (tond.ni_cnd.cn_nameiop) {
1964 vrele(tond.ni_startdir);
1965 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1966 }
1967 if (fromnd.ni_cnd.cn_nameiop) {
1968 vrele(fromnd.ni_startdir);
1969 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1970 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1971 vrele(fromnd.ni_dvp);
1972 vrele(fvp);
1973 }
1974 return (error);
1975}
1976
1977/*
1978 * nfs link service
1979 */
1980int
1981nfsrv_link(nfsd, slp, procp, mrq)
1982 struct nfsrv_descript *nfsd;
1983 struct nfssvc_sock *slp;
1984 struct proc *procp;
1985 struct mbuf **mrq;
1986{
1987 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1988 struct mbuf *nam = nfsd->nd_nam;
1989 caddr_t dpos = nfsd->nd_dpos;
1990 struct ucred *cred = &nfsd->nd_cr;
1991 struct nameidata nd;
1992 register u_long *tl;
1993 register long t1;
1994 caddr_t bpos;
1995 int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1;
1996 int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
1997 char *cp2;
1998 struct mbuf *mb, *mreq;
1999 struct vnode *vp, *xp, *dirp = (struct vnode *)0;
2000 struct vattr dirfor, diraft, at;
2001 nfsfh_t nfh, dnfh;
2002 fhandle_t *fhp, *dfhp;
2003 u_quad_t frev;
2004
2005 fhp = &nfh.fh_generic;
2006 dfhp = &dnfh.fh_generic;
2007 nfsm_srvmtofh(fhp);
2008 nfsm_srvmtofh(dfhp);
2009 nfsm_srvnamesiz(len);
2010 if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
2011 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
2012 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2013 nfsm_srvpostop_attr(getret, &at);
2014 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2015 return (0);
2016 }
2017 if (vp->v_type == VDIR) {
2018 error = EPERM; /* POSIX */
2019 goto out1;
2020 }
2021 nd.ni_cnd.cn_cred = cred;
2022 nd.ni_cnd.cn_nameiop = CREATE;
2023 nd.ni_cnd.cn_flags = LOCKPARENT;
2024 error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
2025 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2026 if (dirp) {
2027 if (v3)
2028 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2029 procp);
2030 else {
2031 vrele(dirp);
2032 dirp = (struct vnode *)0;
2033 }
2034 }
2035 if (error)
2036 goto out1;
2037 xp = nd.ni_vp;
2038 if (xp != NULL) {
2039 error = EEXIST;
2040 goto out;
2041 }
2042 xp = nd.ni_dvp;
2043 if (vp->v_mount != xp->v_mount)
2044 error = EXDEV;
2045out:
2046 if (!error) {
2047 nqsrv_getl(vp, ND_WRITE);
2048 nqsrv_getl(xp, ND_WRITE);
2049#if defined(__NetBSD__) || defined(__FreeBSD__)
2050 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
2051#else /* Lite2 version */
2052 error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
2053#endif
2054 } else {
2055 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2056 if (nd.ni_dvp == nd.ni_vp)
2057 vrele(nd.ni_dvp);
2058 else
2059 vput(nd.ni_dvp);
2060 if (nd.ni_vp)
2061 vrele(nd.ni_vp);
2062 }
2063out1:
2064 if (v3)
2065 getret = VOP_GETATTR(vp, &at, cred, procp);
2066 if (dirp) {
2067 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2068 vrele(dirp);
2069 }
2070 vrele(vp);
2071 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2072 if (v3) {
2073 nfsm_srvpostop_attr(getret, &at);
2074 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2075 return (0);
2076 }
2077 nfsm_srvdone;
2078}
2079
2080/*
2081 * nfs symbolic link service
2082 */
2083int
2084nfsrv_symlink(nfsd, slp, procp, mrq)
2085 struct nfsrv_descript *nfsd;
2086 struct nfssvc_sock *slp;
2087 struct proc *procp;
2088 struct mbuf **mrq;
2089{
2090 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2091 struct mbuf *nam = nfsd->nd_nam;
2092 caddr_t dpos = nfsd->nd_dpos;
2093 struct ucred *cred = &nfsd->nd_cr;
2094 struct vattr va, dirfor, diraft;
2095 struct nameidata nd;
2096 register struct vattr *vap = &va;
2097 register u_long *tl;
2098 register long t1;
2099 struct nfsv2_sattr *sp;
2100 char *bpos, *pathcp = (char *)0, *cp2;
2101 struct uio io;
2102 struct iovec iv;
2103 int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1;
2104 int v3 = (nfsd->nd_flag & ND_NFSV3);
2105 struct mbuf *mb, *mreq, *mb2;
2106 struct vnode *dirp = (struct vnode *)0;
2107 nfsfh_t nfh;
2108 fhandle_t *fhp;
2109 u_quad_t frev;
2110
2111 nd.ni_cnd.cn_nameiop = 0;
2112 fhp = &nfh.fh_generic;
2113 nfsm_srvmtofh(fhp);
2114 nfsm_srvnamesiz(len);
2115 nd.ni_cnd.cn_cred = cred;
2116 nd.ni_cnd.cn_nameiop = CREATE;
2117 nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART;
2118 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2119 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2120 if (dirp) {
2121 if (v3)
2122 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2123 procp);
2124 else {
2125 vrele(dirp);
2126 dirp = (struct vnode *)0;
2127 }
2128 }
2129 if (error)
2130 goto out;
2131 VATTR_NULL(vap);
2132 if (v3)
2133 nfsm_srvsattr(vap);
2134 nfsm_strsiz(len2, NFS_MAXPATHLEN);
2135 MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
2136 iv.iov_base = pathcp;
2137 iv.iov_len = len2;
2138 io.uio_resid = len2;
2139 io.uio_offset = 0;
2140 io.uio_iov = &iv;
2141 io.uio_iovcnt = 1;
2142 io.uio_segflg = UIO_SYSSPACE;
2143 io.uio_rw = UIO_READ;
2144 io.uio_procp = (struct proc *)0;
2145 nfsm_mtouio(&io, len2);
2146 if (!v3) {
2147 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2148 vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
2149 }
2150 *(pathcp + len2) = '\0';
2151 if (nd.ni_vp) {
2152 vrele(nd.ni_startdir);
2153 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2154 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2155 if (nd.ni_dvp == nd.ni_vp)
2156 vrele(nd.ni_dvp);
2157 else
2158 vput(nd.ni_dvp);
2159 vrele(nd.ni_vp);
2160 error = EEXIST;
2161 goto out;
2162 }
2163 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2164 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
2165 if (error)
2166 vrele(nd.ni_startdir);
2167 else {
2168 if (v3) {
2169 nd.ni_cnd.cn_nameiop = LOOKUP;
2170 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW);
2171 nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
2172 nd.ni_cnd.cn_proc = procp;
2173 nd.ni_cnd.cn_cred = cred;
2174 error = lookup(&nd);
2175 if (!error) {
2176 bzero((caddr_t)fhp, sizeof(nfh));
2177 fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
2178 error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
2179 if (!error)
2180 error = VOP_GETATTR(nd.ni_vp, vap, cred,
2181 procp);
2182 vput(nd.ni_vp);
2183 }
2184 } else
2185 vrele(nd.ni_startdir);
2186 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2187 }
2188out:
2189 if (pathcp)
2190 FREE(pathcp, M_TEMP);
2191 if (dirp) {
2192 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2193 vrele(dirp);
2194 }
2195 nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2196 if (v3) {
2197 if (!error) {
2198 nfsm_srvpostop_fh(fhp);
2199 nfsm_srvpostop_attr(0, vap);
2200 }
2201 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2202 }
2203 return (0);
2204nfsmout:
2205 if (nd.ni_cnd.cn_nameiop) {
2206 vrele(nd.ni_startdir);
2207 free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2208 }
2209 if (dirp)
2210 vrele(dirp);
2211 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2212 if (nd.ni_dvp == nd.ni_vp)
2213 vrele(nd.ni_dvp);
2214 else
2215 vput(nd.ni_dvp);
2216 if (nd.ni_vp)
2217 vrele(nd.ni_vp);
2218 if (pathcp)
2219 FREE(pathcp, M_TEMP);
2220 return (error);
2221}
2222
2223/*
2224 * nfs mkdir service
2225 */
2226int
2227nfsrv_mkdir(nfsd, slp, procp, mrq)
2228 struct nfsrv_descript *nfsd;
2229 struct nfssvc_sock *slp;
2230 struct proc *procp;
2231 struct mbuf **mrq;
2232{
2233 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2234 struct mbuf *nam = nfsd->nd_nam;
2235 caddr_t dpos = nfsd->nd_dpos;
2236 struct ucred *cred = &nfsd->nd_cr;
2237 struct vattr va, dirfor, diraft;
2238 register struct vattr *vap = &va;
2239 register struct nfs_fattr *fp;
2240 struct nameidata nd;
2241 register caddr_t cp;
2242 register u_long *tl;
2243 register long t1;
2244 caddr_t bpos;
2245 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2246 int v3 = (nfsd->nd_flag & ND_NFSV3);
2247 char *cp2;
2248 struct mbuf *mb, *mb2, *mreq;
2249 struct vnode *vp, *dirp = (struct vnode *)0;
2250 nfsfh_t nfh;
2251 fhandle_t *fhp;
2252 u_quad_t frev;
2253
2254 fhp = &nfh.fh_generic;
2255 nfsm_srvmtofh(fhp);
2256 nfsm_srvnamesiz(len);
2257 nd.ni_cnd.cn_cred = cred;
2258 nd.ni_cnd.cn_nameiop = CREATE;
2259 nd.ni_cnd.cn_flags = LOCKPARENT;
2260 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2261 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2262 if (dirp) {
2263 if (v3)
2264 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2265 procp);
2266 else {
2267 vrele(dirp);
2268 dirp = (struct vnode *)0;
2269 }
2270 }
2271 if (error) {
2272 nfsm_reply(NFSX_WCCDATA(v3));
2273 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2274 if (dirp)
2275 vrele(dirp);
2276 return (0);
2277 }
2278 VATTR_NULL(vap);
2279 if (v3) {
2280 nfsm_srvsattr(vap);
2281 } else {
2282 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2283 vap->va_mode = nfstov_mode(*tl++);
2284 }
2285 vap->va_type = VDIR;
2286 vp = nd.ni_vp;
2287 if (vp != NULL) {
2288 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2289 if (nd.ni_dvp == vp)
2290 vrele(nd.ni_dvp);
2291 else
2292 vput(nd.ni_dvp);
2293 vrele(vp);
2294 error = EEXIST;
2295 goto out;
2296 }
2297 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2298 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
2299 if (!error) {
2300 vp = nd.ni_vp;
2301 bzero((caddr_t)fhp, sizeof(nfh));
2302 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
2303 error = VFS_VPTOFH(vp, &fhp->fh_fid);
2304 if (!error)
2305 error = VOP_GETATTR(vp, vap, cred, procp);
2306 vput(vp);
2307 }
2308out:
2309 if (dirp) {
2310 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2311 vrele(dirp);
2312 }
2313 nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2314 if (v3) {
2315 if (!error) {
2316 nfsm_srvpostop_fh(fhp);
2317 nfsm_srvpostop_attr(0, vap);
2318 }
2319 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2320 } else {
2321 nfsm_srvfhtom(fhp, v3);
2322 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
2323 nfsm_srvfillattr(vap, fp);
2324 }
2325 return (0);
2326nfsmout:
2327 if (dirp)
2328 vrele(dirp);
2329 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2330 if (nd.ni_dvp == nd.ni_vp)
2331 vrele(nd.ni_dvp);
2332 else
2333 vput(nd.ni_dvp);
2334 if (nd.ni_vp)
2335 vrele(nd.ni_vp);
2336 return (error);
2337}
2338
2339/*
2340 * nfs rmdir service
2341 */
2342int
2343nfsrv_rmdir(nfsd, slp, procp, mrq)
2344 struct nfsrv_descript *nfsd;
2345 struct nfssvc_sock *slp;
2346 struct proc *procp;
2347 struct mbuf **mrq;
2348{
2349 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2350 struct mbuf *nam = nfsd->nd_nam;
2351 caddr_t dpos = nfsd->nd_dpos;
2352 struct ucred *cred = &nfsd->nd_cr;
2353 register u_long *tl;
2354 register long t1;
2355 caddr_t bpos;
2356 int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2357 int v3 = (nfsd->nd_flag & ND_NFSV3);
2358 char *cp2;
2359 struct mbuf *mb, *mreq;
2360 struct vnode *vp, *dirp = (struct vnode *)0;
2361 struct vattr dirfor, diraft;
2362 nfsfh_t nfh;
2363 fhandle_t *fhp;
2364 struct nameidata nd;
2365 u_quad_t frev;
2366
2367 fhp = &nfh.fh_generic;
2368 nfsm_srvmtofh(fhp);
2369 nfsm_srvnamesiz(len);
2370 nd.ni_cnd.cn_cred = cred;
2371 nd.ni_cnd.cn_nameiop = DELETE;
2372 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2373 error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2374 &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2375 if (dirp) {
2376 if (v3)
2377 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2378 procp);
2379 else {
2380 vrele(dirp);
2381 dirp = (struct vnode *)0;
2382 }
2383 }
2384 if (error) {
2385 nfsm_reply(NFSX_WCCDATA(v3));
2386 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2387 if (dirp)
2388 vrele(dirp);
2389 return (0);
2390 }
2391 vp = nd.ni_vp;
2392 if (vp->v_type != VDIR) {
2393 error = ENOTDIR;
2394 goto out;
2395 }
2396 /*
2397 * No rmdir "." please.
2398 */
2399 if (nd.ni_dvp == vp) {
2400 error = EINVAL;
2401 goto out;
2402 }
2403 /*
2404 * The root of a mounted filesystem cannot be deleted.
2405 */
2406 if (vp->v_flag & VROOT)
2407 error = EBUSY;
2408out:
2409 if (!error) {
2410 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2411 nqsrv_getl(vp, ND_WRITE);
2412 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2413 } else {
2414 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2415 if (nd.ni_dvp == nd.ni_vp)
2416 vrele(nd.ni_dvp);
2417 else
2418 vput(nd.ni_dvp);
2419 vput(vp);
2420 }
2421 if (dirp) {
2422 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2423 vrele(dirp);
2424 }
2425 nfsm_reply(NFSX_WCCDATA(v3));
2426 if (v3) {
2427 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2428 return (0);
2429 }
2430 nfsm_srvdone;
2431}
2432
2433/*
2434 * nfs readdir service
2435 * - mallocs what it thinks is enough to read
2436 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2437 * - calls VOP_READDIR()
2438 * - loops around building the reply
2439 * if the output generated exceeds count break out of loop
2440 * The nfsm_clget macro is used here so that the reply will be packed
2441 * tightly in mbuf clusters.
2442 * - it only knows that it has encountered eof when the VOP_READDIR()
2443 * reads nothing
2444 * - as such one readdir rpc will return eof false although you are there
2445 * and then the next will return eof
2446 * - it trims out records with d_fileno == 0
2447 * this doesn't matter for Unix clients, but they might confuse clients
2448 * for other os'.
2449 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2450 * than requested, but this may not apply to all filesystems. For
2451 * example, client NFS does not { although it is never remote mounted
2452 * anyhow }
2453 * The alternate call nfsrv_readdirplus() does lookups as well.
2454 * PS: The NFS protocol spec. does not clarify what the "count" byte
2455 * argument is a count of.. just name strings and file id's or the
2456 * entire reply rpc or ...
2457 * I tried just file name and id sizes and it confused the Sun client,
2458 * so I am using the full rpc size now. The "paranoia.." comment refers
2459 * to including the status longwords that are not a part of the dir.
2460 * "entry" structures, but are in the rpc.
2461 */
2462struct flrep {
2463 nfsuint64 fl_off;
2464 u_long fl_postopok;
2465 u_long fl_fattr[NFSX_V3FATTR / sizeof (u_long)];
2466 u_long fl_fhok;
2467 u_long fl_fhsize;
2468 u_long fl_nfh[NFSX_V3FH / sizeof (u_long)];
2469};
2470
2471int
2472nfsrv_readdir(nfsd, slp, procp, mrq)
2473 struct nfsrv_descript *nfsd;
2474 struct nfssvc_sock *slp;
2475 struct proc *procp;
2476 struct mbuf **mrq;
2477{
2478 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2479 struct mbuf *nam = nfsd->nd_nam;
2480 caddr_t dpos = nfsd->nd_dpos;
2481 struct ucred *cred = &nfsd->nd_cr;
2482 register char *bp, *be;
2483 register struct mbuf *mp;
2484 register struct dirent *dp;
2485 register caddr_t cp;
2486 register u_long *tl;
2487 register long t1;
2488 caddr_t bpos;
2489 struct mbuf *mb, *mb2, *mreq, *mp2;
2490 char *cpos, *cend, *cp2, *rbuf;
2491 struct vnode *vp;
2492 struct vattr at;
2493 nfsfh_t nfh;
2494 fhandle_t *fhp;
2495 struct uio io;
2496 struct iovec iv;
2497 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2498 int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies;
2499 int v3 = (nfsd->nd_flag & ND_NFSV3);
2500 u_quad_t frev, off, toff, verf;
2501 u_long *cookies = NULL, *cookiep;
2502
2503 fhp = &nfh.fh_generic;
2504 nfsm_srvmtofh(fhp);
2505 if (v3) {
2506 nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
2507 fxdr_hyper(tl, &toff);
2508 tl += 2;
2509 fxdr_hyper(tl, &verf);
2510 tl += 2;
2511 } else {
2512 nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2513 toff = fxdr_unsigned(u_quad_t, *tl++);
2514 }
2515 off = toff;
2516 cnt = fxdr_unsigned(int, *tl);
2517 siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2518 xfer = NFS_SRVMAXDATA(nfsd);
2519 if (siz > xfer)
2520 siz = xfer;
2521 fullsiz = siz;
2522 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2523 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
2524 nfsm_reply(NFSX_UNSIGNED);
2525 nfsm_srvpostop_attr(getret, &at);
2526 return (0);
2527 }
2528 nqsrv_getl(vp, ND_READ);
2529 if (v3) {
2530 error = getret = VOP_GETATTR(vp, &at, cred, procp);
2531 if (!error && toff && verf != at.va_filerev)
2532 error = NFSERR_BAD_COOKIE;
2533 }
2534 if (!error)
2535 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
2536 if (error) {
2537 vput(vp);
2538 nfsm_reply(NFSX_POSTOPATTR(v3));
2539 nfsm_srvpostop_attr(getret, &at);
2540 return (0);
2541 }
2542 VOP_UNLOCK(vp, 0, procp);
2543 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
2544#ifdef __NetBSD__
2545 ncookies = siz / (5 * NFSX_UNSIGNED); /*7 for V3, but it's an est. so*/
2546 MALLOC(cookies, u_long *, ncookies * sizeof (u_long *), M_TEMP,
2547 M_WAITOK);
2548#endif
2549again:
2550 iv.iov_base = rbuf;
2551 iv.iov_len = fullsiz;
2552 io.uio_iov = &iv;
2553 io.uio_iovcnt = 1;
2554 io.uio_offset = (off_t)off;
2555 io.uio_resid = fullsiz;
2556 io.uio_segflg = UIO_SYSSPACE;
2557 io.uio_rw = UIO_READ;
2558 io.uio_procp = (struct proc *)0;
2559 eofflag = 0;
2560 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp);
2561 if (cookies) {
2562 free((caddr_t)cookies, M_TEMP);
2563 cookies = NULL;
2564 }
2565 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
2566 off = (off_t)io.uio_offset;
2567 if (!cookies && !error)
2568 error = NFSERR_PERM;
2569 if (v3) {
2570 getret = VOP_GETATTR(vp, &at, cred, procp);
2571 if (!error)
2572 error = getret;
2573 }
2574 VOP_UNLOCK(vp, 0, procp);
2575 if (error) {
2576 vrele(vp);
2577 free((caddr_t)rbuf, M_TEMP);
2578 if (cookies)
2579 free((caddr_t)cookies, M_TEMP);
2580 nfsm_reply(NFSX_POSTOPATTR(v3));
2581 nfsm_srvpostop_attr(getret, &at);
2582 return (0);
2583 }
2584 if (io.uio_resid) {
2585 siz -= io.uio_resid;
2586
2587 /*
2588 * If nothing read, return eof
2589 * rpc reply
2590 */
2591 if (siz == 0) {
2592 vrele(vp);
2593 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
2594 2 * NFSX_UNSIGNED);
2595 if (v3) {
2596 nfsm_srvpostop_attr(getret, &at);
2597 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
2598 txdr_hyper(&at.va_filerev, tl);
2599 tl += 2;
2600 } else
2601 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2602 *tl++ = nfs_false;
2603 *tl = nfs_true;
2604 FREE((caddr_t)rbuf, M_TEMP);
2605 FREE((caddr_t)cookies, M_TEMP);
2606 return (0);
2607 }
2608 }
2609
2610 /*
2611 * Check for degenerate cases of nothing useful read.
2612 * If so go try again
2613 */
2614 cpos = rbuf;
2615 cend = rbuf + siz;
2616 dp = (struct dirent *)cpos;
2617 cookiep = cookies;
2618#ifdef __FreeBSD__
2619 /*
2620 * For some reason FreeBSD's ufs_readdir() chooses to back the
2621 * directory offset up to a block boundary, so it is necessary to
2622 * skip over the records that preceed the requested offset. This
2623 * requires the assumption that file offset cookies monotonically
2624 * increase.
2625 */
2626 while (cpos < cend && ncookies > 0 &&
2627 (dp->d_fileno == 0 || ((u_quad_t)(*cookiep)) <= toff)) {
2628#else
2629 while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
2630#endif
2631 cpos += dp->d_reclen;
2632 dp = (struct dirent *)cpos;
2633 cookiep++;
2634 ncookies--;
2635 }
2636 if (cpos >= cend || ncookies == 0) {
2637 toff = off;
2638 siz = fullsiz;
2639 goto again;
2640 }
2641
2642 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
2643 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
2644 if (v3) {
2645 nfsm_srvpostop_attr(getret, &at);
2646 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2647 txdr_hyper(&at.va_filerev, tl);
2648 }
2649 mp = mp2 = mb;
2650 bp = bpos;
2651 be = bp + M_TRAILINGSPACE(mp);
2652
2653 /* Loop through the records and build reply */
2654 while (cpos < cend && ncookies > 0) {
2655 if (dp->d_fileno != 0) {
2656 nlen = dp->d_namlen;
2657 rem = nfsm_rndup(nlen)-nlen;
2658 len += (4 * NFSX_UNSIGNED + nlen + rem);
2659 if (v3)
2660 len += 2 * NFSX_UNSIGNED;
2661 if (len > cnt) {
2662 eofflag = 0;
2663 break;
2664 }
2665 /*
2666 * Build the directory record xdr from
2667 * the dirent entry.
2668 */
2669 nfsm_clget;
2670 *tl = nfs_true;
2671 bp += NFSX_UNSIGNED;
2672 if (v3) {
2673 nfsm_clget;
2674 *tl = 0;
2675 bp += NFSX_UNSIGNED;
2676 }
2677 nfsm_clget;
2678 *tl = txdr_unsigned(dp->d_fileno);
2679 bp += NFSX_UNSIGNED;
2680 nfsm_clget;
2681 *tl = txdr_unsigned(nlen);
2682 bp += NFSX_UNSIGNED;
2683
2684 /* And loop around copying the name */
2685 xfer = nlen;
2686 cp = dp->d_name;
2687 while (xfer > 0) {
2688 nfsm_clget;
2689 if ((bp+xfer) > be)
2690 tsiz = be-bp;
2691 else
2692 tsiz = xfer;
2693 bcopy(cp, bp, tsiz);
2694 bp += tsiz;
2695 xfer -= tsiz;
2696 if (xfer > 0)
2697 cp += tsiz;
2698 }
2699 /* And null pad to a long boundary */
2700 for (i = 0; i < rem; i++)
2701 *bp++ = '\0';
2702 nfsm_clget;
2703
2704 /* Finish off the record */
2705 if (v3) {
2706 *tl = 0;
2707 bp += NFSX_UNSIGNED;
2708 nfsm_clget;
2709 }
2710 *tl = txdr_unsigned(*cookiep);
2711 bp += NFSX_UNSIGNED;
2712 }
2713 cpos += dp->d_reclen;
2714 dp = (struct dirent *)cpos;
2715 cookiep++;
2716 ncookies--;
2717 }
2718 vrele(vp);
2719 nfsm_clget;
2720 *tl = nfs_false;
2721 bp += NFSX_UNSIGNED;
2722 nfsm_clget;
2723 if (eofflag)
2724 *tl = nfs_true;
2725 else
2726 *tl = nfs_false;
2727 bp += NFSX_UNSIGNED;
2728 if (mp != mb) {
2729 if (bp < be)
2730 mp->m_len = bp - mtod(mp, caddr_t);
2731 } else
2732 mp->m_len += bp - bpos;
2733 FREE((caddr_t)rbuf, M_TEMP);
2734 FREE((caddr_t)cookies, M_TEMP);
2735 nfsm_srvdone;
2736}
2737
2738int
2739nfsrv_readdirplus(nfsd, slp, procp, mrq)
2740 struct nfsrv_descript *nfsd;
2741 struct nfssvc_sock *slp;
2742 struct proc *procp;
2743 struct mbuf **mrq;
2744{
2745 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2746 struct mbuf *nam = nfsd->nd_nam;
2747 caddr_t dpos = nfsd->nd_dpos;
2748 struct ucred *cred = &nfsd->nd_cr;
2749 register char *bp, *be;
2750 register struct mbuf *mp;
2751 register struct dirent *dp;
2752 register caddr_t cp;
2753 register u_long *tl;
2754 register long t1;
2755 caddr_t bpos;
2756 struct mbuf *mb, *mb2, *mreq, *mp2;
2757 char *cpos, *cend, *cp2, *rbuf;
2758 struct vnode *vp, *nvp;
2759 struct flrep fl;
2760 nfsfh_t nfh;
2761 fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
2762 struct uio io;
2763 struct iovec iv;
2764 struct vattr va, at, *vap = &va;
2765 struct nfs_fattr *fp;
2766 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2767 int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies;
2768 u_quad_t frev, off, toff, verf;
2769 u_long *cookies = NULL, *cookiep;
2770
2771 fhp = &nfh.fh_generic;
2772 nfsm_srvmtofh(fhp);
2773 nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED);
2774 fxdr_hyper(tl, &toff);
2775 tl += 2;
2776 fxdr_hyper(tl, &verf);
2777 tl += 2;
2778 siz = fxdr_unsigned(int, *tl++);
2779 cnt = fxdr_unsigned(int, *tl);
2780 off = toff;
2781 siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2782 xfer = NFS_SRVMAXDATA(nfsd);
2783 if (siz > xfer)
2784 siz = xfer;
2785 fullsiz = siz;
2786 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2787 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
2788 nfsm_reply(NFSX_UNSIGNED);
2789 nfsm_srvpostop_attr(getret, &at);
2790 return (0);
2791 }
2792 error = getret = VOP_GETATTR(vp, &at, cred, procp);
2793 if (!error && toff && verf != at.va_filerev)
2794 error = NFSERR_BAD_COOKIE;
2795 if (!error) {
2796 nqsrv_getl(vp, ND_READ);
2797 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
2798 }
2799 if (error) {
2800 vput(vp);
2801 nfsm_reply(NFSX_V3POSTOPATTR);
2802 nfsm_srvpostop_attr(getret, &at);
2803 return (0);
2804 }
2805 VOP_UNLOCK(vp, 0, procp);
2806 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
2807#ifdef __NetBSD__
2808 ncookies = siz / (7 * NFSX_UNSIGNED);
2809 MALLOC(cookies, u_long *, ncookies * sizeof (u_long *), M_TEMP,
2810 M_WAITOK);
2811#endif
2812again:
2813 iv.iov_base = rbuf;
2814 iv.iov_len = fullsiz;
2815 io.uio_iov = &iv;
2816 io.uio_iovcnt = 1;
2817 io.uio_offset = (off_t)off;
2818 io.uio_resid = fullsiz;
2819 io.uio_segflg = UIO_SYSSPACE;
2820 io.uio_rw = UIO_READ;
2821 io.uio_procp = (struct proc *)0;
2822 eofflag = 0;
2823 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp);
2824 if (cookies) {
2825 free((caddr_t)cookies, M_TEMP);
2826 cookies = NULL;
2827 }
2828 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
2829 off = (u_quad_t)io.uio_offset;
2830 getret = VOP_GETATTR(vp, &at, cred, procp);
2831 VOP_UNLOCK(vp, 0, procp);
2832 if (!cookies && !error)
2833 error = NFSERR_PERM;
2834 if (!error)
2835 error = getret;
2836 if (error) {
2837 vrele(vp);
2838 if (cookies)
2839 free((caddr_t)cookies, M_TEMP);
2840 free((caddr_t)rbuf, M_TEMP);
2841 nfsm_reply(NFSX_V3POSTOPATTR);
2842 nfsm_srvpostop_attr(getret, &at);
2843 return (0);
2844 }
2845 if (io.uio_resid) {
2846 siz -= io.uio_resid;
2847
2848 /*
2849 * If nothing read, return eof
2850 * rpc reply
2851 */
2852 if (siz == 0) {
2853 vrele(vp);
2854 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
2855 2 * NFSX_UNSIGNED);
2856 nfsm_srvpostop_attr(getret, &at);
2857 nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
2858 txdr_hyper(&at.va_filerev, tl);
2859 tl += 2;
2860 *tl++ = nfs_false;
2861 *tl = nfs_true;
2862 FREE((caddr_t)cookies, M_TEMP);
2863 FREE((caddr_t)rbuf, M_TEMP);
2864 return (0);
2865 }
2866 }
2867
2868 /*
2869 * Check for degenerate cases of nothing useful read.
2870 * If so go try again
2871 */
2872 cpos = rbuf;
2873 cend = rbuf + siz;
2874 dp = (struct dirent *)cpos;
2875 cookiep = cookies;
2876#ifdef __FreeBSD__
2877 /*
2878 * For some reason FreeBSD's ufs_readdir() chooses to back the
2879 * directory offset up to a block boundary, so it is necessary to
2880 * skip over the records that preceed the requested offset. This
2881 * requires the assumption that file offset cookies monotonically
2882 * increase.
2883 */
2884 while (cpos < cend && ncookies > 0 &&
2885 (dp->d_fileno == 0 || ((u_quad_t)(*cookiep)) <= toff)) {
2886#else
2887 while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
2888#endif
2889 cpos += dp->d_reclen;
2890 dp = (struct dirent *)cpos;
2891 cookiep++;
2892 ncookies--;
2893 }
2894 if (cpos >= cend || ncookies == 0) {
2895 toff = off;
2896 siz = fullsiz;
2897 goto again;
2898 }
2899
2900 /*
2901 * Probe one of the directory entries to see if the filesystem
2902 * supports VGET.
2903 */
2904 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp) == EOPNOTSUPP) {
2905 error = NFSERR_NOTSUPP;
2906 vrele(vp);
2907 free((caddr_t)cookies, M_TEMP);
2908 free((caddr_t)rbuf, M_TEMP);
2909 nfsm_reply(NFSX_V3POSTOPATTR);
2910 nfsm_srvpostop_attr(getret, &at);
2911 return (0);
2912 }
2913 vput(nvp);
2914
2915 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
2916 nfsm_reply(cnt);
2917 nfsm_srvpostop_attr(getret, &at);
2918 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2919 txdr_hyper(&at.va_filerev, tl);
2920 mp = mp2 = mb;
2921 bp = bpos;
2922 be = bp + M_TRAILINGSPACE(mp);
2923
2924 /* Loop through the records and build reply */
2925 while (cpos < cend && ncookies > 0) {
2926 if (dp->d_fileno != 0) {
2927 nlen = dp->d_namlen;
2928 rem = nfsm_rndup(nlen)-nlen;
2929
2930 /*
2931 * For readdir_and_lookup get the vnode using
2932 * the file number.
2933 */
2934 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
2935 goto invalid;
2936 bzero((caddr_t)nfhp, NFSX_V3FH);
2937 nfhp->fh_fsid =
2938 nvp->v_mount->mnt_stat.f_fsid;
2939 if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
2940 vput(nvp);
2941 goto invalid;
2942 }
2943 if (VOP_GETATTR(nvp, vap, cred, procp)) {
2944 vput(nvp);
2945 goto invalid;
2946 }
2947 vput(nvp);
2948
2949 /*
2950 * If either the dircount or maxcount will be
2951 * exceeded, get out now. Both of these lengths
2952 * are calculated conservatively, including all
2953 * XDR overheads.
2954 */
2955 len += (7 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
2956 NFSX_V3POSTOPATTR);
2957 dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
2958 if (len > cnt || dirlen > fullsiz) {
2959 eofflag = 0;
2960 break;
2961 }
2962
2963 /*
2964 * Build the directory record xdr from
2965 * the dirent entry.
2966 */
2967 fp = (struct nfs_fattr *)&fl.fl_fattr;
2968 nfsm_srvfillattr(vap, fp);
2969 fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
2970 fl.fl_fhok = nfs_true;
2971 fl.fl_postopok = nfs_true;
2972 fl.fl_off.nfsuquad[0] = 0;
2973 fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
2974
2975 nfsm_clget;
2976 *tl = nfs_true;
2977 bp += NFSX_UNSIGNED;
2978 nfsm_clget;
2979 *tl = 0;
2980 bp += NFSX_UNSIGNED;
2981 nfsm_clget;
2982 *tl = txdr_unsigned(dp->d_fileno);
2983 bp += NFSX_UNSIGNED;
2984 nfsm_clget;
2985 *tl = txdr_unsigned(nlen);
2986 bp += NFSX_UNSIGNED;
2987
2988 /* And loop around copying the name */
2989 xfer = nlen;
2990 cp = dp->d_name;
2991 while (xfer > 0) {
2992 nfsm_clget;
2993 if ((bp + xfer) > be)
2994 tsiz = be - bp;
2995 else
2996 tsiz = xfer;
2997 bcopy(cp, bp, tsiz);
2998 bp += tsiz;
2999 xfer -= tsiz;
3000 if (xfer > 0)
3001 cp += tsiz;
3002 }
3003 /* And null pad to a long boundary */
3004 for (i = 0; i < rem; i++)
3005 *bp++ = '\0';
3006
3007 /*
3008 * Now copy the flrep structure out.
3009 */
3010 xfer = sizeof (struct flrep);
3011 cp = (caddr_t)&fl;
3012 while (xfer > 0) {
3013 nfsm_clget;
3014 if ((bp + xfer) > be)
3015 tsiz = be - bp;
3016 else
3017 tsiz = xfer;
3018 bcopy(cp, bp, tsiz);
3019 bp += tsiz;
3020 xfer -= tsiz;
3021 if (xfer > 0)
3022 cp += tsiz;
3023 }
3024 }
3025invalid:
3026 cpos += dp->d_reclen;
3027 dp = (struct dirent *)cpos;
3028 cookiep++;
3029 ncookies--;
3030 }
3031 vrele(vp);
3032 nfsm_clget;
3033 *tl = nfs_false;
3034 bp += NFSX_UNSIGNED;
3035 nfsm_clget;
3036 if (eofflag)
3037 *tl = nfs_true;
3038 else
3039 *tl = nfs_false;
3040 bp += NFSX_UNSIGNED;
3041 if (mp != mb) {
3042 if (bp < be)
3043 mp->m_len = bp - mtod(mp, caddr_t);
3044 } else
3045 mp->m_len += bp - bpos;
3046 FREE((caddr_t)cookies, M_TEMP);
3047 FREE((caddr_t)rbuf, M_TEMP);
3048 nfsm_srvdone;
3049}
3050
3051/*
3052 * nfs commit service
3053 */
3054int
3055nfsrv_commit(nfsd, slp, procp, mrq)
3056 struct nfsrv_descript *nfsd;
3057 struct nfssvc_sock *slp;
3058 struct proc *procp;
3059 struct mbuf **mrq;
3060{
3061 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3062 struct mbuf *nam = nfsd->nd_nam;
3063 caddr_t dpos = nfsd->nd_dpos;
3064 struct ucred *cred = &nfsd->nd_cr;
3065 struct vattr bfor, aft;
3066 struct vnode *vp;
3067 nfsfh_t nfh;
3068 fhandle_t *fhp;
3069 register u_long *tl;
3070 register long t1;
3071 caddr_t bpos;
3072 int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache;
3073 char *cp2;
3074 struct mbuf *mb, *mb2, *mreq;
3075 u_quad_t frev, off;
3076
3077#ifndef nolint
3078 cache = 0;
3079#endif
3080 fhp = &nfh.fh_generic;
3081 nfsm_srvmtofh(fhp);
3082 nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
3083
3084 /*
3085 * XXX At this time VOP_FSYNC() does not accept offset and byte
3086 * count parameters, so these arguments are useless (someday maybe).
3087 */
3088 fxdr_hyper(tl, &off);
3089 tl += 2;
3090 cnt = fxdr_unsigned(int, *tl);
3091 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3092 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3093 nfsm_reply(2 * NFSX_UNSIGNED);
3094 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3095 return (0);
3096 }
3097 for_ret = VOP_GETATTR(vp, &bfor, cred, procp);
3098 error = VOP_FSYNC(vp, cred, MNT_WAIT, procp);
3099 aft_ret = VOP_GETATTR(vp, &aft, cred, procp);
3100 vput(vp);
3101 nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
3102 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3103 if (!error) {
3104 nfsm_build(tl, u_long *, NFSX_V3WRITEVERF);
3105 *tl++ = txdr_unsigned(boottime.tv_sec);
3106 *tl = txdr_unsigned(boottime.tv_usec);
3107 } else
3108 return (0);
3109 nfsm_srvdone;
3110}
3111
3112/*
3113 * nfs statfs service
3114 */
3115int
3116nfsrv_statfs(nfsd, slp, procp, mrq)
3117 struct nfsrv_descript *nfsd;
3118 struct nfssvc_sock *slp;
3119 struct proc *procp;
3120 struct mbuf **mrq;
3121{
3122 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3123 struct mbuf *nam = nfsd->nd_nam;
3124 caddr_t dpos = nfsd->nd_dpos;
3125 struct ucred *cred = &nfsd->nd_cr;
3126 register struct statfs *sf;
3127 register struct nfs_statfs *sfp;
3128 register u_long *tl;
3129 register long t1;
3130 caddr_t bpos;
3131 int error = 0, rdonly, cache, getret = 1;
3132 int v3 = (nfsd->nd_flag & ND_NFSV3);
3133 char *cp2;
3134 struct mbuf *mb, *mb2, *mreq;
3135 struct vnode *vp;
3136 struct vattr at;
3137 nfsfh_t nfh;
3138 fhandle_t *fhp;
3139 struct statfs statfs;
3140 u_quad_t frev, tval;
3141
3142#ifndef nolint
3143 cache = 0;
3144#endif
3145 fhp = &nfh.fh_generic;
3146 nfsm_srvmtofh(fhp);
3147 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3148 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3149 nfsm_reply(NFSX_UNSIGNED);
3150 nfsm_srvpostop_attr(getret, &at);
3151 return (0);
3152 }
3153 sf = &statfs;
3154 error = VFS_STATFS(vp->v_mount, sf, procp);
3155 getret = VOP_GETATTR(vp, &at, cred, procp);
3156 vput(vp);
3157 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
3158 if (v3)
3159 nfsm_srvpostop_attr(getret, &at);
3160 if (error)
3161 return (0);
3162 nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
3163 if (v3) {
3164 tval = (u_quad_t)sf->f_blocks;
3165 tval *= (u_quad_t)sf->f_bsize;
3166 txdr_hyper(&tval, &sfp->sf_tbytes);
3167 tval = (u_quad_t)sf->f_bfree;
3168 tval *= (u_quad_t)sf->f_bsize;
3169 txdr_hyper(&tval, &sfp->sf_fbytes);
3170 tval = (u_quad_t)sf->f_bavail;
3171 tval *= (u_quad_t)sf->f_bsize;
3172 txdr_hyper(&tval, &sfp->sf_abytes);
3173 sfp->sf_tfiles.nfsuquad[0] = 0;
3174 sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
3175 sfp->sf_ffiles.nfsuquad[0] = 0;
3176 sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3177 sfp->sf_afiles.nfsuquad[0] = 0;
3178 sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3179 sfp->sf_invarsec = 0;
3180 } else {
3181 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
3182 sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
3183 sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
3184 sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
3185 sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
3186 }
3187 nfsm_srvdone;
3188}
3189
3190/*
3191 * nfs fsinfo service
3192 */
3193int
3194nfsrv_fsinfo(nfsd, slp, procp, mrq)
3195 struct nfsrv_descript *nfsd;
3196 struct nfssvc_sock *slp;
3197 struct proc *procp;
3198 struct mbuf **mrq;
3199{
3200 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3201 struct mbuf *nam = nfsd->nd_nam;
3202 caddr_t dpos = nfsd->nd_dpos;
3203 struct ucred *cred = &nfsd->nd_cr;
3204 register u_long *tl;
3205 register struct nfsv3_fsinfo *sip;
3206 register long t1;
3207 caddr_t bpos;
3208 int error = 0, rdonly, cache, getret = 1, pref;
3209 char *cp2;
3210 struct mbuf *mb, *mb2, *mreq;
3211 struct vnode *vp;
3212 struct vattr at;
3213 nfsfh_t nfh;
3214 fhandle_t *fhp;
3215 u_quad_t frev;
3216
3217#ifndef nolint
3218 cache = 0;
3219#endif
3220 fhp = &nfh.fh_generic;
3221 nfsm_srvmtofh(fhp);
3222 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3223 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3224 nfsm_reply(NFSX_UNSIGNED);
3225 nfsm_srvpostop_attr(getret, &at);
3226 return (0);
3227 }
3228 getret = VOP_GETATTR(vp, &at, cred, procp);
3229 vput(vp);
3230 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
3231 nfsm_srvpostop_attr(getret, &at);
3232 nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
3233
3234 /*
3235 * XXX
3236 * There should be file system VFS OP(s) to get this information.
3237 * For now, assume ufs.
3238 */
3239 if (slp->ns_so->so_type == SOCK_DGRAM)
3240 pref = NFS_MAXDGRAMDATA;
3241 else
3242 pref = NFS_MAXDATA;
3243 sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
3244 sip->fs_rtpref = txdr_unsigned(pref);
3245 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3246 sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
3247 sip->fs_wtpref = txdr_unsigned(pref);
3248 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3249 sip->fs_dtpref = txdr_unsigned(pref);
3250 sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
3251 sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
3252 sip->fs_timedelta.nfsv3_sec = 0;
3253 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3254 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3255 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3256 NFSV3FSINFO_CANSETTIME);
3257 nfsm_srvdone;
3258}
3259
3260/*
3261 * nfs pathconf service
3262 */
3263int
3264nfsrv_pathconf(nfsd, slp, procp, mrq)
3265 struct nfsrv_descript *nfsd;
3266 struct nfssvc_sock *slp;
3267 struct proc *procp;
3268 struct mbuf **mrq;
3269{
3270 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3271 struct mbuf *nam = nfsd->nd_nam;
3272 caddr_t dpos = nfsd->nd_dpos;
3273 struct ucred *cred = &nfsd->nd_cr;
3274 register u_long *tl;
3275 register struct nfsv3_pathconf *pc;
3276 register long t1;
3277 caddr_t bpos;
3278 int error = 0, rdonly, cache, getret = 1, linkmax, namemax;
3279 int chownres, notrunc;
3280 char *cp2;
3281 struct mbuf *mb, *mb2, *mreq;
3282 struct vnode *vp;
3283 struct vattr at;
3284 nfsfh_t nfh;
3285 fhandle_t *fhp;
3286 u_quad_t frev;
3287
3288#ifndef nolint
3289 cache = 0;
3290#endif
3291 fhp = &nfh.fh_generic;
3292 nfsm_srvmtofh(fhp);
3293 if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3294 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3295 nfsm_reply(NFSX_UNSIGNED);
3296 nfsm_srvpostop_attr(getret, &at);
3297 return (0);
3298 }
3299 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
3300 if (!error)
3301 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
3302 if (!error)
3303 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
3304 if (!error)
3305 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc);
3306 getret = VOP_GETATTR(vp, &at, cred, procp);
3307 vput(vp);
3308 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
3309 nfsm_srvpostop_attr(getret, &at);
3310 if (error)
3311 return (0);
3312 nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
3313
3314 pc->pc_linkmax = txdr_unsigned(linkmax);
3315 pc->pc_namemax = txdr_unsigned(namemax);
3316 pc->pc_notrunc = txdr_unsigned(notrunc);
3317 pc->pc_chownrestricted = txdr_unsigned(chownres);
3318
3319 /*
3320 * These should probably be supported by VOP_PATHCONF(), but
3321 * until msdosfs is exportable (why would you want to?), the
3322 * Unix defaults should be ok.
3323 */
3324 pc->pc_caseinsensitive = nfs_false;
3325 pc->pc_casepreserving = nfs_true;
3326 nfsm_srvdone;
3327}
3328
3329/*
3330 * Null operation, used by clients to ping server
3331 */
3332/* ARGSUSED */
3333int
3334nfsrv_null(nfsd, slp, procp, mrq)
3335 struct nfsrv_descript *nfsd;
3336 struct nfssvc_sock *slp;
3337 struct proc *procp;
3338 struct mbuf **mrq;
3339{
3340 struct mbuf *mrep = nfsd->nd_mrep;
3341 caddr_t bpos;
3342 int error = NFSERR_RETVOID, cache;
3343 struct mbuf *mb, *mreq;
3344 u_quad_t frev;
3345
3346#ifndef nolint
3347 cache = 0;
3348#endif
3349 nfsm_reply(0);
3350 return (0);
3351}
3352
3353/*
3354 * No operation, used for obsolete procedures
3355 */
3356/* ARGSUSED */
3357int
3358nfsrv_noop(nfsd, slp, procp, mrq)
3359 struct nfsrv_descript *nfsd;
3360 struct nfssvc_sock *slp;
3361 struct proc *procp;
3362 struct mbuf **mrq;
3363{
3364 struct mbuf *mrep = nfsd->nd_mrep;
3365 caddr_t bpos;
3366 int error, cache;
3367 struct mbuf *mb, *mreq;
3368 u_quad_t frev;
3369
3370#ifndef nolint
3371 cache = 0;
3372#endif
3373 if (nfsd->nd_repstat)
3374 error = nfsd->nd_repstat;
3375 else
3376 error = EPROCUNAVAIL;
3377 nfsm_reply(0);
3378 return (0);
3379}
3380
3381/*
3382 * Perform access checking for vnodes obtained from file handles that would
3383 * refer to files already opened by a Unix client. You cannot just use
3384 * vn_writechk() and VOP_ACCESS() for two reasons.
3385 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3386 * 2 - The owner is to be given access irrespective of mode bits so that
3387 * processes that chmod after opening a file don't break. I don't like
3388 * this because it opens a security hole, but since the nfs server opens
3389 * a security hole the size of a barn door anyhow, what the heck.
3390 */
3391static int
3392nfsrv_access(vp, flags, cred, rdonly, p)
3393 register struct vnode *vp;
3394 int flags;
3395 register struct ucred *cred;
3396 int rdonly;
3397 struct proc *p;
3398{
3399 struct vattr vattr;
3400 int error;
3401 if (flags & VWRITE) {
3402 /* Just vn_writechk() changed to check rdonly */
3403 /*
3404 * Disallow write attempts on read-only file systems;
3405 * unless the file is a socket or a block or character
3406 * device resident on the file system.
3407 */
3408 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3409 switch (vp->v_type) {
3410 case VREG: case VDIR: case VLNK:
3411 return (EROFS);
3412 }
3413 }
3414 /*
3415 * If there's shared text associated with
3416 * the inode, we can't allow writing.
3417 */
3418 if (vp->v_flag & VTEXT)
3419 return (ETXTBSY);
3420 }
3421 if (error = VOP_GETATTR(vp, &vattr, cred, p))
3422 return (error);
3423 if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
3424 cred->cr_uid != vattr.va_uid)
3425 return (error);
3426 return (0);
3427}
3428#endif /* NFS_NOSERVER */
3429