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