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