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