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