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