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