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