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