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