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