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