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