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