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