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