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