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