nfs_serv.c revision 1.164 1 /* $NetBSD: nfs_serv.c,v 1.164 2012/08/27 11:35:13 chs 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.164 2012/08/27 11:35:13 chs 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 fromnd.ni_cnd.cn_nameiop = 0;
1935 nfsm_reply(2 * NFSX_WCCDATA(v3));
1936 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1937 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1938 if (fdirp)
1939 vrele(fdirp);
1940 if (fromnd.ni_pathbuf != NULL) {
1941 pathbuf_destroy(fromnd.ni_pathbuf);
1942 }
1943 return (0);
1944 }
1945 if (fromnd.ni_dvp != fromnd.ni_vp) {
1946 VOP_UNLOCK(fromnd.ni_dvp);
1947 }
1948 fvp = fromnd.ni_vp;
1949
1950 localfs = fvp->v_mount;
1951 error = VFS_RENAMELOCK_ENTER(localfs);
1952 if (error) {
1953 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1954 vrele(fromnd.ni_dvp);
1955 vrele(fvp);
1956 goto out1;
1957 }
1958
1959 /* Copied, regrettably, from vfs_syscalls.c (q.v.) */
1960 vrele(fvp);
1961 if ((fromnd.ni_cnd.cn_namelen == 1 &&
1962 fromnd.ni_cnd.cn_nameptr[0] == '.') ||
1963 (fromnd.ni_cnd.cn_namelen == 2 &&
1964 fromnd.ni_cnd.cn_nameptr[0] == '.' &&
1965 fromnd.ni_cnd.cn_nameptr[1] == '.')) {
1966 error = EINVAL;
1967 VFS_RENAMELOCK_EXIT(localfs);
1968 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1969 vrele(fromnd.ni_dvp);
1970 goto out1;
1971 }
1972 vn_lock(fromnd.ni_dvp, LK_EXCLUSIVE | LK_RETRY);
1973 error = relookup(fromnd.ni_dvp, &fromnd.ni_vp, &fromnd.ni_cnd, 0);
1974 if (error) {
1975 VOP_UNLOCK(fromnd.ni_dvp);
1976 VFS_RENAMELOCK_EXIT(localfs);
1977 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1978 vrele(fromnd.ni_dvp);
1979 goto out1;
1980 }
1981 VOP_UNLOCK(fromnd.ni_vp);
1982 if (fromnd.ni_dvp != fromnd.ni_vp)
1983 VOP_UNLOCK(fromnd.ni_dvp);
1984 fvp = fromnd.ni_vp;
1985
1986 nfsm_srvmtofh(&tnsfh);
1987 if (v3) {
1988 nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED);
1989 len2 = fxdr_unsigned(uint32_t, *tl);
1990 /* len2 will be checked by nfs_namei */
1991 }
1992 else {
1993 /* NFSv2 */
1994 nfsm_strsiz(len2, NFS_MAXNAMLEN);
1995 }
1996 kauth_cred_seteuid(cred, saved_uid);
1997 tond.ni_cnd.cn_cred = cred;
1998 tond.ni_cnd.cn_nameiop = RENAME;
1999 tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | INRENAME;
2000 error = nfs_namei(&tond, &tnsfh, len2, slp, nam, &md,
2001 &dpos, &tdirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
2002 if (tdirp && v3) {
2003 tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred);
2004 }
2005 if (error) {
2006 VFS_RENAMELOCK_EXIT(localfs);
2007 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2008 vrele(fromnd.ni_dvp);
2009 vrele(fvp);
2010 goto out1;
2011 }
2012 tdvp = tond.ni_dvp;
2013 tvp = tond.ni_vp;
2014 if (tvp != NULL) {
2015 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2016 if (v3)
2017 error = EEXIST;
2018 else
2019 error = EISDIR;
2020 goto out;
2021 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2022 if (v3)
2023 error = EEXIST;
2024 else
2025 error = ENOTDIR;
2026 goto out;
2027 }
2028 if (tvp->v_type == VDIR && tvp->v_mountedhere) {
2029 if (v3)
2030 error = EXDEV;
2031 else
2032 error = ENOTEMPTY;
2033 goto out;
2034 }
2035 }
2036 if (fvp->v_type == VDIR && fvp->v_mountedhere) {
2037 if (v3)
2038 error = EXDEV;
2039 else
2040 error = ENOTEMPTY;
2041 goto out;
2042 }
2043 if (fvp->v_mount != tdvp->v_mount) {
2044 if (v3)
2045 error = EXDEV;
2046 else
2047 error = ENOTEMPTY;
2048 goto out;
2049 }
2050 if (fvp == tdvp) {
2051 if (v3)
2052 error = EINVAL;
2053 else
2054 error = ENOTEMPTY;
2055 }
2056 /*
2057 * If source is the same as the destination (that is the
2058 * same vnode with the same name in the same directory),
2059 * then there is nothing to do.
2060 */
2061 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
2062 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2063 !memcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2064 fromnd.ni_cnd.cn_namelen))
2065 error = -1;
2066 out:
2067 if (!error) {
2068 nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
2069 nqsrv_getl(tdvp, ND_WRITE);
2070 if (tvp) {
2071 nqsrv_getl(tvp, ND_WRITE);
2072 }
2073 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2074 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2075 VFS_RENAMELOCK_EXIT(localfs);
2076 } else {
2077 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2078 if (tdvp == tvp)
2079 vrele(tdvp);
2080 else
2081 vput(tdvp);
2082 if (tvp)
2083 vput(tvp);
2084 VFS_RENAMELOCK_EXIT(localfs);
2085 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2086 vrele(fromnd.ni_dvp);
2087 vrele(fvp);
2088 if (error == -1)
2089 error = 0;
2090 }
2091 if (tond.ni_pathbuf != NULL) {
2092 pathbuf_destroy(tond.ni_pathbuf);
2093 tond.ni_pathbuf = NULL;
2094 }
2095 tond.ni_cnd.cn_nameiop = 0;
2096 out1:
2097 if (fdirp) {
2098 if (v3) {
2099 vn_lock(fdirp, LK_SHARED | LK_RETRY);
2100 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred);
2101 VOP_UNLOCK(fdirp);
2102 }
2103 vrele(fdirp);
2104 fdirp = NULL;
2105 }
2106 if (tdirp) {
2107 if (v3) {
2108 vn_lock(tdirp, LK_SHARED | LK_RETRY);
2109 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred);
2110 VOP_UNLOCK(tdirp);
2111 }
2112 vrele(tdirp);
2113 tdirp = NULL;
2114 }
2115 pathbuf_destroy(fromnd.ni_pathbuf);
2116 fromnd.ni_pathbuf = NULL;
2117 fromnd.ni_cnd.cn_nameiop = 0;
2118 localfs = NULL;
2119 nfsm_reply(2 * NFSX_WCCDATA(v3));
2120 if (v3) {
2121 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
2122 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
2123 }
2124 return (0);
2125
2126 nfsmout:
2127 if (fdirp)
2128 vrele(fdirp);
2129 #ifdef notdef
2130 if (tdirp)
2131 vrele(tdirp);
2132 #endif
2133 if (tond.ni_cnd.cn_nameiop) {
2134 if (tond.ni_pathbuf != NULL) {
2135 pathbuf_destroy(tond.ni_pathbuf);
2136 tond.ni_pathbuf = NULL;
2137 }
2138 }
2139 if (localfs) {
2140 VFS_RENAMELOCK_EXIT(localfs);
2141 }
2142 if (fromnd.ni_cnd.cn_nameiop) {
2143 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2144 if (fromnd.ni_pathbuf != NULL) {
2145 pathbuf_destroy(fromnd.ni_pathbuf);
2146 fromnd.ni_pathbuf = NULL;
2147 }
2148 vrele(fromnd.ni_dvp);
2149 vrele(fvp);
2150 }
2151 return (error);
2152 }
2153
2154 /*
2155 * nfs link service
2156 */
2157 int
2158 nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
2159 {
2160 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2161 struct mbuf *nam = nfsd->nd_nam;
2162 char *dpos = nfsd->nd_dpos;
2163 kauth_cred_t cred = nfsd->nd_cr;
2164 struct nameidata nd;
2165 u_int32_t *tl;
2166 int32_t t1;
2167 char *bpos;
2168 int error = 0, rdonly, cache = 0, len, dirfor_ret = 1, diraft_ret = 1;
2169 int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
2170 char *cp2;
2171 struct mbuf *mb, *mreq;
2172 struct vnode *vp, *xp, *dirp = (struct vnode *)0;
2173 struct vattr dirfor, diraft, at;
2174 nfsrvfh_t nsfh, dnsfh;
2175 u_quad_t frev;
2176
2177 nfsm_srvmtofh(&nsfh);
2178 nfsm_srvmtofh(&dnsfh);
2179 nfsm_srvnamesiz(len);
2180 error = nfsrv_fhtovp(&nsfh, false, &vp, cred, slp, nam,
2181 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
2182 if (error) {
2183 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2184 nfsm_srvpostop_attr(getret, &at);
2185 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2186 return (0);
2187 }
2188 if (vp->v_type == VDIR) {
2189 error = EPERM;
2190 goto out1;
2191 }
2192 nd.ni_cnd.cn_cred = cred;
2193 nd.ni_cnd.cn_nameiop = CREATE;
2194 nd.ni_cnd.cn_flags = LOCKPARENT;
2195 error = nfs_namei(&nd, &dnsfh, len, slp, nam, &md, &dpos,
2196 &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
2197 if (dirp && v3) {
2198 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred);
2199 }
2200 if (error)
2201 goto out1;
2202 xp = nd.ni_vp;
2203 if (xp != NULL) {
2204 error = EEXIST;
2205 goto out;
2206 }
2207 xp = nd.ni_dvp;
2208 if (vp->v_mount != xp->v_mount)
2209 error = EXDEV;
2210 out:
2211 if (!error) {
2212 nqsrv_getl(vp, ND_WRITE);
2213 nqsrv_getl(xp, ND_WRITE);
2214 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
2215 } else {
2216 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2217 if (nd.ni_dvp == nd.ni_vp)
2218 vrele(nd.ni_dvp);
2219 else
2220 vput(nd.ni_dvp);
2221 if (nd.ni_vp)
2222 vrele(nd.ni_vp);
2223 }
2224 out1:
2225 if (v3) {
2226 vn_lock(vp, LK_SHARED | LK_RETRY);
2227 getret = VOP_GETATTR(vp, &at, cred);
2228 VOP_UNLOCK(vp);
2229 }
2230 if (dirp) {
2231 if (v3) {
2232 vn_lock(dirp, LK_SHARED | LK_RETRY);
2233 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
2234 VOP_UNLOCK(dirp);
2235 }
2236 vrele(dirp);
2237 }
2238 vrele(vp);
2239 if (nd.ni_pathbuf != NULL) {
2240 pathbuf_destroy(nd.ni_pathbuf);
2241 nd.ni_pathbuf = NULL;
2242 }
2243 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2244 if (v3) {
2245 nfsm_srvpostop_attr(getret, &at);
2246 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2247 return (0);
2248 }
2249 nfsm_srvdone;
2250 }
2251
2252 /*
2253 * nfs symbolic link service
2254 */
2255 int
2256 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
2257 {
2258 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2259 struct mbuf *nam = nfsd->nd_nam;
2260 char *dpos = nfsd->nd_dpos;
2261 kauth_cred_t cred = nfsd->nd_cr;
2262 struct vattr va, dirfor, diraft;
2263 struct nameidata nd;
2264 u_int32_t *tl;
2265 int32_t t1;
2266 struct nfsv2_sattr *sp;
2267 char *bpos, *pathcp = NULL, *cp2;
2268 struct uio io;
2269 struct iovec iv;
2270 int error = 0, cache = 0, dirfor_ret = 1, diraft_ret = 1, abort = 0;
2271 uint32_t len, len2;
2272 int v3 = (nfsd->nd_flag & ND_NFSV3);
2273 struct mbuf *mb, *mreq;
2274 struct vnode *dirp = (struct vnode *)0;
2275 nfsrvfh_t nsfh;
2276 u_quad_t frev;
2277
2278 nd.ni_cnd.cn_nameiop = 0;
2279 nfsm_srvmtofh(&nsfh);
2280 nfsm_srvnamesiz(len);
2281 nd.ni_cnd.cn_cred = cred;
2282 nd.ni_cnd.cn_nameiop = CREATE;
2283 nd.ni_cnd.cn_flags = LOCKPARENT;
2284 error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos,
2285 &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
2286 if (dirp && v3) {
2287 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred);
2288 }
2289 if (error)
2290 goto out;
2291 abort = 1;
2292 vattr_null(&va);
2293 va.va_type = VLNK;
2294 if (v3) {
2295 va.va_mode = 0;
2296 nfsm_srvsattr(&va);
2297 nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED);
2298 len2 = fxdr_unsigned(uint32_t, *tl);
2299 if (len2 > PATH_MAX) {
2300 /* XXX should check _PC_NO_TRUNC */
2301 error = ENAMETOOLONG;
2302 goto abortop;
2303 }
2304 }
2305 else {
2306 /* NFSv2 */
2307 nfsm_strsiz(len2, NFS_MAXPATHLEN);
2308 }
2309 pathcp = malloc(len2 + 1, M_TEMP, M_WAITOK);
2310 iv.iov_base = pathcp;
2311 iv.iov_len = len2;
2312 io.uio_resid = len2;
2313 io.uio_offset = 0;
2314 io.uio_iov = &iv;
2315 io.uio_iovcnt = 1;
2316 io.uio_rw = UIO_READ;
2317 UIO_SETUP_SYSSPACE(&io);
2318 nfsm_mtouio(&io, len2);
2319 if (!v3) {
2320 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2321 va.va_mode = fxdr_unsigned(u_int16_t, sp->sa_mode);
2322 }
2323 *(pathcp + len2) = '\0';
2324 if (nd.ni_vp) {
2325 error = EEXIST;
2326 abortop:
2327 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2328 if (nd.ni_dvp == nd.ni_vp)
2329 vrele(nd.ni_dvp);
2330 else
2331 vput(nd.ni_dvp);
2332 if (nd.ni_vp)
2333 vrele(nd.ni_vp);
2334 goto out;
2335 }
2336 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2337 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, pathcp);
2338 if (!error) {
2339 if (v3) {
2340 error = nfsrv_composefh(nd.ni_vp, &nsfh, v3);
2341 if (!error)
2342 error = VOP_GETATTR(nd.ni_vp, &va, cred);
2343 vput(nd.ni_vp);
2344 } else {
2345 vput(nd.ni_vp);
2346 }
2347 }
2348 out:
2349 if (pathcp)
2350 free(pathcp, M_TEMP);
2351 if (dirp) {
2352 if (v3) {
2353 vn_lock(dirp, LK_SHARED | LK_RETRY);
2354 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
2355 VOP_UNLOCK(dirp);
2356 }
2357 vrele(dirp);
2358 dirp = NULL;
2359 }
2360 if (nd.ni_pathbuf != NULL) {
2361 pathbuf_destroy(nd.ni_pathbuf);
2362 nd.ni_pathbuf = NULL;
2363 }
2364 abort = 0;
2365 nfsm_reply(NFSX_SRVFH(&nsfh, v3) + NFSX_POSTOPATTR(v3) +
2366 NFSX_WCCDATA(v3));
2367 if (v3) {
2368 if (!error) {
2369 nfsm_srvpostop_fh(&nsfh);
2370 nfsm_srvpostop_attr(0, &va);
2371 }
2372 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2373 }
2374 return (0);
2375 nfsmout:
2376 if (abort) {
2377 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2378 if (nd.ni_dvp == nd.ni_vp)
2379 vrele(nd.ni_dvp);
2380 else
2381 vput(nd.ni_dvp);
2382 if (nd.ni_vp)
2383 vrele(nd.ni_vp);
2384 if (nd.ni_pathbuf != NULL) {
2385 pathbuf_destroy(nd.ni_pathbuf);
2386 nd.ni_pathbuf = NULL;
2387 }
2388 }
2389 if (dirp)
2390 vrele(dirp);
2391 if (pathcp)
2392 free(pathcp, M_TEMP);
2393 return (error);
2394 }
2395
2396 /*
2397 * nfs mkdir service
2398 */
2399 int
2400 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
2401 {
2402 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2403 struct mbuf *nam = nfsd->nd_nam;
2404 char *dpos = nfsd->nd_dpos;
2405 kauth_cred_t cred = nfsd->nd_cr;
2406 struct vattr va, dirfor, diraft;
2407 struct nfs_fattr *fp;
2408 struct nameidata nd;
2409 char *cp;
2410 u_int32_t *tl;
2411 int32_t t1;
2412 char *bpos;
2413 int error = 0, cache = 0, len, dirfor_ret = 1, diraft_ret = 1;
2414 int abort = 0;
2415 int v3 = (nfsd->nd_flag & ND_NFSV3);
2416 char *cp2;
2417 struct mbuf *mb, *mreq;
2418 struct vnode *vp, *dirp = (struct vnode *)0;
2419 nfsrvfh_t nsfh;
2420 u_quad_t frev;
2421
2422 nfsm_srvmtofh(&nsfh);
2423 nfsm_srvnamesiz(len);
2424 nd.ni_cnd.cn_cred = cred;
2425 nd.ni_cnd.cn_nameiop = CREATE;
2426 nd.ni_cnd.cn_flags = LOCKPARENT;
2427 error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos,
2428 &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
2429 if (dirp && v3) {
2430 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred);
2431 }
2432 if (error) {
2433 if (nd.ni_pathbuf != NULL) {
2434 pathbuf_destroy(nd.ni_pathbuf);
2435 nd.ni_pathbuf = NULL;
2436 }
2437 nfsm_reply(NFSX_WCCDATA(v3));
2438 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2439 if (dirp)
2440 vrele(dirp);
2441 return (0);
2442 }
2443 abort = 1;
2444 vattr_null(&va);
2445 if (v3) {
2446 va.va_mode = 0;
2447 nfsm_srvsattr(&va);
2448 } else {
2449 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
2450 va.va_mode = nfstov_mode(*tl++);
2451 }
2452 va.va_type = VDIR;
2453 vp = nd.ni_vp;
2454 if (vp != NULL) {
2455 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2456 if (nd.ni_dvp == vp)
2457 vrele(nd.ni_dvp);
2458 else
2459 vput(nd.ni_dvp);
2460 vrele(vp);
2461 error = EEXIST;
2462 goto out;
2463 }
2464 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2465 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
2466 if (!error) {
2467 vp = nd.ni_vp;
2468 error = nfsrv_composefh(vp, &nsfh, v3);
2469 if (!error)
2470 error = VOP_GETATTR(vp, &va, cred);
2471 vput(vp);
2472 }
2473 out:
2474 if (dirp) {
2475 if (v3) {
2476 vn_lock(dirp, LK_SHARED | LK_RETRY);
2477 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
2478 VOP_UNLOCK(dirp);
2479 }
2480 vrele(dirp);
2481 dirp = NULL;
2482 }
2483 if (nd.ni_pathbuf != NULL) {
2484 pathbuf_destroy(nd.ni_pathbuf);
2485 nd.ni_pathbuf = NULL;
2486 }
2487 abort = 0;
2488 nfsm_reply(NFSX_SRVFH(&nsfh, v3) + NFSX_POSTOPATTR(v3) +
2489 NFSX_WCCDATA(v3));
2490 if (v3) {
2491 if (!error) {
2492 nfsm_srvpostop_fh(&nsfh);
2493 nfsm_srvpostop_attr(0, &va);
2494 }
2495 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2496 } else {
2497 nfsm_srvfhtom(&nsfh, v3);
2498 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
2499 nfsm_srvfillattr(&va, fp);
2500 }
2501 return (0);
2502 nfsmout:
2503 if (abort) {
2504 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2505 if (nd.ni_dvp == nd.ni_vp)
2506 vrele(nd.ni_dvp);
2507 else
2508 vput(nd.ni_dvp);
2509 if (nd.ni_vp)
2510 vrele(nd.ni_vp);
2511 if (nd.ni_pathbuf != NULL) {
2512 pathbuf_destroy(nd.ni_pathbuf);
2513 nd.ni_pathbuf = NULL;
2514 }
2515 }
2516 if (dirp)
2517 vrele(dirp);
2518 return (error);
2519 }
2520
2521 /*
2522 * nfs rmdir service
2523 */
2524 int
2525 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
2526 {
2527 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2528 struct mbuf *nam = nfsd->nd_nam;
2529 char *dpos = nfsd->nd_dpos;
2530 kauth_cred_t cred = nfsd->nd_cr;
2531 u_int32_t *tl;
2532 int32_t t1;
2533 char *bpos;
2534 int error = 0, cache = 0, len, dirfor_ret = 1, diraft_ret = 1;
2535 int v3 = (nfsd->nd_flag & ND_NFSV3);
2536 char *cp2;
2537 struct mbuf *mb, *mreq;
2538 struct vnode *vp, *dirp = (struct vnode *)0;
2539 struct vattr dirfor, diraft;
2540 nfsrvfh_t nsfh;
2541 struct nameidata nd;
2542 u_quad_t frev;
2543
2544 nfsm_srvmtofh(&nsfh);
2545 nfsm_srvnamesiz(len);
2546 nd.ni_cnd.cn_cred = cred;
2547 nd.ni_cnd.cn_nameiop = DELETE;
2548 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2549 error = nfs_namei(&nd, &nsfh, len, slp, nam, &md, &dpos,
2550 &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), false);
2551 if (dirp && v3) {
2552 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred);
2553 }
2554 if (error) {
2555 if (nd.ni_pathbuf != NULL) {
2556 pathbuf_destroy(nd.ni_pathbuf);
2557 nd.ni_pathbuf = NULL;
2558 }
2559 nfsm_reply(NFSX_WCCDATA(v3));
2560 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2561 if (dirp)
2562 vrele(dirp);
2563 return (0);
2564 }
2565 vp = nd.ni_vp;
2566 if (vp->v_type != VDIR) {
2567 error = ENOTDIR;
2568 goto out;
2569 }
2570 /*
2571 * No rmdir "." please.
2572 */
2573 if (nd.ni_dvp == vp) {
2574 error = EINVAL;
2575 goto out;
2576 }
2577 /*
2578 * The root of a mounted filesystem cannot be deleted.
2579 */
2580 if (vp->v_vflag & VV_ROOT)
2581 error = EBUSY;
2582 out:
2583 if (!error) {
2584 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2585 nqsrv_getl(vp, ND_WRITE);
2586 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2587 } else {
2588 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2589 if (nd.ni_dvp == nd.ni_vp)
2590 vrele(nd.ni_dvp);
2591 else
2592 vput(nd.ni_dvp);
2593 vput(vp);
2594 }
2595 if (nd.ni_pathbuf != NULL) {
2596 pathbuf_destroy(nd.ni_pathbuf);
2597 nd.ni_pathbuf = NULL;
2598 }
2599 if (dirp) {
2600 if (v3) {
2601 vn_lock(dirp, LK_SHARED | LK_RETRY);
2602 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
2603 VOP_UNLOCK(dirp);
2604 }
2605 vrele(dirp);
2606 }
2607 nfsm_reply(NFSX_WCCDATA(v3));
2608 if (v3) {
2609 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2610 return (0);
2611 }
2612 nfsm_srvdone;
2613 }
2614
2615 /*
2616 * nfs readdir service
2617 * - mallocs what it thinks is enough to read
2618 * count rounded up to a multiple of NFS_SRVDIRBLKSIZ <= NFS_MAXREADDIR
2619 * - calls VOP_READDIR()
2620 * - loops around building the reply
2621 * if the output generated exceeds count break out of loop
2622 * The nfsm_clget macro is used here so that the reply will be packed
2623 * tightly in mbuf clusters.
2624 * - it only knows that it has encountered eof when the VOP_READDIR()
2625 * reads nothing
2626 * - as such one readdir rpc will return eof false although you are there
2627 * and then the next will return eof
2628 * - it trims out records with d_fileno == 0
2629 * this doesn't matter for Unix clients, but they might confuse clients
2630 * for other os'.
2631 * - it trims out records with d_type == DT_WHT
2632 * these cannot be seen through NFS (unless we extend the protocol)
2633 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2634 * than requested, but this may not apply to all filesystems. For
2635 * example, client NFS does not { although it is never remote mounted
2636 * anyhow }
2637 * The alternate call nfsrv_readdirplus() does lookups as well.
2638 * PS: The NFS protocol spec. does not clarify what the "count" byte
2639 * argument is a count of.. just name strings and file id's or the
2640 * entire reply rpc or ...
2641 * I tried just file name and id sizes and it confused the Sun client,
2642 * so I am using the full rpc size now. The "paranoia.." comment refers
2643 * to including the status longwords that are not a part of the dir.
2644 * "entry" structures, but are in the rpc.
2645 */
2646
2647 #define NFS_SRVDIRBLKSIZ 1024
2648
2649 struct flrep {
2650 nfsuint64 fl_off;
2651 u_int32_t fl_postopok;
2652 struct nfs_fattr fl_fattr; /* XXX: must be of fattr3 size */
2653 u_int32_t fl_fhok;
2654 u_int32_t fl_fhsize;
2655 /* handle comes here, filled in dynamically */
2656 };
2657
2658 int
2659 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
2660 {
2661 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2662 struct mbuf *nam = nfsd->nd_nam;
2663 char *dpos = nfsd->nd_dpos;
2664 kauth_cred_t cred = nfsd->nd_cr;
2665 char *bp, *be;
2666 struct mbuf *mp;
2667 struct dirent *dp;
2668 char *cp;
2669 u_int32_t *tl;
2670 int32_t t1;
2671 char *bpos;
2672 struct mbuf *mb, *mreq, *mp2;
2673 char *cpos, *cend, *cp2, *rbuf;
2674 struct vnode *vp;
2675 struct vattr at;
2676 nfsrvfh_t nsfh;
2677 struct uio io;
2678 struct iovec iv;
2679 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2680 int siz, cnt, fullsiz, eofflag, rdonly, cache = 0, ncookies;
2681 int v3 = (nfsd->nd_flag & ND_NFSV3);
2682 u_quad_t frev, off, toff, verf;
2683 off_t *cookies = NULL, *cookiep;
2684 nfsuint64 jar;
2685
2686 nfsm_srvmtofh(&nsfh);
2687 if (v3) {
2688 nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2689 toff = fxdr_hyper(tl);
2690 tl += 2;
2691 verf = fxdr_hyper(tl);
2692 tl += 2;
2693 } else {
2694 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2695 toff = fxdr_unsigned(u_quad_t, *tl++);
2696 }
2697 off = toff;
2698 cnt = fxdr_unsigned(int, *tl);
2699 siz = ((cnt + NFS_SRVDIRBLKSIZ - 1) & ~(NFS_SRVDIRBLKSIZ - 1));
2700 xfer = NFS_SRVMAXDATA(nfsd);
2701 if (siz > xfer)
2702 siz = xfer;
2703 fullsiz = siz;
2704 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
2705 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
2706 if (!error && vp->v_type != VDIR) {
2707 error = ENOTDIR;
2708 vput(vp);
2709 }
2710 if (error) {
2711 nfsm_reply(NFSX_UNSIGNED);
2712 nfsm_srvpostop_attr(getret, &at);
2713 return (0);
2714 }
2715 nqsrv_getl(vp, ND_READ);
2716 if (v3) {
2717 error = getret = VOP_GETATTR(vp, &at, cred);
2718 #ifdef NFS3_STRICTVERF
2719 /*
2720 * XXX This check is too strict for Solaris 2.5 clients.
2721 */
2722 if (!error && toff && verf != at.va_filerev)
2723 error = NFSERR_BAD_COOKIE;
2724 #endif
2725 }
2726 if (!error)
2727 error = nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0);
2728 if (error) {
2729 vput(vp);
2730 nfsm_reply(NFSX_POSTOPATTR(v3));
2731 nfsm_srvpostop_attr(getret, &at);
2732 return (0);
2733 }
2734 VOP_UNLOCK(vp);
2735 rbuf = malloc(siz, M_TEMP, M_WAITOK);
2736 again:
2737 iv.iov_base = rbuf;
2738 iv.iov_len = fullsiz;
2739 io.uio_iov = &iv;
2740 io.uio_iovcnt = 1;
2741 io.uio_offset = (off_t)off;
2742 io.uio_resid = fullsiz;
2743 io.uio_rw = UIO_READ;
2744 UIO_SETUP_SYSSPACE(&io);
2745 eofflag = 0;
2746 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2747
2748 error = VOP_READDIR(vp, &io, cred, &eofflag, &cookies, &ncookies);
2749
2750 off = (off_t)io.uio_offset;
2751 if (!cookies && !error)
2752 error = NFSERR_PERM;
2753 if (v3) {
2754 getret = VOP_GETATTR(vp, &at, cred);
2755 if (!error)
2756 error = getret;
2757 }
2758
2759 VOP_UNLOCK(vp);
2760 if (error) {
2761 vrele(vp);
2762 free((void *)rbuf, M_TEMP);
2763 if (cookies)
2764 free((void *)cookies, M_TEMP);
2765 nfsm_reply(NFSX_POSTOPATTR(v3));
2766 nfsm_srvpostop_attr(getret, &at);
2767 return (0);
2768 }
2769 if (io.uio_resid) {
2770 siz -= io.uio_resid;
2771
2772 /*
2773 * If nothing read, return eof
2774 * rpc reply
2775 */
2776 if (siz == 0) {
2777 vrele(vp);
2778 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
2779 2 * NFSX_UNSIGNED);
2780 if (v3) {
2781 nfsm_srvpostop_attr(getret, &at);
2782 nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2783 txdr_hyper(at.va_filerev, tl);
2784 tl += 2;
2785 } else
2786 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2787 *tl++ = nfs_false;
2788 *tl = nfs_true;
2789 free((void *)rbuf, M_TEMP);
2790 free((void *)cookies, M_TEMP);
2791 return (0);
2792 }
2793 }
2794
2795 /*
2796 * Check for degenerate cases of nothing useful read.
2797 * If so go try again
2798 */
2799 cpos = rbuf;
2800 cend = rbuf + siz;
2801 dp = (struct dirent *)cpos;
2802 cookiep = cookies;
2803
2804 while (cpos < cend && ncookies > 0 &&
2805 (dp->d_fileno == 0 || dp->d_type == DT_WHT)) {
2806 cpos += dp->d_reclen;
2807 dp = (struct dirent *)cpos;
2808 cookiep++;
2809 ncookies--;
2810 }
2811 if (cpos >= cend || ncookies == 0) {
2812 toff = off;
2813 siz = fullsiz;
2814 free(cookies, M_TEMP);
2815 cookies = NULL;
2816 goto again;
2817 }
2818
2819 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
2820 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
2821 if (v3) {
2822 nfsm_srvpostop_attr(getret, &at);
2823 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2824 txdr_hyper(at.va_filerev, tl);
2825 }
2826 mp = mp2 = mb;
2827 bp = bpos;
2828 be = bp + M_TRAILINGSPACE(mp);
2829
2830 /* Loop through the records and build reply */
2831 while (cpos < cend && ncookies > 0) {
2832 if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
2833 nlen = dp->d_namlen;
2834 rem = nfsm_rndup(nlen)-nlen;
2835 len += (4 * NFSX_UNSIGNED + nlen + rem);
2836 if (v3)
2837 len += 2 * NFSX_UNSIGNED;
2838 if (len > cnt) {
2839 eofflag = 0;
2840 break;
2841 }
2842 /*
2843 * Build the directory record xdr from
2844 * the dirent entry.
2845 */
2846 nfsm_clget;
2847 *tl = nfs_true;
2848 bp += NFSX_UNSIGNED;
2849 if (v3) {
2850 nfsm_clget;
2851 *tl = txdr_unsigned(dp->d_fileno >> 32);
2852 bp += NFSX_UNSIGNED;
2853 }
2854 nfsm_clget;
2855 *tl = txdr_unsigned(dp->d_fileno);
2856 bp += NFSX_UNSIGNED;
2857 nfsm_clget;
2858 *tl = txdr_unsigned(nlen);
2859 bp += NFSX_UNSIGNED;
2860
2861 /* And loop around copying the name */
2862 xfer = nlen;
2863 cp = dp->d_name;
2864 while (xfer > 0) {
2865 nfsm_clget;
2866 if ((bp+xfer) > be)
2867 tsiz = be-bp;
2868 else
2869 tsiz = xfer;
2870 memcpy(bp, cp, tsiz);
2871 bp += tsiz;
2872 xfer -= tsiz;
2873 if (xfer > 0)
2874 cp += tsiz;
2875 }
2876 /* And null pad to an int32_t boundary */
2877 for (i = 0; i < rem; i++)
2878 *bp++ = '\0';
2879 nfsm_clget;
2880
2881 /* Finish off the record */
2882 txdr_hyper(*cookiep, &jar);
2883 if (v3) {
2884 *tl = jar.nfsuquad[0];
2885 bp += NFSX_UNSIGNED;
2886 nfsm_clget;
2887 }
2888 *tl = jar.nfsuquad[1];
2889 bp += NFSX_UNSIGNED;
2890 }
2891 cpos += dp->d_reclen;
2892 dp = (struct dirent *)cpos;
2893 cookiep++;
2894 ncookies--;
2895 }
2896 vrele(vp);
2897 nfsm_clget;
2898 *tl = nfs_false;
2899 bp += NFSX_UNSIGNED;
2900 nfsm_clget;
2901 if (eofflag)
2902 *tl = nfs_true;
2903 else
2904 *tl = nfs_false;
2905 bp += NFSX_UNSIGNED;
2906 if (mp != mb) {
2907 if (bp < be)
2908 mp->m_len = bp - mtod(mp, char *);
2909 } else
2910 mp->m_len += bp - bpos;
2911 free((void *)rbuf, M_TEMP);
2912 free((void *)cookies, M_TEMP);
2913 nfsm_srvdone;
2914 }
2915
2916 int
2917 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
2918 {
2919 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2920 struct mbuf *nam = nfsd->nd_nam;
2921 char *dpos = nfsd->nd_dpos;
2922 kauth_cred_t cred = nfsd->nd_cr;
2923 char *bp, *be;
2924 struct mbuf *mp;
2925 struct dirent *dp;
2926 char *cp;
2927 u_int32_t *tl;
2928 int32_t t1;
2929 char *bpos;
2930 struct mbuf *mb, *mreq, *mp2;
2931 char *cpos, *cend, *cp2, *rbuf;
2932 struct vnode *vp, *nvp;
2933 struct flrep fl;
2934 nfsrvfh_t nsfh;
2935 struct uio io;
2936 struct iovec iv;
2937 struct vattr va, at, *vap = &va;
2938 struct nfs_fattr *fp;
2939 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2940 int siz, cnt, fullsiz, eofflag, rdonly, cache = 0, dirlen, ncookies;
2941 u_quad_t frev, off, toff, verf;
2942 off_t *cookies = NULL, *cookiep;
2943
2944 nfsm_srvmtofh(&nsfh);
2945 nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2946 toff = fxdr_hyper(tl);
2947 tl += 2;
2948 verf = fxdr_hyper(tl);
2949 tl += 2;
2950 siz = fxdr_unsigned(int, *tl++);
2951 cnt = fxdr_unsigned(int, *tl);
2952 off = toff;
2953 siz = ((siz + NFS_SRVDIRBLKSIZ - 1) & ~(NFS_SRVDIRBLKSIZ - 1));
2954 xfer = NFS_SRVMAXDATA(nfsd);
2955 if (siz > xfer)
2956 siz = xfer;
2957 fullsiz = siz;
2958 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
2959 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
2960 if (!error && vp->v_type != VDIR) {
2961 error = ENOTDIR;
2962 vput(vp);
2963 }
2964 if (error) {
2965 nfsm_reply(NFSX_UNSIGNED);
2966 nfsm_srvpostop_attr(getret, &at);
2967 return (0);
2968 }
2969 error = getret = VOP_GETATTR(vp, &at, cred);
2970 #ifdef NFS3_STRICTVERF
2971 /*
2972 * XXX This check is too strict for Solaris 2.5 clients.
2973 */
2974 if (!error && toff && verf != at.va_filerev)
2975 error = NFSERR_BAD_COOKIE;
2976 #endif
2977 if (!error) {
2978 nqsrv_getl(vp, ND_READ);
2979 error = nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0);
2980 }
2981 if (error) {
2982 vput(vp);
2983 nfsm_reply(NFSX_V3POSTOPATTR);
2984 nfsm_srvpostop_attr(getret, &at);
2985 return (0);
2986 }
2987 VOP_UNLOCK(vp);
2988
2989 rbuf = malloc(siz, M_TEMP, M_WAITOK);
2990 again:
2991 iv.iov_base = rbuf;
2992 iv.iov_len = fullsiz;
2993 io.uio_iov = &iv;
2994 io.uio_iovcnt = 1;
2995 io.uio_offset = (off_t)off;
2996 io.uio_resid = fullsiz;
2997 io.uio_rw = UIO_READ;
2998 UIO_SETUP_SYSSPACE(&io);
2999 eofflag = 0;
3000
3001 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
3002
3003 error = VOP_READDIR(vp, &io, cred, &eofflag, &cookies, &ncookies);
3004
3005 off = (u_quad_t)io.uio_offset;
3006 getret = VOP_GETATTR(vp, &at, cred);
3007
3008 VOP_UNLOCK(vp);
3009
3010 /*
3011 * If the VGET operation doesn't work for this filesystem,
3012 * we can't support readdirplus. Returning NOTSUPP should
3013 * make clients fall back to plain readdir.
3014 * There's no need to check for VPTOFH as well, we wouldn't
3015 * even be here otherwise.
3016 */
3017 if (!getret) {
3018 if ((getret = VFS_VGET(vp->v_mount, at.va_fileid, &nvp)))
3019 getret = (getret == EOPNOTSUPP) ?
3020 NFSERR_NOTSUPP : NFSERR_IO;
3021 else
3022 vput(nvp);
3023 }
3024
3025 if (!cookies && !error)
3026 error = NFSERR_PERM;
3027 if (!error)
3028 error = getret;
3029 if (error) {
3030 vrele(vp);
3031 if (cookies)
3032 free((void *)cookies, M_TEMP);
3033 free((void *)rbuf, M_TEMP);
3034 nfsm_reply(NFSX_V3POSTOPATTR);
3035 nfsm_srvpostop_attr(getret, &at);
3036 return (0);
3037 }
3038 if (io.uio_resid) {
3039 siz -= io.uio_resid;
3040
3041 /*
3042 * If nothing read, return eof
3043 * rpc reply
3044 */
3045 if (siz == 0) {
3046 vrele(vp);
3047 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
3048 2 * NFSX_UNSIGNED);
3049 nfsm_srvpostop_attr(getret, &at);
3050 nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
3051 txdr_hyper(at.va_filerev, tl);
3052 tl += 2;
3053 *tl++ = nfs_false;
3054 *tl = nfs_true;
3055 free((void *)cookies, M_TEMP);
3056 free((void *)rbuf, M_TEMP);
3057 return (0);
3058 }
3059 }
3060
3061 /*
3062 * Check for degenerate cases of nothing useful read.
3063 * If so go try again
3064 */
3065 cpos = rbuf;
3066 cend = rbuf + siz;
3067 dp = (struct dirent *)cpos;
3068 cookiep = cookies;
3069
3070 while (cpos < cend && ncookies > 0 &&
3071 (dp->d_fileno == 0 || dp->d_type == DT_WHT)) {
3072 cpos += dp->d_reclen;
3073 dp = (struct dirent *)cpos;
3074 cookiep++;
3075 ncookies--;
3076 }
3077 if (cpos >= cend || ncookies == 0) {
3078 toff = off;
3079 siz = fullsiz;
3080 free(cookies, M_TEMP);
3081 cookies = NULL;
3082 goto again;
3083 }
3084
3085 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
3086 nfsm_reply(cnt);
3087 nfsm_srvpostop_attr(getret, &at);
3088 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3089 txdr_hyper(at.va_filerev, tl);
3090 mp = mp2 = mb;
3091 bp = bpos;
3092 be = bp + M_TRAILINGSPACE(mp);
3093
3094 /* Loop through the records and build reply */
3095 while (cpos < cend && ncookies > 0) {
3096 if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
3097 nfsrvfh_t nnsfh;
3098
3099 nlen = dp->d_namlen;
3100 rem = nfsm_rndup(nlen)-nlen;
3101
3102 /*
3103 * For readdir_and_lookup get the vnode using
3104 * the file number.
3105 */
3106 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
3107 goto invalid;
3108 if (nfsrv_composefh(nvp, &nnsfh, true)) {
3109 vput(nvp);
3110 goto invalid;
3111 }
3112 if (VOP_GETATTR(nvp, vap, cred)) {
3113 vput(nvp);
3114 goto invalid;
3115 }
3116 vput(nvp);
3117
3118 /*
3119 * If either the dircount or maxcount will be
3120 * exceeded, get out now. Both of these lengths
3121 * are calculated conservatively, including all
3122 * XDR overheads.
3123 */
3124 len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
3125 NFSX_V3POSTOPATTR);
3126 dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
3127 if (len > cnt || dirlen > fullsiz) {
3128 eofflag = 0;
3129 break;
3130 }
3131
3132 /*
3133 * Build the directory record xdr from
3134 * the dirent entry.
3135 */
3136 fp = (struct nfs_fattr *)&fl.fl_fattr;
3137 nfsm_srvfillattr(vap, fp);
3138 fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
3139 fl.fl_fhok = nfs_true;
3140 fl.fl_postopok = nfs_true;
3141 txdr_hyper(*cookiep, fl.fl_off.nfsuquad);
3142
3143 nfsm_clget;
3144 *tl = nfs_true;
3145 bp += NFSX_UNSIGNED;
3146 nfsm_clget;
3147 *tl = txdr_unsigned(dp->d_fileno >> 32);
3148 bp += NFSX_UNSIGNED;
3149 nfsm_clget;
3150 *tl = txdr_unsigned(dp->d_fileno);
3151 bp += NFSX_UNSIGNED;
3152 nfsm_clget;
3153 *tl = txdr_unsigned(nlen);
3154 bp += NFSX_UNSIGNED;
3155
3156 /* And loop around copying the name */
3157 xfer = nlen;
3158 cp = dp->d_name;
3159 while (xfer > 0) {
3160 nfsm_clget;
3161 if ((bp + xfer) > be)
3162 tsiz = be - bp;
3163 else
3164 tsiz = xfer;
3165 memcpy(bp, cp, tsiz);
3166 bp += tsiz;
3167 xfer -= tsiz;
3168 if (xfer > 0)
3169 cp += tsiz;
3170 }
3171 /* And null pad to an int32_t boundary */
3172 for (i = 0; i < rem; i++)
3173 *bp++ = '\0';
3174
3175 /*
3176 * Now copy the flrep structure out.
3177 */
3178 xfer = sizeof(struct flrep);
3179 cp = (void *)&fl;
3180 while (xfer > 0) {
3181 nfsm_clget;
3182 if ((bp + xfer) > be)
3183 tsiz = be - bp;
3184 else
3185 tsiz = xfer;
3186 memcpy(bp, cp, tsiz);
3187 bp += tsiz;
3188 xfer -= tsiz;
3189 if (xfer > 0)
3190 cp += tsiz;
3191 }
3192
3193 /*
3194 * ... and filehandle.
3195 */
3196 xfer = NFSRVFH_SIZE(&nnsfh);
3197 cp = NFSRVFH_DATA(&nnsfh);
3198 while (xfer > 0) {
3199 nfsm_clget;
3200 if ((bp + xfer) > be)
3201 tsiz = be - bp;
3202 else
3203 tsiz = xfer;
3204 memcpy(bp, cp, tsiz);
3205 bp += tsiz;
3206 xfer -= tsiz;
3207 if (xfer > 0)
3208 cp += tsiz;
3209 }
3210 }
3211 invalid:
3212 cpos += dp->d_reclen;
3213 dp = (struct dirent *)cpos;
3214 cookiep++;
3215 ncookies--;
3216 }
3217 vrele(vp);
3218 nfsm_clget;
3219 *tl = nfs_false;
3220 bp += NFSX_UNSIGNED;
3221 nfsm_clget;
3222 if (eofflag)
3223 *tl = nfs_true;
3224 else
3225 *tl = nfs_false;
3226 bp += NFSX_UNSIGNED;
3227 if (mp != mb) {
3228 if (bp < be)
3229 mp->m_len = bp - mtod(mp, char *);
3230 } else
3231 mp->m_len += bp - bpos;
3232 free((void *)cookies, M_TEMP);
3233 free((void *)rbuf, M_TEMP);
3234 nfsm_srvdone;
3235 }
3236
3237 /*
3238 * nfs commit service
3239 */
3240 int
3241 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
3242 {
3243 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3244 struct mbuf *nam = nfsd->nd_nam;
3245 char *dpos = nfsd->nd_dpos;
3246 kauth_cred_t cred = nfsd->nd_cr;
3247 struct vattr bfor, aft;
3248 struct vnode *vp;
3249 nfsrvfh_t nsfh;
3250 u_int32_t *tl;
3251 int32_t t1;
3252 char *bpos;
3253 int error = 0, rdonly, for_ret = 1, aft_ret = 1, cache = 0;
3254 uint32_t cnt;
3255 char *cp2;
3256 struct mbuf *mb, *mreq;
3257 u_quad_t frev, off, end;
3258
3259 nfsm_srvmtofh(&nsfh);
3260 nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3261
3262 off = fxdr_hyper(tl);
3263 tl += 2;
3264 cnt = fxdr_unsigned(uint32_t, *tl);
3265 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
3266 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
3267 if (error) {
3268 nfsm_reply(2 * NFSX_UNSIGNED);
3269 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3270 return (0);
3271 }
3272 for_ret = VOP_GETATTR(vp, &bfor, cred);
3273 end = (cnt > 0) ? off + cnt : vp->v_size;
3274 if (end < off || end > vp->v_size)
3275 end = vp->v_size;
3276 if (off < vp->v_size)
3277 error = VOP_FSYNC(vp, cred, FSYNC_WAIT, off, end);
3278 /* else error == 0, from nfsrv_fhtovp() */
3279 aft_ret = VOP_GETATTR(vp, &aft, cred);
3280 vput(vp);
3281 nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
3282 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3283 if (!error) {
3284 nfsm_build(tl, u_int32_t *, NFSX_V3WRITEVERF);
3285 *tl++ = txdr_unsigned(boottime.tv_sec);
3286 *tl = txdr_unsigned(boottime.tv_nsec / 1000);
3287 } else {
3288 return (0);
3289 }
3290 nfsm_srvdone;
3291 }
3292
3293 /*
3294 * nfs statfs service
3295 */
3296 int
3297 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
3298 {
3299 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3300 struct mbuf *nam = nfsd->nd_nam;
3301 char *dpos = nfsd->nd_dpos;
3302 kauth_cred_t cred = nfsd->nd_cr;
3303 struct statvfs *sf = NULL;
3304 struct nfs_statfs *sfp;
3305 u_int32_t *tl;
3306 int32_t t1;
3307 char *bpos;
3308 int error = 0, rdonly, cache = 0, getret = 1;
3309 int v3 = (nfsd->nd_flag & ND_NFSV3);
3310 char *cp2;
3311 struct mbuf *mb, *mreq;
3312 struct vnode *vp;
3313 struct vattr at;
3314 nfsrvfh_t nsfh;
3315 u_quad_t frev, tval;
3316
3317 nfsm_srvmtofh(&nsfh);
3318 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
3319 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
3320 if (error) {
3321 nfsm_reply(NFSX_UNSIGNED);
3322 nfsm_srvpostop_attr(getret, &at);
3323 return (0);
3324 }
3325 sf = malloc(sizeof(*sf), M_TEMP, M_WAITOK);
3326 error = VFS_STATVFS(vp->v_mount, sf);
3327 getret = VOP_GETATTR(vp, &at, cred);
3328 vput(vp);
3329 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
3330 if (v3)
3331 nfsm_srvpostop_attr(getret, &at);
3332 if (error) {
3333 free(sf, M_TEMP);
3334 return (0);
3335 }
3336 nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
3337 if (v3) {
3338 tval = (u_quad_t)((quad_t)sf->f_blocks * (quad_t)sf->f_frsize);
3339 txdr_hyper(tval, &sfp->sf_tbytes);
3340 tval = (u_quad_t)((quad_t)sf->f_bfree * (quad_t)sf->f_frsize);
3341 txdr_hyper(tval, &sfp->sf_fbytes);
3342 tval = (u_quad_t)((quad_t)sf->f_bavail * (quad_t)sf->f_frsize);
3343 txdr_hyper(tval, &sfp->sf_abytes);
3344 tval = (u_quad_t)sf->f_files;
3345 txdr_hyper(tval, &sfp->sf_tfiles);
3346 tval = (u_quad_t)sf->f_ffree;
3347 txdr_hyper(tval, &sfp->sf_ffiles);
3348 txdr_hyper(tval, &sfp->sf_afiles);
3349 sfp->sf_invarsec = 0;
3350 } else {
3351 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
3352 sfp->sf_bsize = txdr_unsigned(sf->f_frsize);
3353 sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
3354 sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
3355 sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
3356 }
3357 nfsmout:
3358 if (sf)
3359 free(sf, M_TEMP);
3360 return error;
3361 }
3362
3363 /*
3364 * nfs fsinfo service
3365 */
3366 int
3367 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
3368 {
3369 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3370 struct mbuf *nam = nfsd->nd_nam;
3371 char *dpos = nfsd->nd_dpos;
3372 kauth_cred_t cred = nfsd->nd_cr;
3373 u_int32_t *tl;
3374 struct nfsv3_fsinfo *sip;
3375 int32_t t1;
3376 char *bpos;
3377 int error = 0, rdonly, cache = 0, getret = 1;
3378 uint32_t maxdata;
3379 char *cp2;
3380 struct mbuf *mb, *mreq;
3381 struct vnode *vp;
3382 struct vattr at;
3383 nfsrvfh_t nsfh;
3384 u_quad_t frev, maxfsize;
3385 struct statvfs *sb;
3386
3387 nfsm_srvmtofh(&nsfh);
3388 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
3389 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
3390 if (error) {
3391 nfsm_reply(NFSX_UNSIGNED);
3392 nfsm_srvpostop_attr(getret, &at);
3393 return (0);
3394 }
3395
3396 /* XXX Try to make a guess on the max file size. */
3397 sb = malloc(sizeof(*sb), M_TEMP, M_WAITOK);
3398 VFS_STATVFS(vp->v_mount, sb);
3399 maxfsize = (u_quad_t)0x80000000 * sb->f_frsize - 1;
3400 free(sb, M_TEMP);
3401
3402 getret = VOP_GETATTR(vp, &at, cred);
3403 vput(vp);
3404 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
3405 nfsm_srvpostop_attr(getret, &at);
3406 nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
3407
3408 /*
3409 * XXX
3410 * There should be file system VFS OP(s) to get this information.
3411 * For now, assume ufs.
3412 */
3413 if (slp->ns_so->so_type == SOCK_DGRAM)
3414 maxdata = NFS_MAXDGRAMDATA;
3415 else
3416 maxdata = NFS_MAXDATA;
3417 sip->fs_rtmax = txdr_unsigned(maxdata);
3418 sip->fs_rtpref = txdr_unsigned(maxdata);
3419 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3420 sip->fs_wtmax = txdr_unsigned(maxdata);
3421 sip->fs_wtpref = txdr_unsigned(maxdata);
3422 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3423 sip->fs_dtpref = txdr_unsigned(maxdata);
3424 txdr_hyper(maxfsize, &sip->fs_maxfilesize);
3425 sip->fs_timedelta.nfsv3_sec = 0;
3426 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3427 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3428 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3429 NFSV3FSINFO_CANSETTIME);
3430 nfsm_srvdone;
3431 }
3432
3433 /*
3434 * nfs pathconf service
3435 */
3436 int
3437 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct lwp *lwp, struct mbuf **mrq)
3438 {
3439 struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3440 struct mbuf *nam = nfsd->nd_nam;
3441 char *dpos = nfsd->nd_dpos;
3442 kauth_cred_t cred = nfsd->nd_cr;
3443 u_int32_t *tl;
3444 struct nfsv3_pathconf *pc;
3445 int32_t t1;
3446 char *bpos;
3447 int error = 0, rdonly, cache = 0, getret = 1;
3448 register_t linkmax, namemax, chownres, notrunc;
3449 char *cp2;
3450 struct mbuf *mb, *mreq;
3451 struct vnode *vp;
3452 struct vattr at;
3453 nfsrvfh_t nsfh;
3454 u_quad_t frev;
3455
3456 nfsm_srvmtofh(&nsfh);
3457 error = nfsrv_fhtovp(&nsfh, 1, &vp, cred, slp, nam,
3458 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), false);
3459 if (error) {
3460 nfsm_reply(NFSX_UNSIGNED);
3461 nfsm_srvpostop_attr(getret, &at);
3462 return (0);
3463 }
3464 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
3465 if (!error)
3466 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
3467 if (!error)
3468 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
3469 if (!error)
3470 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc);
3471 getret = VOP_GETATTR(vp, &at, cred);
3472 vput(vp);
3473 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
3474 nfsm_srvpostop_attr(getret, &at);
3475 if (error)
3476 return (0);
3477 nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
3478
3479 pc->pc_linkmax = txdr_unsigned(linkmax);
3480 pc->pc_namemax = txdr_unsigned(namemax);
3481 pc->pc_notrunc = txdr_unsigned(notrunc);
3482 pc->pc_chownrestricted = txdr_unsigned(chownres);
3483
3484 /*
3485 * These should probably be supported by VOP_PATHCONF(), but
3486 * until msdosfs is exportable (why would you want to?), the
3487 * Unix defaults should be ok.
3488 */
3489 pc->pc_caseinsensitive = nfs_false;
3490 pc->pc_casepreserving = nfs_true;
3491 nfsm_srvdone;
3492 }
3493
3494 /*
3495 * Null operation, used by clients to ping server
3496 */
3497 /* ARGSUSED */
3498 int
3499 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3500 struct lwp *lwp, struct mbuf **mrq)
3501 {
3502 struct mbuf *mrep = nfsd->nd_mrep;
3503 char *bpos;
3504 int error = NFSERR_RETVOID, cache = 0;
3505 struct mbuf *mb, *mreq;
3506 u_quad_t frev;
3507
3508 nfsm_reply(0);
3509 nfsmout:
3510 return (0);
3511 }
3512
3513 /*
3514 * No operation, used for obsolete procedures
3515 */
3516 /* ARGSUSED */
3517 int
3518 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3519 struct lwp *lwp, struct mbuf **mrq)
3520 {
3521 struct mbuf *mrep = nfsd->nd_mrep;
3522 char *bpos;
3523 int error, cache = 0;
3524 struct mbuf *mb, *mreq;
3525 u_quad_t frev;
3526
3527 if (nfsd->nd_repstat)
3528 error = nfsd->nd_repstat;
3529 else
3530 error = EPROCUNAVAIL;
3531 nfsm_reply(0);
3532 nfsmout:
3533 return (0);
3534 }
3535
3536 /*
3537 * Perform access checking for vnodes obtained from file handles that would
3538 * refer to files already opened by a Unix client. You cannot just use
3539 * vn_writechk() and VOP_ACCESS() for two reasons.
3540 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3541 * 2 - The owner is to be given access irrespective of mode bits for some
3542 * operations, so that processes that chmod after opening a file don't
3543 * break. I don't like this because it opens a security hole, but since
3544 * the nfs server opens a security hole the size of a barn door anyhow,
3545 * what the heck.
3546 *
3547 * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
3548 * will return EPERM instead of EACCES. EPERM is always an error.
3549 */
3550 int
3551 nfsrv_access(struct vnode *vp, int flags, kauth_cred_t cred, int rdonly, struct lwp *lwp, int override)
3552 {
3553 struct vattr vattr;
3554 int error;
3555 if (flags & VWRITE) {
3556 /* Just vn_writechk() changed to check rdonly */
3557 /*
3558 * Disallow write attempts on read-only file systems;
3559 * unless the file is a socket or a block or character
3560 * device resident on the file system.
3561 */
3562 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3563 switch (vp->v_type) {
3564 case VREG:
3565 case VDIR:
3566 case VLNK:
3567 return (EROFS);
3568 default:
3569 break;
3570 }
3571 }
3572
3573 /*
3574 * If the vnode is in use as a process's text,
3575 * we can't allow writing.
3576 */
3577 if (vp->v_iflag & VI_TEXT)
3578 return (ETXTBSY);
3579 }
3580 error = VOP_GETATTR(vp, &vattr, cred);
3581 if (error)
3582 return (error);
3583 error = VOP_ACCESS(vp, flags, cred);
3584 /*
3585 * Allow certain operations for the owner (reads and writes
3586 * on files that are already open).
3587 */
3588 if (override && error == EACCES && kauth_cred_geteuid(cred) == vattr.va_uid)
3589 error = 0;
3590 return error;
3591 }
3592