657f85aff17f5eab05dda067b359949a6c6013bb
[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.8 2003/08/20 09:56:33 rob 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 timeval   nfsver = { 0 };
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 = LOOKUP;
488         nd.ni_cnd.cn_flags = LOCKLEAF | 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, 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_usec);
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_usec);
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 = CREATE;
1633         nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | 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, &nd.ni_vp, &nd.ni_cnd, vap);
1731                         if (error)
1732                                 NDFREE(&nd, NDF_ONLY_PNBUF);
1733                         else {
1734                                 nfsrv_object_create(nd.ni_vp);
1735                                 if (exclusive_flag) {
1736                                         exclusive_flag = 0;
1737                                         VATTR_NULL(vap);
1738                                         bcopy(cverf, (caddr_t)&vap->va_atime,
1739                                                 NFSX_V3CREATEVERF);
1740                                         error = VOP_SETATTR(nd.ni_vp, vap, cred,
1741                                                 td);
1742                                 }
1743                         }
1744                 } else if (
1745                         vap->va_type == VCHR || 
1746                         vap->va_type == VBLK ||
1747                         vap->va_type == VFIFO
1748                 ) {
1749                         /*
1750                          * Handle SysV FIFO node special cases.  All other
1751                          * devices require super user to access.
1752                          */
1753                         if (vap->va_type == VCHR && rdev == 0xffffffff)
1754                                 vap->va_type = VFIFO;
1755                         if (vap->va_type != VFIFO &&
1756                             (error = suser_cred(cred, 0))) {
1757                                 goto nfsmreply0;
1758                         }
1759                         vap->va_rdev = rdev;
1760                         nqsrv_getl(nd.ni_dvp, ND_WRITE);
1761
1762                         error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1763                         if (error) {
1764                                 NDFREE(&nd, NDF_ONLY_PNBUF);
1765                                 goto nfsmreply0;
1766                         }
1767                         vput(nd.ni_vp);
1768                         nd.ni_vp = NULL;
1769
1770                         /*
1771                          * release dvp prior to lookup
1772                          */
1773                         vput(nd.ni_dvp);
1774                         nd.ni_dvp = NULL;
1775
1776                         /*
1777                          * Setup for lookup. 
1778                          *
1779                          * Even though LOCKPARENT was cleared, ni_dvp may
1780                          * be garbage. 
1781                          */
1782                         nd.ni_cnd.cn_nameiop = LOOKUP;
1783                         nd.ni_cnd.cn_flags &= ~(LOCKPARENT);
1784                         nd.ni_cnd.cn_td = td;
1785                         nd.ni_cnd.cn_cred = cred;
1786
1787                         error = lookup(&nd);
1788                         nd.ni_dvp = NULL;
1789
1790                         if (error != 0) {
1791                                 nfsm_reply(0);
1792                                 /* fall through on certain errors */
1793                         }
1794                         nfsrv_object_create(nd.ni_vp);
1795                         if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1796                                 error = EINVAL;
1797                                 goto nfsmreply0;
1798                         }
1799                 } else {
1800                         error = ENXIO;
1801                 }
1802         } else {
1803                 if (vap->va_size != -1) {
1804                         error = nfsrv_access(nd.ni_vp, VWRITE, cred,
1805                             (nd.ni_cnd.cn_flags & RDONLY), td, 0);
1806                         if (!error) {
1807                                 nqsrv_getl(nd.ni_vp, ND_WRITE);
1808                                 tempsize = vap->va_size;
1809                                 VATTR_NULL(vap);
1810                                 vap->va_size = tempsize;
1811                                 error = VOP_SETATTR(nd.ni_vp, vap, cred, td);
1812                         }
1813                 }
1814         }
1815
1816         if (!error) {
1817                 bzero((caddr_t)fhp, sizeof(nfh));
1818                 fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
1819                 error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
1820                 if (!error)
1821                         error = VOP_GETATTR(nd.ni_vp, vap, td);
1822         }
1823         if (v3) {
1824                 if (exclusive_flag && !error &&
1825                         bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF))
1826                         error = EEXIST;
1827                 diraft_ret = VOP_GETATTR(dirp, &diraft, td);
1828                 vrele(dirp);
1829                 dirp = NULL;
1830         }
1831         nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
1832         if (v3) {
1833                 if (!error) {
1834                         nfsm_srvpostop_fh(fhp);
1835                         nfsm_srvpostop_attr(0, vap);
1836                 }
1837                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1838                 error = 0;
1839         } else {
1840                 nfsm_srvfhtom(fhp, v3);
1841                 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1842                 nfsm_srvfillattr(vap, fp);
1843         }
1844         goto nfsmout;
1845
1846 nfsmreply0:
1847         nfsm_reply(0);
1848         error = 0;
1849         /* fall through */
1850
1851 nfsmout:
1852         if (nd.ni_startdir) {
1853                 vrele(nd.ni_startdir);
1854                 nd.ni_startdir = NULL;
1855         }
1856         if (dirp)
1857                 vrele(dirp);
1858         NDFREE(&nd, NDF_ONLY_PNBUF);
1859         if (nd.ni_dvp) {
1860                 if (nd.ni_dvp == nd.ni_vp)
1861                         vrele(nd.ni_dvp);
1862                 else
1863                         vput(nd.ni_dvp);
1864         }
1865         if (nd.ni_vp)
1866                 vput(nd.ni_vp);
1867         return (error);
1868 }
1869
1870 /*
1871  * nfs v3 mknod service
1872  */
1873 int
1874 nfsrv_mknod(nfsd, slp, td, mrq)
1875         struct nfsrv_descript *nfsd;
1876         struct nfssvc_sock *slp;
1877         struct thread *td;
1878         struct mbuf **mrq;
1879 {
1880         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1881         struct sockaddr *nam = nfsd->nd_nam;
1882         caddr_t dpos = nfsd->nd_dpos;
1883         struct ucred *cred = &nfsd->nd_cr;
1884         struct vattr va, dirfor, diraft;
1885         struct vattr *vap = &va;
1886         u_int32_t *tl;
1887         struct nameidata nd;
1888         int32_t t1;
1889         caddr_t bpos;
1890         int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
1891         u_int32_t major, minor;
1892         enum vtype vtyp;
1893         char *cp2;
1894         struct mbuf *mb, *mb2, *mreq;
1895         struct vnode *vp, *dirp = (struct vnode *)0;
1896         nfsfh_t nfh;
1897         fhandle_t *fhp;
1898         u_quad_t frev;
1899
1900         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
1901         ndclear(&nd);
1902
1903         fhp = &nfh.fh_generic;
1904         nfsm_srvmtofh(fhp);
1905         nfsm_srvnamesiz(len);
1906
1907         nd.ni_cnd.cn_cred = cred;
1908         nd.ni_cnd.cn_nameiop = CREATE;
1909         nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1910
1911         /*
1912          * Handle nfs_namei() call.  If an error occurs, the nd structure
1913          * is not valid.  However, nfsm_*() routines may still jump to
1914          * nfsmout.
1915          */
1916
1917         error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1918                 &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1919         if (dirp)
1920                 dirfor_ret = VOP_GETATTR(dirp, &dirfor, td);
1921         if (error) {
1922                 nfsm_reply(NFSX_WCCDATA(1));
1923                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1924                 error = 0;
1925                 goto nfsmout;
1926         }
1927         nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1928         vtyp = nfsv3tov_type(*tl);
1929         if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1930                 error = NFSERR_BADTYPE;
1931                 goto out;
1932         }
1933         VATTR_NULL(vap);
1934         nfsm_srvsattr(vap);
1935         if (vtyp == VCHR || vtyp == VBLK) {
1936                 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1937                 major = fxdr_unsigned(u_int32_t, *tl++);
1938                 minor = fxdr_unsigned(u_int32_t, *tl);
1939                 vap->va_rdev = makeudev(major, minor);
1940         }
1941
1942         /*
1943          * Iff doesn't exist, create it.
1944          */
1945         if (nd.ni_vp) {
1946                 error = EEXIST;
1947                 goto out;
1948         }
1949         vap->va_type = vtyp;
1950         if (vap->va_mode == (mode_t)VNOVAL)
1951                 vap->va_mode = 0;
1952         if (vtyp == VSOCK) {
1953                 vrele(nd.ni_startdir);
1954                 nd.ni_startdir = NULL;
1955                 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1956                 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1957                 if (error)
1958                         NDFREE(&nd, NDF_ONLY_PNBUF);
1959         } else {
1960                 if (vtyp != VFIFO && (error = suser_cred(cred, 0)))
1961                         goto out;
1962                 nqsrv_getl(nd.ni_dvp, ND_WRITE);
1963
1964                 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1965                 if (error) {
1966                         NDFREE(&nd, NDF_ONLY_PNBUF);
1967                         goto out;
1968                 }
1969                 vput(nd.ni_vp);
1970                 nd.ni_vp = NULL;
1971
1972                 /*
1973                  * Release dvp prior to lookup
1974                  */
1975                 vput(nd.ni_dvp);
1976                 nd.ni_dvp = NULL;
1977
1978                 KKASSERT(td->td_proc);
1979                 nd.ni_cnd.cn_nameiop = LOOKUP;
1980                 nd.ni_cnd.cn_flags &= ~(LOCKPARENT);
1981                 nd.ni_cnd.cn_td = td;
1982                 nd.ni_cnd.cn_cred = td->td_proc->p_ucred;
1983
1984                 error = lookup(&nd);
1985                 nd.ni_dvp = NULL;
1986
1987                 if (error)
1988                         goto out;
1989                 if (nd.ni_cnd.cn_flags & ISSYMLINK)
1990                         error = EINVAL;
1991         }
1992
1993         /*
1994          * send response, cleanup, return.
1995          */
1996 out:
1997         if (nd.ni_startdir) {
1998                 vrele(nd.ni_startdir);
1999                 nd.ni_startdir = NULL;
2000         }
2001         NDFREE(&nd, NDF_ONLY_PNBUF);
2002         if (nd.ni_dvp) {
2003                 if (nd.ni_dvp == nd.ni_vp)
2004                         vrele(nd.ni_dvp);
2005                 else
2006                         vput(nd.ni_dvp);
2007                 nd.ni_dvp = NULL;
2008         }
2009         vp = nd.ni_vp;
2010         if (!error) {
2011                 bzero((caddr_t)fhp, sizeof(nfh));
2012                 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
2013                 error = VFS_VPTOFH(vp, &fhp->fh_fid);
2014                 if (!error)
2015                         error = VOP_GETATTR(vp, vap, td);
2016         }
2017         if (vp) {
2018                 vput(vp);
2019                 vp = NULL;
2020                 nd.ni_vp = NULL;
2021         }
2022         diraft_ret = VOP_GETATTR(dirp, &diraft, td);
2023         if (dirp) {
2024                 vrele(dirp);
2025                 dirp = NULL;
2026         }
2027         nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
2028         if (!error) {
2029                 nfsm_srvpostop_fh(fhp);
2030                 nfsm_srvpostop_attr(0, vap);
2031         }
2032         nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2033         return (0);
2034 nfsmout:
2035         if (dirp)
2036                 vrele(dirp);
2037         if (nd.ni_startdir)
2038                 vrele(nd.ni_startdir);
2039         NDFREE(&nd, NDF_ONLY_PNBUF);
2040         if (nd.ni_dvp) {
2041                 if (nd.ni_dvp == nd.ni_vp)
2042                         vrele(nd.ni_dvp);
2043                 else
2044                         vput(nd.ni_dvp);
2045         }
2046         if (nd.ni_vp)
2047                 vput(nd.ni_vp);
2048         return (error);
2049 }
2050
2051 /*
2052  * nfs remove service
2053  */
2054 int
2055 nfsrv_remove(nfsd, slp, td, mrq)
2056         struct nfsrv_descript *nfsd;
2057         struct nfssvc_sock *slp;
2058         struct thread *td;
2059         struct mbuf **mrq;
2060 {
2061         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2062         struct sockaddr *nam = nfsd->nd_nam;
2063         caddr_t dpos = nfsd->nd_dpos;
2064         struct ucred *cred = &nfsd->nd_cr;
2065         struct nameidata nd;
2066         u_int32_t *tl;
2067         int32_t t1;
2068         caddr_t bpos;
2069         int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2070         int v3 = (nfsd->nd_flag & ND_NFSV3);
2071         char *cp2;
2072         struct mbuf *mb, *mreq;
2073         struct vnode *dirp;
2074         struct vattr dirfor, diraft;
2075         nfsfh_t nfh;
2076         fhandle_t *fhp;
2077         u_quad_t frev;
2078
2079         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2080         ndclear(&nd);
2081
2082         fhp = &nfh.fh_generic;
2083         nfsm_srvmtofh(fhp);
2084         nfsm_srvnamesiz(len);
2085
2086         nd.ni_cnd.cn_cred = cred;
2087         nd.ni_cnd.cn_nameiop = DELETE;
2088         nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2089         error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2090                 &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2091         if (dirp) {
2092                 if (v3) {
2093                         dirfor_ret = VOP_GETATTR(dirp, &dirfor, td);
2094                 } else {
2095                         vrele(dirp);
2096                         dirp = NULL;
2097                 }
2098         }
2099         if (error == 0) {
2100                 if (nd.ni_vp->v_type == VDIR) {
2101                         error = EPERM;          /* POSIX */
2102                         goto out;
2103                 }
2104                 /*
2105                  * The root of a mounted filesystem cannot be deleted.
2106                  */
2107                 if (nd.ni_vp->v_flag & VROOT) {
2108                         error = EBUSY;
2109                         goto out;
2110                 }
2111 out:
2112                 if (!error) {
2113                         nqsrv_getl(nd.ni_dvp, ND_WRITE);
2114                         nqsrv_getl(nd.ni_vp, ND_WRITE);
2115                         error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2116                         NDFREE(&nd, NDF_ONLY_PNBUF);
2117                 }
2118         }
2119         if (dirp && v3) {
2120                 diraft_ret = VOP_GETATTR(dirp, &diraft, td);
2121                 vrele(dirp);
2122                 dirp = NULL;
2123         }
2124         nfsm_reply(NFSX_WCCDATA(v3));
2125         if (v3) {
2126                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2127                 error = 0;
2128         }
2129 nfsmout:
2130         NDFREE(&nd, NDF_ONLY_PNBUF);
2131         if (nd.ni_dvp) {
2132                 if (nd.ni_dvp == nd.ni_vp)
2133                         vrele(nd.ni_dvp);
2134                 else
2135                         vput(nd.ni_dvp);
2136         }
2137         if (nd.ni_vp)
2138                 vput(nd.ni_vp);
2139         return(error);
2140 }
2141
2142 /*
2143  * nfs rename service
2144  */
2145 int
2146 nfsrv_rename(nfsd, slp, td, mrq)
2147         struct nfsrv_descript *nfsd;
2148         struct nfssvc_sock *slp;
2149         struct thread *td;
2150         struct mbuf **mrq;
2151 {
2152         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2153         struct sockaddr *nam = nfsd->nd_nam;
2154         caddr_t dpos = nfsd->nd_dpos;
2155         struct ucred *cred = &nfsd->nd_cr;
2156         u_int32_t *tl;
2157         int32_t t1;
2158         caddr_t bpos;
2159         int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
2160         int tdirfor_ret = 1, tdiraft_ret = 1;
2161         int v3 = (nfsd->nd_flag & ND_NFSV3);
2162         char *cp2;
2163         struct mbuf *mb, *mreq;
2164         struct nameidata fromnd, tond;
2165         struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0;
2166         struct vnode *tdirp = (struct vnode *)0;
2167         struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
2168         nfsfh_t fnfh, tnfh;
2169         fhandle_t *ffhp, *tfhp;
2170         u_quad_t frev;
2171         uid_t saved_uid;
2172
2173         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2174 #ifndef nolint
2175         fvp = (struct vnode *)0;
2176 #endif
2177         ffhp = &fnfh.fh_generic;
2178         tfhp = &tnfh.fh_generic;
2179
2180         /*
2181          * Clear fields incase goto nfsmout occurs from macro.
2182          */
2183
2184         ndclear(&fromnd);
2185         ndclear(&tond);
2186
2187         nfsm_srvmtofh(ffhp);
2188         nfsm_srvnamesiz(len);
2189         /*
2190          * Remember our original uid so that we can reset cr_uid before
2191          * the second nfs_namei() call, in case it is remapped.
2192          */
2193         saved_uid = cred->cr_uid;
2194         fromnd.ni_cnd.cn_cred = cred;
2195         fromnd.ni_cnd.cn_nameiop = DELETE;
2196         fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
2197         error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
2198                 &dpos, &fdirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2199         if (fdirp) {
2200                 if (v3) {
2201                         fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, td);
2202                 } else {
2203                         vrele(fdirp);
2204                         fdirp = NULL;
2205                 }
2206         }
2207         if (error) {
2208                 nfsm_reply(2 * NFSX_WCCDATA(v3));
2209                 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
2210                 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
2211                 error = 0;
2212                 goto nfsmout;
2213         }
2214         fvp = fromnd.ni_vp;
2215         nfsm_srvmtofh(tfhp);
2216         nfsm_strsiz(len2, NFS_MAXNAMLEN);
2217         cred->cr_uid = saved_uid;
2218         tond.ni_cnd.cn_cred = cred;
2219         tond.ni_cnd.cn_nameiop = RENAME;
2220         tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
2221         error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
2222                 &dpos, &tdirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2223         if (tdirp) {
2224                 if (v3) {
2225                         tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, td);
2226                 } else {
2227                         vrele(tdirp);
2228                         tdirp = NULL;
2229                 }
2230         }
2231         if (error)
2232                 goto out1;
2233
2234         tdvp = tond.ni_dvp;
2235         tvp = tond.ni_vp;
2236         if (tvp != NULL) {
2237                 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2238                         if (v3)
2239                                 error = EEXIST;
2240                         else
2241                                 error = EISDIR;
2242                         goto out;
2243                 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2244                         if (v3)
2245                                 error = EEXIST;
2246                         else
2247                                 error = ENOTDIR;
2248                         goto out;
2249                 }
2250                 if (tvp->v_type == VDIR && tvp->v_mountedhere) {
2251                         if (v3)
2252                                 error = EXDEV;
2253                         else
2254                                 error = ENOTEMPTY;
2255                         goto out;
2256                 }
2257         }
2258         if (fvp->v_type == VDIR && fvp->v_mountedhere) {
2259                 if (v3)
2260                         error = EXDEV;
2261                 else
2262                         error = ENOTEMPTY;
2263                 goto out;
2264         }
2265         if (fvp->v_mount != tdvp->v_mount) {
2266                 if (v3)
2267                         error = EXDEV;
2268                 else
2269                         error = ENOTEMPTY;
2270                 goto out;
2271         }
2272         if (fvp == tdvp) {
2273                 if (v3)
2274                         error = EINVAL;
2275                 else
2276                         error = ENOTEMPTY;
2277         }
2278         /*
2279          * If source is the same as the destination (that is the
2280          * same vnode with the same name in the same directory),
2281          * then there is nothing to do.
2282          */
2283         if (fvp == tvp && fromnd.ni_dvp == tdvp &&
2284             fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2285             !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2286               fromnd.ni_cnd.cn_namelen))
2287                 error = -1;
2288 out:
2289         if (!error) {
2290                 /*
2291                  * The VOP_RENAME function releases all vnode references &
2292                  * locks prior to returning so we need to clear the pointers
2293                  * to bypass cleanup code later on.
2294                  */
2295                 nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
2296                 nqsrv_getl(tdvp, ND_WRITE);
2297                 if (tvp) {
2298                         nqsrv_getl(tvp, ND_WRITE);
2299                 }
2300                 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2301                                    tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2302                 fromnd.ni_dvp = NULL;
2303                 fromnd.ni_vp = NULL;
2304                 tond.ni_dvp = NULL;
2305                 tond.ni_vp = NULL;
2306                 if (error) {
2307                         fromnd.ni_cnd.cn_flags &= ~HASBUF;
2308                         tond.ni_cnd.cn_flags &= ~HASBUF;
2309                 }
2310         } else {
2311                 if (error == -1)
2312                         error = 0;
2313         }
2314         /* fall through */
2315
2316 out1:
2317         if (fdirp)
2318                 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, td);
2319         if (tdirp)
2320                 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, td);
2321         nfsm_reply(2 * NFSX_WCCDATA(v3));
2322         if (v3) {
2323                 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
2324                 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
2325         }
2326         error = 0;
2327         /* fall through */
2328
2329 nfsmout:
2330         /*
2331          * Clear out tond related fields
2332          */
2333         if (tdirp)
2334                 vrele(tdirp);
2335         if (tond.ni_startdir)
2336                 vrele(tond.ni_startdir);
2337         NDFREE(&tond, NDF_ONLY_PNBUF);
2338         if (tond.ni_dvp) {
2339                 if (tond.ni_dvp == tond.ni_vp)
2340                         vrele(tond.ni_dvp);
2341                 else
2342                         vput(tond.ni_dvp);
2343         }
2344         if (tond.ni_vp)
2345                 vput(tond.ni_vp);
2346
2347         /*
2348          * Clear out fromnd related fields
2349          */
2350         if (fdirp)
2351                 vrele(fdirp);
2352         if (fromnd.ni_startdir)
2353                 vrele(fromnd.ni_startdir);
2354         NDFREE(&fromnd, NDF_ONLY_PNBUF);
2355         if (fromnd.ni_dvp)
2356                 vrele(fromnd.ni_dvp);
2357         if (fromnd.ni_vp)
2358                 vrele(fromnd.ni_vp);
2359
2360         return (error);
2361 }
2362
2363 /*
2364  * nfs link service
2365  */
2366 int
2367 nfsrv_link(nfsd, slp, td, mrq)
2368         struct nfsrv_descript *nfsd;
2369         struct nfssvc_sock *slp;
2370         struct thread *td;
2371         struct mbuf **mrq;
2372 {
2373         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2374         struct sockaddr *nam = nfsd->nd_nam;
2375         caddr_t dpos = nfsd->nd_dpos;
2376         struct ucred *cred = &nfsd->nd_cr;
2377         struct nameidata nd;
2378         u_int32_t *tl;
2379         int32_t t1;
2380         caddr_t bpos;
2381         int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1;
2382         int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
2383         char *cp2;
2384         struct mbuf *mb, *mreq;
2385         struct vnode *vp = NULL, *xp, *dirp = (struct vnode *)0;
2386         struct vattr dirfor, diraft, at;
2387         nfsfh_t nfh, dnfh;
2388         fhandle_t *fhp, *dfhp;
2389         u_quad_t frev;
2390
2391         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2392         ndclear(&nd);
2393
2394         fhp = &nfh.fh_generic;
2395         dfhp = &dnfh.fh_generic;
2396         nfsm_srvmtofh(fhp);
2397         nfsm_srvmtofh(dfhp);
2398         nfsm_srvnamesiz(len);
2399
2400         error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
2401                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
2402         if (error) {
2403                 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2404                 nfsm_srvpostop_attr(getret, &at);
2405                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2406                 vp = NULL;
2407                 error = 0;
2408                 goto nfsmout;
2409         }
2410         if (vp->v_type == VDIR) {
2411                 error = EPERM;          /* POSIX */
2412                 goto out1;
2413         }
2414         nd.ni_cnd.cn_cred = cred;
2415         nd.ni_cnd.cn_nameiop = CREATE;
2416         nd.ni_cnd.cn_flags = LOCKPARENT;
2417         error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
2418                 &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2419         if (dirp) {
2420                 if (v3) {
2421                         dirfor_ret = VOP_GETATTR(dirp, &dirfor, td);
2422                 } else {
2423                         vrele(dirp);
2424                         dirp = NULL;
2425                 }
2426         }
2427         if (error)
2428                 goto out1;
2429
2430         xp = nd.ni_vp;
2431         if (xp != NULL) {
2432                 error = EEXIST;
2433                 goto out;
2434         }
2435         xp = nd.ni_dvp;
2436         if (vp->v_mount != xp->v_mount)
2437                 error = EXDEV;
2438 out:
2439         if (!error) {
2440                 nqsrv_getl(vp, ND_WRITE);
2441                 nqsrv_getl(xp, ND_WRITE);
2442                 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
2443                 NDFREE(&nd, NDF_ONLY_PNBUF);
2444         }
2445         /* fall through */
2446
2447 out1:
2448         if (v3)
2449                 getret = VOP_GETATTR(vp, &at, td);
2450         if (dirp)
2451                 diraft_ret = VOP_GETATTR(dirp, &diraft, td);
2452         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2453         if (v3) {
2454                 nfsm_srvpostop_attr(getret, &at);
2455                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2456                 error = 0;
2457         }
2458         /* fall through */
2459
2460 nfsmout:
2461         NDFREE(&nd, NDF_ONLY_PNBUF);
2462         if (dirp)
2463                 vrele(dirp);
2464         if (vp)
2465                 vrele(vp);
2466         if (nd.ni_dvp) {
2467                 if (nd.ni_dvp == nd.ni_vp)
2468                         vrele(nd.ni_dvp);
2469                 else
2470                         vput(nd.ni_dvp);
2471         }
2472         if (nd.ni_vp)
2473                 vrele(nd.ni_vp);
2474         return(error);
2475 }
2476
2477 /*
2478  * nfs symbolic link service
2479  */
2480 int
2481 nfsrv_symlink(nfsd, slp, td, mrq)
2482         struct nfsrv_descript *nfsd;
2483         struct nfssvc_sock *slp;
2484         struct thread *td;
2485         struct mbuf **mrq;
2486 {
2487         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2488         struct sockaddr *nam = nfsd->nd_nam;
2489         caddr_t dpos = nfsd->nd_dpos;
2490         struct ucred *cred = &nfsd->nd_cr;
2491         struct vattr va, dirfor, diraft;
2492         struct nameidata nd;
2493         struct vattr *vap = &va;
2494         u_int32_t *tl;
2495         int32_t t1;
2496         struct nfsv2_sattr *sp;
2497         char *bpos, *pathcp = (char *)0, *cp2;
2498         struct uio io;
2499         struct iovec iv;
2500         int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1;
2501         int v3 = (nfsd->nd_flag & ND_NFSV3);
2502         struct mbuf *mb, *mreq, *mb2;
2503         struct vnode *dirp = (struct vnode *)0;
2504         nfsfh_t nfh;
2505         fhandle_t *fhp;
2506         u_quad_t frev;
2507
2508         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2509         ndclear(&nd);
2510
2511         fhp = &nfh.fh_generic;
2512         nfsm_srvmtofh(fhp);
2513         nfsm_srvnamesiz(len);
2514         nd.ni_cnd.cn_cred = cred;
2515         nd.ni_cnd.cn_nameiop = CREATE;
2516         nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART;
2517         error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2518                 &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2519         if (dirp) {
2520                 if (v3) {
2521                         dirfor_ret = VOP_GETATTR(dirp, &dirfor, td);
2522                 } else {
2523                         vrele(dirp);
2524                         dirp = NULL;
2525                 }
2526         }
2527         if (error)
2528                 goto out;
2529
2530         VATTR_NULL(vap);
2531         if (v3)
2532                 nfsm_srvsattr(vap);
2533         nfsm_strsiz(len2, NFS_MAXPATHLEN);
2534         MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
2535         iv.iov_base = pathcp;
2536         iv.iov_len = len2;
2537         io.uio_resid = len2;
2538         io.uio_offset = 0;
2539         io.uio_iov = &iv;
2540         io.uio_iovcnt = 1;
2541         io.uio_segflg = UIO_SYSSPACE;
2542         io.uio_rw = UIO_READ;
2543         io.uio_td = NULL;
2544         nfsm_mtouio(&io, len2);
2545         if (!v3) {
2546                 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2547                 vap->va_mode = nfstov_mode(sp->sa_mode);
2548         }
2549         *(pathcp + len2) = '\0';
2550         if (nd.ni_vp) {
2551                 error = EEXIST;
2552                 goto out;
2553         }
2554
2555         /*
2556          * issue symlink op.  SAVESTART is set so the underlying path component
2557          * is only freed by the VOP if an error occurs.
2558          */
2559         if (vap->va_mode == (mode_t)VNOVAL)
2560                 vap->va_mode = 0;
2561         nqsrv_getl(nd.ni_dvp, ND_WRITE);
2562         error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
2563         if (error)
2564                 NDFREE(&nd, NDF_ONLY_PNBUF);
2565         else
2566                 vput(nd.ni_vp);
2567         nd.ni_vp = NULL;
2568         /*
2569          * releases directory prior to potential lookup op.
2570          */
2571         vput(nd.ni_dvp);
2572         nd.ni_dvp = NULL;
2573
2574         if (error == 0) {
2575             if (v3) {
2576                 /*
2577                  * Issue lookup.  Leave SAVESTART set so we can easily free
2578                  * the name buffer later on.
2579                  *
2580                  * since LOCKPARENT is not set, ni_dvp will be garbage on
2581                  * return whether an error occurs or not.
2582                  */
2583                 nd.ni_cnd.cn_nameiop = LOOKUP;
2584                 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | FOLLOW);
2585                 nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
2586                 nd.ni_cnd.cn_td = td;
2587                 nd.ni_cnd.cn_cred = cred;
2588
2589                 error = lookup(&nd);
2590                 nd.ni_dvp = NULL;
2591
2592                 if (error == 0) {
2593                         bzero((caddr_t)fhp, sizeof(nfh));
2594                         fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
2595                         error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
2596                         if (!error)
2597                                 error = VOP_GETATTR(nd.ni_vp, vap, td);
2598                         vput(nd.ni_vp);
2599                         nd.ni_vp = NULL;
2600                 }
2601             }
2602         }
2603 out:
2604         /*
2605          * These releases aren't strictly required, does even doing them
2606          * make any sense? XXX can nfsm_reply() block?
2607          */
2608         if (pathcp) {
2609                 FREE(pathcp, M_TEMP);
2610                 pathcp = NULL;
2611         }
2612         if (dirp) {
2613                 diraft_ret = VOP_GETATTR(dirp, &diraft, td);
2614                 vrele(dirp);
2615                 dirp = NULL;
2616         }
2617         if (nd.ni_startdir) {
2618                 vrele(nd.ni_startdir);
2619                 nd.ni_startdir = NULL;
2620         }
2621         nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2622         if (v3) {
2623                 if (!error) {
2624                         nfsm_srvpostop_fh(fhp);
2625                         nfsm_srvpostop_attr(0, vap);
2626                 }
2627                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2628         }
2629         error = 0;
2630         /* fall through */
2631
2632 nfsmout:
2633         NDFREE(&nd, NDF_ONLY_PNBUF);
2634         if (nd.ni_dvp) {
2635                 if (nd.ni_dvp == nd.ni_vp)
2636                         vrele(nd.ni_dvp);
2637                 else
2638                         vput(nd.ni_dvp);
2639         }
2640         if (nd.ni_vp)
2641                 vrele(nd.ni_vp);
2642         if (nd.ni_startdir)
2643                 vrele(nd.ni_startdir);
2644         if (dirp)
2645                 vrele(dirp);
2646         if (pathcp)
2647                 FREE(pathcp, M_TEMP);
2648
2649         return (error);
2650 }
2651
2652 /*
2653  * nfs mkdir service
2654  */
2655 int
2656 nfsrv_mkdir(nfsd, slp, td, mrq)
2657         struct nfsrv_descript *nfsd;
2658         struct nfssvc_sock *slp;
2659         struct thread *td;
2660         struct mbuf **mrq;
2661 {
2662         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2663         struct sockaddr *nam = nfsd->nd_nam;
2664         caddr_t dpos = nfsd->nd_dpos;
2665         struct ucred *cred = &nfsd->nd_cr;
2666         struct vattr va, dirfor, diraft;
2667         struct vattr *vap = &va;
2668         struct nfs_fattr *fp;
2669         struct nameidata nd;
2670         caddr_t cp;
2671         u_int32_t *tl;
2672         int32_t t1;
2673         caddr_t bpos;
2674         int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2675         int v3 = (nfsd->nd_flag & ND_NFSV3);
2676         char *cp2;
2677         struct mbuf *mb, *mb2, *mreq;
2678         struct vnode *dirp = NULL;
2679         int vpexcl = 0;
2680         nfsfh_t nfh;
2681         fhandle_t *fhp;
2682         u_quad_t frev;
2683
2684         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2685         ndclear(&nd);
2686
2687         fhp = &nfh.fh_generic;
2688         nfsm_srvmtofh(fhp);
2689         nfsm_srvnamesiz(len);
2690         nd.ni_cnd.cn_cred = cred;
2691         nd.ni_cnd.cn_nameiop = CREATE;
2692         nd.ni_cnd.cn_flags = LOCKPARENT;
2693
2694         error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2695                 &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2696         if (dirp) {
2697                 if (v3) {
2698                         dirfor_ret = VOP_GETATTR(dirp, &dirfor, td);
2699                 } else {
2700                         vrele(dirp);
2701                         dirp = NULL;
2702                 }
2703         }
2704         if (error) {
2705                 nfsm_reply(NFSX_WCCDATA(v3));
2706                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2707                 error = 0;
2708                 goto nfsmout;
2709         }
2710         VATTR_NULL(vap);
2711         if (v3) {
2712                 nfsm_srvsattr(vap);
2713         } else {
2714                 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
2715                 vap->va_mode = nfstov_mode(*tl++);
2716         }
2717
2718         /*
2719          * At this point nd.ni_dvp is referenced and exclusively locked and
2720          * nd.ni_vp, if it exists, is referenced but not locked.
2721          */
2722
2723         vap->va_type = VDIR;
2724         if (nd.ni_vp != NULL) {
2725                 NDFREE(&nd, NDF_ONLY_PNBUF);
2726                 error = EEXIST;
2727                 goto out;
2728         }
2729
2730         /*
2731          * Issue mkdir op.  Since SAVESTART is not set, the pathname 
2732          * component is freed by the VOP call.  This will fill-in
2733          * nd.ni_vp, reference, and exclusively lock it.
2734          */
2735         if (vap->va_mode == (mode_t)VNOVAL)
2736                 vap->va_mode = 0;
2737         nqsrv_getl(nd.ni_dvp, ND_WRITE);
2738         error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
2739         NDFREE(&nd, NDF_ONLY_PNBUF);
2740         vpexcl = 1;
2741
2742         vput(nd.ni_dvp);
2743         nd.ni_dvp = NULL;
2744
2745         if (!error) {
2746                 bzero((caddr_t)fhp, sizeof(nfh));
2747                 fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
2748                 error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
2749                 if (!error)
2750                         error = VOP_GETATTR(nd.ni_vp, vap, td);
2751         }
2752 out:
2753         if (dirp)
2754                 diraft_ret = VOP_GETATTR(dirp, &diraft, td);
2755         nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2756         if (v3) {
2757                 if (!error) {
2758                         nfsm_srvpostop_fh(fhp);
2759                         nfsm_srvpostop_attr(0, vap);
2760                 }
2761                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2762         } else {
2763                 nfsm_srvfhtom(fhp, v3);
2764                 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
2765                 nfsm_srvfillattr(vap, fp);
2766         }
2767         error = 0;
2768         /* fall through */
2769
2770 nfsmout:
2771         if (dirp)
2772                 vrele(dirp);
2773         if (nd.ni_dvp) {
2774                 NDFREE(&nd, NDF_ONLY_PNBUF);
2775                 if (nd.ni_dvp == nd.ni_vp && vpexcl)
2776                         vrele(nd.ni_dvp);
2777                 else
2778                         vput(nd.ni_dvp);
2779         }
2780         if (nd.ni_vp) {
2781                 if (vpexcl)
2782                         vput(nd.ni_vp);
2783                 else
2784                         vrele(nd.ni_vp);
2785         }
2786         return (error);
2787 }
2788
2789 /*
2790  * nfs rmdir service
2791  */
2792 int
2793 nfsrv_rmdir(nfsd, slp, td, mrq)
2794         struct nfsrv_descript *nfsd;
2795         struct nfssvc_sock *slp;
2796         struct thread *td;
2797         struct mbuf **mrq;
2798 {
2799         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2800         struct sockaddr *nam = nfsd->nd_nam;
2801         caddr_t dpos = nfsd->nd_dpos;
2802         struct ucred *cred = &nfsd->nd_cr;
2803         u_int32_t *tl;
2804         int32_t t1;
2805         caddr_t bpos;
2806         int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2807         int v3 = (nfsd->nd_flag & ND_NFSV3);
2808         char *cp2;
2809         struct mbuf *mb, *mreq;
2810         struct vnode *vp, *dirp = (struct vnode *)0;
2811         struct vattr dirfor, diraft;
2812         nfsfh_t nfh;
2813         fhandle_t *fhp;
2814         struct nameidata nd;
2815         u_quad_t frev;
2816
2817         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2818         ndclear(&nd);
2819
2820         fhp = &nfh.fh_generic;
2821         nfsm_srvmtofh(fhp);
2822         nfsm_srvnamesiz(len);
2823         nd.ni_cnd.cn_cred = cred;
2824         nd.ni_cnd.cn_nameiop = DELETE;
2825         nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2826         error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2827                 &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2828         if (dirp) {
2829                 if (v3) {
2830                         dirfor_ret = VOP_GETATTR(dirp, &dirfor, td);
2831                 } else {
2832                         vrele(dirp);
2833                         dirp = NULL;
2834                 }
2835         }
2836         if (error) {
2837                 nfsm_reply(NFSX_WCCDATA(v3));
2838                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2839                 error = 0;
2840                 goto nfsmout;
2841         }
2842         vp = nd.ni_vp;
2843         if (vp->v_type != VDIR) {
2844                 error = ENOTDIR;
2845                 goto out;
2846         }
2847         /*
2848          * No rmdir "." please.
2849          */
2850         if (nd.ni_dvp == vp) {
2851                 error = EINVAL;
2852                 goto out;
2853         }
2854         /*
2855          * The root of a mounted filesystem cannot be deleted.
2856          */
2857         if (vp->v_flag & VROOT)
2858                 error = EBUSY;
2859 out:
2860         /*
2861          * Issue or abort op.  Since SAVESTART is not set, path name
2862          * component is freed by the VOP after either.
2863          */
2864         if (!error) {
2865                 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2866                 nqsrv_getl(vp, ND_WRITE);
2867                 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2868         }
2869         NDFREE(&nd, NDF_ONLY_PNBUF);
2870
2871         if (dirp)
2872                 diraft_ret = VOP_GETATTR(dirp, &diraft, td);
2873         nfsm_reply(NFSX_WCCDATA(v3));
2874         if (v3) {
2875                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2876                 error = 0;
2877         }
2878         /* fall through */
2879
2880 nfsmout:
2881         NDFREE(&nd, NDF_ONLY_PNBUF);
2882         if (dirp)
2883                 vrele(dirp);
2884         if (nd.ni_dvp) {
2885                 if (nd.ni_dvp == nd.ni_vp)
2886                         vrele(nd.ni_dvp);
2887                 else
2888                         vput(nd.ni_dvp);
2889         }
2890         if (nd.ni_vp)
2891                 vput(nd.ni_vp);
2892
2893         return(error);
2894 }
2895
2896 /*
2897  * nfs readdir service
2898  * - mallocs what it thinks is enough to read
2899  *      count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2900  * - calls VOP_READDIR()
2901  * - loops around building the reply
2902  *      if the output generated exceeds count break out of loop
2903  *      The nfsm_clget macro is used here so that the reply will be packed
2904  *      tightly in mbuf clusters.
2905  * - it only knows that it has encountered eof when the VOP_READDIR()
2906  *      reads nothing
2907  * - as such one readdir rpc will return eof false although you are there
2908  *      and then the next will return eof
2909  * - it trims out records with d_fileno == 0
2910  *      this doesn't matter for Unix clients, but they might confuse clients
2911  *      for other os'.
2912  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2913  *      than requested, but this may not apply to all filesystems. For
2914  *      example, client NFS does not { although it is never remote mounted
2915  *      anyhow }
2916  *     The alternate call nfsrv_readdirplus() does lookups as well.
2917  * PS: The NFS protocol spec. does not clarify what the "count" byte
2918  *      argument is a count of.. just name strings and file id's or the
2919  *      entire reply rpc or ...
2920  *      I tried just file name and id sizes and it confused the Sun client,
2921  *      so I am using the full rpc size now. The "paranoia.." comment refers
2922  *      to including the status longwords that are not a part of the dir.
2923  *      "entry" structures, but are in the rpc.
2924  */
2925 struct flrep {
2926         nfsuint64       fl_off;
2927         u_int32_t       fl_postopok;
2928         u_int32_t       fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)];
2929         u_int32_t       fl_fhok;
2930         u_int32_t       fl_fhsize;
2931         u_int32_t       fl_nfh[NFSX_V3FH / sizeof (u_int32_t)];
2932 };
2933
2934 int
2935 nfsrv_readdir(nfsd, slp, td, mrq)
2936         struct nfsrv_descript *nfsd;
2937         struct nfssvc_sock *slp;
2938         struct thread *td;
2939         struct mbuf **mrq;
2940 {
2941         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2942         struct sockaddr *nam = nfsd->nd_nam;
2943         caddr_t dpos = nfsd->nd_dpos;
2944         struct ucred *cred = &nfsd->nd_cr;
2945         char *bp, *be;
2946         struct mbuf *mp;
2947         struct dirent *dp;
2948         caddr_t cp;
2949         u_int32_t *tl;
2950         int32_t t1;
2951         caddr_t bpos;
2952         struct mbuf *mb, *mb2, *mreq, *mp2;
2953         char *cpos, *cend, *cp2, *rbuf;
2954         struct vnode *vp = NULL;
2955         struct vattr at;
2956         nfsfh_t nfh;
2957         fhandle_t *fhp;
2958         struct uio io;
2959         struct iovec iv;
2960         int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2961         int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies;
2962         int v3 = (nfsd->nd_flag & ND_NFSV3);
2963         u_quad_t frev, off, toff, verf;
2964         u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */
2965
2966         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2967         fhp = &nfh.fh_generic;
2968         nfsm_srvmtofh(fhp);
2969         if (v3) {
2970                 nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2971                 toff = fxdr_hyper(tl);
2972                 tl += 2;
2973                 verf = fxdr_hyper(tl);
2974                 tl += 2;
2975         } else {
2976                 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2977                 toff = fxdr_unsigned(u_quad_t, *tl++);
2978                 verf = 0;       /* shut up gcc */
2979         }
2980         off = toff;
2981         cnt = fxdr_unsigned(int, *tl);
2982         siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2983         xfer = NFS_SRVMAXDATA(nfsd);
2984         if (cnt > xfer)
2985                 cnt = xfer;
2986         if (siz > xfer)
2987                 siz = xfer;
2988         fullsiz = siz;
2989         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2990                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
2991         if (!error && vp->v_type != VDIR) {
2992                 error = ENOTDIR;
2993                 vput(vp);
2994                 vp = NULL;
2995         }
2996         if (error) {
2997                 nfsm_reply(NFSX_UNSIGNED);
2998                 nfsm_srvpostop_attr(getret, &at);
2999                 error = 0;
3000                 goto nfsmout;
3001         }
3002
3003         /*
3004          * Obtain lock on vnode for this section of the code
3005          */
3006
3007         nqsrv_getl(vp, ND_READ);
3008         if (v3) {
3009                 error = getret = VOP_GETATTR(vp, &at, td);
3010 #if 0
3011                 /*
3012                  * XXX This check may be too strict for Solaris 2.5 clients.
3013                  */
3014                 if (!error && toff && verf && verf != at.va_filerev)
3015                         error = NFSERR_BAD_COOKIE;
3016 #endif
3017         }
3018         if (!error)
3019                 error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0);
3020         if (error) {
3021                 vput(vp);
3022                 vp = NULL;
3023                 nfsm_reply(NFSX_POSTOPATTR(v3));
3024                 nfsm_srvpostop_attr(getret, &at);
3025                 error = 0;
3026                 goto nfsmout;
3027         }
3028         VOP_UNLOCK(vp, 0, td);
3029
3030         /*
3031          * end section.  Allocate rbuf and continue
3032          */
3033         MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
3034 again:
3035         iv.iov_base = rbuf;
3036         iv.iov_len = fullsiz;
3037         io.uio_iov = &iv;
3038         io.uio_iovcnt = 1;
3039         io.uio_offset = (off_t)off;
3040         io.uio_resid = fullsiz;
3041         io.uio_segflg = UIO_SYSSPACE;
3042         io.uio_rw = UIO_READ;
3043         io.uio_td = NULL;
3044         eofflag = 0;
3045         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3046         if (cookies) {
3047                 free((caddr_t)cookies, M_TEMP);
3048                 cookies = NULL;
3049         }
3050         error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
3051         off = (off_t)io.uio_offset;
3052         if (!cookies && !error)
3053                 error = NFSERR_PERM;
3054         if (v3) {
3055                 getret = VOP_GETATTR(vp, &at, td);
3056                 if (!error)
3057                         error = getret;
3058         }
3059         VOP_UNLOCK(vp, 0, td);
3060         if (error) {
3061                 vrele(vp);
3062                 vp = NULL;
3063                 free((caddr_t)rbuf, M_TEMP);
3064                 if (cookies)
3065                         free((caddr_t)cookies, M_TEMP);
3066                 nfsm_reply(NFSX_POSTOPATTR(v3));
3067                 nfsm_srvpostop_attr(getret, &at);
3068                 error = 0;
3069                 goto nfsmout;
3070         }
3071         if (io.uio_resid) {
3072                 siz -= io.uio_resid;
3073
3074                 /*
3075                  * If nothing read, return eof
3076                  * rpc reply
3077                  */
3078                 if (siz == 0) {
3079                         vrele(vp);
3080                         vp = NULL;
3081                         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
3082                                 2 * NFSX_UNSIGNED);
3083                         if (v3) {
3084                                 nfsm_srvpostop_attr(getret, &at);
3085                                 nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
3086                                 txdr_hyper(at.va_filerev, tl);
3087                                 tl += 2;
3088                         } else
3089                                 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3090                         *tl++ = nfs_false;
3091                         *tl = nfs_true;
3092                         FREE((caddr_t)rbuf, M_TEMP);
3093                         FREE((caddr_t)cookies, M_TEMP);
3094                         error = 0;
3095                         goto nfsmout;
3096                 }
3097         }
3098
3099         /*
3100          * Check for degenerate cases of nothing useful read.
3101          * If so go try again
3102          */
3103         cpos = rbuf;
3104         cend = rbuf + siz;
3105         dp = (struct dirent *)cpos;
3106         cookiep = cookies;
3107         /*
3108          * For some reason FreeBSD's ufs_readdir() chooses to back the
3109          * directory offset up to a block boundary, so it is necessary to
3110          * skip over the records that preceed the requested offset. This
3111          * requires the assumption that file offset cookies monotonically
3112          * increase.
3113          */
3114         while (cpos < cend && ncookies > 0 &&
3115                 (dp->d_fileno == 0 || dp->d_type == DT_WHT ||
3116                  ((u_quad_t)(*cookiep)) <= toff)) {
3117                 cpos += dp->d_reclen;
3118                 dp = (struct dirent *)cpos;
3119                 cookiep++;
3120                 ncookies--;
3121         }
3122         if (cpos >= cend || ncookies == 0) {
3123                 toff = off;
3124                 siz = fullsiz;
3125                 goto again;
3126         }
3127
3128         len = 3 * NFSX_UNSIGNED;        /* paranoia, probably can be 0 */
3129         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
3130         if (v3) {
3131                 nfsm_srvpostop_attr(getret, &at);
3132                 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3133                 txdr_hyper(at.va_filerev, tl);
3134         }
3135         mp = mp2 = mb;
3136         bp = bpos;
3137         be = bp + M_TRAILINGSPACE(mp);
3138
3139         /* Loop through the records and build reply */
3140         while (cpos < cend && ncookies > 0) {
3141                 if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
3142                         nlen = dp->d_namlen;
3143                         rem = nfsm_rndup(nlen) - nlen;
3144                         len += (4 * NFSX_UNSIGNED + nlen + rem);
3145                         if (v3)
3146                                 len += 2 * NFSX_UNSIGNED;
3147                         if (len > cnt) {
3148                                 eofflag = 0;
3149                                 break;
3150                         }
3151                         /*
3152                          * Build the directory record xdr from
3153                          * the dirent entry.
3154                          */
3155                         nfsm_clget;
3156                         *tl = nfs_true;
3157                         bp += NFSX_UNSIGNED;
3158                         if (v3) {
3159                                 nfsm_clget;
3160                                 *tl = 0;
3161                                 bp += NFSX_UNSIGNED;
3162                         }
3163                         nfsm_clget;
3164                         *tl = txdr_unsigned(dp->d_fileno);
3165                         bp += NFSX_UNSIGNED;
3166                         nfsm_clget;
3167                         *tl = txdr_unsigned(nlen);
3168                         bp += NFSX_UNSIGNED;
3169
3170                         /* And loop around copying the name */
3171                         xfer = nlen;
3172                         cp = dp->d_name;
3173                         while (xfer > 0) {
3174                                 nfsm_clget;
3175                                 if ((bp+xfer) > be)
3176                                         tsiz = be-bp;
3177                                 else
3178                                         tsiz = xfer;
3179                                 bcopy(cp, bp, tsiz);
3180                                 bp += tsiz;
3181                                 xfer -= tsiz;
3182                                 if (xfer > 0)
3183                                         cp += tsiz;
3184                         }
3185                         /* And null pad to a int32_t boundary */
3186                         for (i = 0; i < rem; i++)
3187                                 *bp++ = '\0';
3188                         nfsm_clget;
3189
3190                         /* Finish off the record */
3191                         if (v3) {
3192                                 *tl = 0;
3193                                 bp += NFSX_UNSIGNED;
3194                                 nfsm_clget;
3195                         }
3196                         *tl = txdr_unsigned(*cookiep);
3197                         bp += NFSX_UNSIGNED;
3198                 }
3199                 cpos += dp->d_reclen;
3200                 dp = (struct dirent *)cpos;
3201                 cookiep++;
3202                 ncookies--;
3203         }
3204         vrele(vp);
3205         vp = NULL;
3206         nfsm_clget;
3207         *tl = nfs_false;
3208         bp += NFSX_UNSIGNED;
3209         nfsm_clget;
3210         if (eofflag)
3211                 *tl = nfs_true;
3212         else
3213                 *tl = nfs_false;
3214         bp += NFSX_UNSIGNED;
3215         if (mp != mb) {
3216                 if (bp < be)
3217                         mp->m_len = bp - mtod(mp, caddr_t);
3218         } else
3219                 mp->m_len += bp - bpos;
3220         FREE((caddr_t)rbuf, M_TEMP);
3221         FREE((caddr_t)cookies, M_TEMP);
3222
3223 nfsmout:
3224         if (vp)
3225                 vrele(vp);
3226         return(error);
3227 }
3228
3229 int
3230 nfsrv_readdirplus(nfsd, slp, td, mrq)
3231         struct nfsrv_descript *nfsd;
3232         struct nfssvc_sock *slp;
3233         struct thread *td;
3234         struct mbuf **mrq;
3235 {
3236         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3237         struct sockaddr *nam = nfsd->nd_nam;
3238         caddr_t dpos = nfsd->nd_dpos;
3239         struct ucred *cred = &nfsd->nd_cr;
3240         char *bp, *be;
3241         struct mbuf *mp;
3242         struct dirent *dp;
3243         caddr_t cp;
3244         u_int32_t *tl;
3245         int32_t t1;
3246         caddr_t bpos;
3247         struct mbuf *mb, *mb2, *mreq, *mp2;
3248         char *cpos, *cend, *cp2, *rbuf;
3249         struct vnode *vp = NULL, *nvp;
3250         struct flrep fl;
3251         nfsfh_t nfh;
3252         fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
3253         struct uio io;
3254         struct iovec iv;
3255         struct vattr va, at, *vap = &va;
3256         struct nfs_fattr *fp;
3257         int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
3258         int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies;
3259         u_quad_t frev, off, toff, verf;
3260         u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */
3261
3262         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3263         fhp = &nfh.fh_generic;
3264         nfsm_srvmtofh(fhp);
3265         nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3266         toff = fxdr_hyper(tl);
3267         tl += 2;
3268         verf = fxdr_hyper(tl);
3269         tl += 2;
3270         siz = fxdr_unsigned(int, *tl++);
3271         cnt = fxdr_unsigned(int, *tl);
3272         off = toff;
3273         siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
3274         xfer = NFS_SRVMAXDATA(nfsd);
3275         if (cnt > xfer)
3276                 cnt = xfer;
3277         if (siz > xfer)
3278                 siz = xfer;
3279         fullsiz = siz;
3280         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3281                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3282         if (!error && vp->v_type != VDIR) {
3283                 error = ENOTDIR;
3284                 vput(vp);
3285                 vp = NULL;
3286         }
3287         if (error) {
3288                 nfsm_reply(NFSX_UNSIGNED);
3289                 nfsm_srvpostop_attr(getret, &at);
3290                 error = 0;
3291                 goto nfsmout;
3292         }
3293         error = getret = VOP_GETATTR(vp, &at, td);
3294 #if 0
3295         /*
3296          * XXX This check may be too strict for Solaris 2.5 clients.
3297          */
3298         if (!error && toff && verf && verf != at.va_filerev)
3299                 error = NFSERR_BAD_COOKIE;
3300 #endif
3301         if (!error) {
3302                 nqsrv_getl(vp, ND_READ);
3303                 error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0);
3304         }
3305         if (error) {
3306                 vput(vp);
3307                 vp = NULL;
3308                 nfsm_reply(NFSX_V3POSTOPATTR);
3309                 nfsm_srvpostop_attr(getret, &at);
3310                 error = 0;
3311                 goto nfsmout;
3312         }
3313         VOP_UNLOCK(vp, 0, td);
3314         MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
3315 again:
3316         iv.iov_base = rbuf;
3317         iv.iov_len = fullsiz;
3318         io.uio_iov = &iv;
3319         io.uio_iovcnt = 1;
3320         io.uio_offset = (off_t)off;
3321         io.uio_resid = fullsiz;
3322         io.uio_segflg = UIO_SYSSPACE;
3323         io.uio_rw = UIO_READ;
3324         io.uio_td = NULL;
3325         eofflag = 0;
3326         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3327         if (cookies) {
3328                 free((caddr_t)cookies, M_TEMP);
3329                 cookies = NULL;
3330         }
3331         error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
3332         off = (u_quad_t)io.uio_offset;
3333         getret = VOP_GETATTR(vp, &at, td);
3334         VOP_UNLOCK(vp, 0, td);
3335         if (!cookies && !error)
3336                 error = NFSERR_PERM;
3337         if (!error)
3338                 error = getret;
3339         if (error) {
3340                 vrele(vp);
3341                 vp = NULL;
3342                 if (cookies)
3343                         free((caddr_t)cookies, M_TEMP);
3344                 free((caddr_t)rbuf, M_TEMP);
3345                 nfsm_reply(NFSX_V3POSTOPATTR);
3346                 nfsm_srvpostop_attr(getret, &at);
3347                 error = 0;
3348                 goto nfsmout;
3349         }
3350         if (io.uio_resid) {
3351                 siz -= io.uio_resid;
3352
3353                 /*
3354                  * If nothing read, return eof
3355                  * rpc reply
3356                  */
3357                 if (siz == 0) {
3358                         vrele(vp);
3359                         vp = NULL;
3360                         nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
3361                                 2 * NFSX_UNSIGNED);
3362                         nfsm_srvpostop_attr(getret, &at);
3363                         nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
3364                         txdr_hyper(at.va_filerev, tl);
3365                         tl += 2;
3366                         *tl++ = nfs_false;
3367                         *tl = nfs_true;
3368                         FREE((caddr_t)cookies, M_TEMP);
3369                         FREE((caddr_t)rbuf, M_TEMP);
3370                         error = 0;
3371                         goto nfsmout;
3372                 }
3373         }
3374
3375         /*
3376          * Check for degenerate cases of nothing useful read.
3377          * If so go try again
3378          */
3379         cpos = rbuf;
3380         cend = rbuf + siz;
3381         dp = (struct dirent *)cpos;
3382         cookiep = cookies;
3383         /*
3384          * For some reason FreeBSD's ufs_readdir() chooses to back the
3385          * directory offset up to a block boundary, so it is necessary to
3386          * skip over the records that preceed the requested offset. This
3387          * requires the assumption that file offset cookies monotonically
3388          * increase.
3389          */
3390         while (cpos < cend && ncookies > 0 &&
3391                 (dp->d_fileno == 0 || dp->d_type == DT_WHT ||
3392                  ((u_quad_t)(*cookiep)) <= toff)) {
3393                 cpos += dp->d_reclen;
3394                 dp = (struct dirent *)cpos;
3395                 cookiep++;
3396                 ncookies--;
3397         }
3398         if (cpos >= cend || ncookies == 0) {
3399                 toff = off;
3400                 siz = fullsiz;
3401                 goto again;
3402         }
3403
3404         /*
3405          * Probe one of the directory entries to see if the filesystem
3406          * supports VGET.
3407          */
3408         if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp) == EOPNOTSUPP) {
3409                 error = NFSERR_NOTSUPP;
3410                 vrele(vp);
3411                 vp = NULL;
3412                 free((caddr_t)cookies, M_TEMP);
3413                 free((caddr_t)rbuf, M_TEMP);
3414                 nfsm_reply(NFSX_V3POSTOPATTR);
3415                 nfsm_srvpostop_attr(getret, &at);
3416                 error = 0;
3417                 goto nfsmout;
3418         }
3419         vput(nvp);
3420         nvp = NULL;
3421             
3422         dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
3423         nfsm_reply(cnt);
3424         nfsm_srvpostop_attr(getret, &at);
3425         nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3426         txdr_hyper(at.va_filerev, tl);
3427         mp = mp2 = mb;
3428         bp = bpos;
3429         be = bp + M_TRAILINGSPACE(mp);
3430
3431         /* Loop through the records and build reply */
3432         while (cpos < cend && ncookies > 0) {
3433                 if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
3434                         nlen = dp->d_namlen;
3435                         rem = nfsm_rndup(nlen)-nlen;
3436
3437                         /*
3438                          * For readdir_and_lookup get the vnode using
3439                          * the file number.
3440                          */
3441                         if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
3442                                 goto invalid;
3443                         bzero((caddr_t)nfhp, NFSX_V3FH);
3444                         nfhp->fh_fsid =
3445                                 nvp->v_mount->mnt_stat.f_fsid;
3446                         if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
3447                                 vput(nvp);
3448                                 nvp = NULL;
3449                                 goto invalid;
3450                         }
3451                         if (VOP_GETATTR(nvp, vap, td)) {
3452                                 vput(nvp);
3453                                 nvp = NULL;
3454                                 goto invalid;
3455                         }
3456                         vput(nvp);
3457                         nvp = NULL;
3458
3459                         /*
3460                          * If either the dircount or maxcount will be
3461                          * exceeded, get out now. Both of these lengths
3462                          * are calculated conservatively, including all
3463                          * XDR overheads.
3464                          */
3465                         len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
3466                                 NFSX_V3POSTOPATTR);
3467                         dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
3468                         if (len > cnt || dirlen > fullsiz) {
3469                                 eofflag = 0;
3470                                 break;
3471                         }
3472
3473                         /*
3474                          * Build the directory record xdr from
3475                          * the dirent entry.
3476                          */
3477                         fp = (struct nfs_fattr *)&fl.fl_fattr;
3478                         nfsm_srvfillattr(vap, fp);
3479                         fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
3480                         fl.fl_fhok = nfs_true;
3481                         fl.fl_postopok = nfs_true;
3482                         fl.fl_off.nfsuquad[0] = 0;
3483                         fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
3484
3485                         nfsm_clget;
3486                         *tl = nfs_true;
3487                         bp += NFSX_UNSIGNED;
3488                         nfsm_clget;
3489                         *tl = 0;
3490                         bp += NFSX_UNSIGNED;
3491                         nfsm_clget;
3492                         *tl = txdr_unsigned(dp->d_fileno);
3493                         bp += NFSX_UNSIGNED;
3494                         nfsm_clget;
3495                         *tl = txdr_unsigned(nlen);
3496                         bp += NFSX_UNSIGNED;
3497
3498                         /* And loop around copying the name */
3499                         xfer = nlen;
3500                         cp = dp->d_name;
3501                         while (xfer > 0) {
3502                                 nfsm_clget;
3503                                 if ((bp + xfer) > be)
3504                                         tsiz = be - bp;
3505                                 else
3506                                         tsiz = xfer;
3507                                 bcopy(cp, bp, tsiz);
3508                                 bp += tsiz;
3509                                 xfer -= tsiz;
3510                                 if (xfer > 0)
3511                                         cp += tsiz;
3512                         }
3513                         /* And null pad to a int32_t boundary */
3514                         for (i = 0; i < rem; i++)
3515                                 *bp++ = '\0';
3516         
3517                         /*
3518                          * Now copy the flrep structure out.
3519                          */
3520                         xfer = sizeof (struct flrep);
3521                         cp = (caddr_t)&fl;
3522                         while (xfer > 0) {
3523                                 nfsm_clget;
3524                                 if ((bp + xfer) > be)
3525                                         tsiz = be - bp;
3526                                 else
3527                                         tsiz = xfer;
3528                                 bcopy(cp, bp, tsiz);
3529                                 bp += tsiz;
3530                                 xfer -= tsiz;
3531                                 if (xfer > 0)
3532                                         cp += tsiz;
3533                         }
3534                 }
3535 invalid:
3536                 cpos += dp->d_reclen;
3537                 dp = (struct dirent *)cpos;
3538                 cookiep++;
3539                 ncookies--;
3540         }
3541         vrele(vp);
3542         vp = NULL;
3543         nfsm_clget;
3544         *tl = nfs_false;
3545         bp += NFSX_UNSIGNED;
3546         nfsm_clget;
3547         if (eofflag)
3548                 *tl = nfs_true;
3549         else
3550                 *tl = nfs_false;
3551         bp += NFSX_UNSIGNED;
3552         if (mp != mb) {
3553                 if (bp < be)
3554                         mp->m_len = bp - mtod(mp, caddr_t);
3555         } else
3556                 mp->m_len += bp - bpos;
3557         FREE((caddr_t)cookies, M_TEMP);
3558         FREE((caddr_t)rbuf, M_TEMP);
3559 nfsmout:
3560         if (vp)
3561                 vrele(vp);
3562         return(error);
3563 }
3564
3565 /*
3566  * nfs commit service
3567  */
3568 int
3569 nfsrv_commit(nfsd, slp, td, mrq)
3570         struct nfsrv_descript *nfsd;
3571         struct nfssvc_sock *slp;
3572         struct thread *td;
3573         struct mbuf **mrq;
3574 {
3575         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3576         struct sockaddr *nam = nfsd->nd_nam;
3577         caddr_t dpos = nfsd->nd_dpos;
3578         struct ucred *cred = &nfsd->nd_cr;
3579         struct vattr bfor, aft;
3580         struct vnode *vp = NULL;
3581         nfsfh_t nfh;
3582         fhandle_t *fhp;
3583         u_int32_t *tl;
3584         int32_t t1;
3585         caddr_t bpos;
3586         int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache;
3587         char *cp2;
3588         struct mbuf *mb, *mb2, *mreq;
3589         u_quad_t frev, off;
3590
3591         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3592 #ifndef nolint
3593         cache = 0;
3594 #endif
3595         fhp = &nfh.fh_generic;
3596         nfsm_srvmtofh(fhp);
3597         nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3598
3599         /*
3600          * XXX At this time VOP_FSYNC() does not accept offset and byte
3601          * count parameters, so these arguments are useless (someday maybe).
3602          */
3603         off = fxdr_hyper(tl);
3604         tl += 2;
3605         cnt = fxdr_unsigned(int, *tl);
3606         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3607                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3608         if (error) {
3609                 nfsm_reply(2 * NFSX_UNSIGNED);
3610                 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3611                 error = 0;
3612                 goto nfsmout;
3613         }
3614         for_ret = VOP_GETATTR(vp, &bfor, td);
3615
3616         if (cnt > MAX_COMMIT_COUNT) {
3617                 /*
3618                  * Give up and do the whole thing
3619                  */
3620                 if (vp->v_object &&
3621                    (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
3622                         vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC);
3623                 }
3624                 error = VOP_FSYNC(vp, MNT_WAIT, td);
3625         } else {
3626                 /*
3627                  * Locate and synchronously write any buffers that fall
3628                  * into the requested range.  Note:  we are assuming that
3629                  * f_iosize is a power of 2.
3630                  */
3631                 int iosize = vp->v_mount->mnt_stat.f_iosize;
3632                 int iomask = iosize - 1;
3633                 int s;
3634                 daddr_t lblkno;
3635
3636                 /*
3637                  * Align to iosize boundry, super-align to page boundry.
3638                  */
3639                 if (off & iomask) {
3640                         cnt += off & iomask;
3641                         off &= ~(u_quad_t)iomask;
3642                 }
3643                 if (off & PAGE_MASK) {
3644                         cnt += off & PAGE_MASK;
3645                         off &= ~(u_quad_t)PAGE_MASK;
3646                 }
3647                 lblkno = off / iosize;
3648
3649                 if (vp->v_object &&
3650                    (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
3651                         vm_object_page_clean(vp->v_object, off / PAGE_SIZE, (cnt + PAGE_MASK) / PAGE_SIZE, OBJPC_SYNC);
3652                 }
3653
3654                 s = splbio();
3655                 while (cnt > 0) {
3656                         struct buf *bp;
3657
3658                         /*
3659                          * If we have a buffer and it is marked B_DELWRI we
3660                          * have to lock and write it.  Otherwise the prior
3661                          * write is assumed to have already been committed.
3662                          */
3663                         if ((bp = gbincore(vp, lblkno)) != NULL && (bp->b_flags & B_DELWRI)) {
3664                                 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
3665                                         BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL);
3666                                         continue; /* retry */
3667                                 }
3668                                 bremfree(bp);
3669                                 bp->b_flags &= ~B_ASYNC;
3670                                 VOP_BWRITE(bp->b_vp, bp);
3671                                 ++nfs_commit_miss;
3672                         }
3673                         ++nfs_commit_blks;
3674                         if (cnt < iosize)
3675                                 break;
3676                         cnt -= iosize;
3677                         ++lblkno;
3678                 }
3679                 splx(s);
3680         }
3681
3682         aft_ret = VOP_GETATTR(vp, &aft, td);
3683         vput(vp);
3684         vp = NULL;
3685         nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
3686         nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3687         if (!error) {
3688                 nfsm_build(tl, u_int32_t *, NFSX_V3WRITEVERF);
3689                 if (nfsver.tv_sec == 0)
3690                         nfsver = boottime;
3691                 *tl++ = txdr_unsigned(nfsver.tv_sec);
3692                 *tl = txdr_unsigned(nfsver.tv_usec);
3693         } else {
3694                 error = 0;
3695         }
3696 nfsmout:
3697         if (vp)
3698                 vput(vp);
3699         return(error);
3700 }
3701
3702 /*
3703  * nfs statfs service
3704  */
3705 int
3706 nfsrv_statfs(nfsd, slp, td, mrq)
3707         struct nfsrv_descript *nfsd;
3708         struct nfssvc_sock *slp;
3709         struct thread *td;
3710         struct mbuf **mrq;
3711 {
3712         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3713         struct sockaddr *nam = nfsd->nd_nam;
3714         caddr_t dpos = nfsd->nd_dpos;
3715         struct ucred *cred = &nfsd->nd_cr;
3716         struct statfs *sf;
3717         struct nfs_statfs *sfp;
3718         u_int32_t *tl;
3719         int32_t t1;
3720         caddr_t bpos;
3721         int error = 0, rdonly, cache, getret = 1;
3722         int v3 = (nfsd->nd_flag & ND_NFSV3);
3723         char *cp2;
3724         struct mbuf *mb, *mb2, *mreq;
3725         struct vnode *vp = NULL;
3726         struct vattr at;
3727         nfsfh_t nfh;
3728         fhandle_t *fhp;
3729         struct statfs statfs;
3730         u_quad_t frev, tval;
3731
3732         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3733 #ifndef nolint
3734         cache = 0;
3735 #endif
3736         fhp = &nfh.fh_generic;
3737         nfsm_srvmtofh(fhp);
3738         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3739                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3740         if (error) {
3741                 nfsm_reply(NFSX_UNSIGNED);
3742                 nfsm_srvpostop_attr(getret, &at);
3743                 error = 0;
3744                 goto nfsmout;
3745         }
3746         sf = &statfs;
3747         error = VFS_STATFS(vp->v_mount, sf, td);
3748         getret = VOP_GETATTR(vp, &at, td);
3749         vput(vp);
3750         vp = NULL;
3751         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
3752         if (v3)
3753                 nfsm_srvpostop_attr(getret, &at);
3754         if (error) {
3755                 error = 0;
3756                 goto nfsmout;
3757         }
3758         nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
3759         if (v3) {
3760                 tval = (u_quad_t)sf->f_blocks;
3761                 tval *= (u_quad_t)sf->f_bsize;
3762                 txdr_hyper(tval, &sfp->sf_tbytes);
3763                 tval = (u_quad_t)sf->f_bfree;
3764                 tval *= (u_quad_t)sf->f_bsize;
3765                 txdr_hyper(tval, &sfp->sf_fbytes);
3766                 tval = (u_quad_t)sf->f_bavail;
3767                 tval *= (u_quad_t)sf->f_bsize;
3768                 txdr_hyper(tval, &sfp->sf_abytes);
3769                 sfp->sf_tfiles.nfsuquad[0] = 0;
3770                 sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
3771                 sfp->sf_ffiles.nfsuquad[0] = 0;
3772                 sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3773                 sfp->sf_afiles.nfsuquad[0] = 0;
3774                 sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3775                 sfp->sf_invarsec = 0;
3776         } else {
3777                 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
3778                 sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
3779                 sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
3780                 sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
3781                 sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
3782         }
3783 nfsmout:
3784         if (vp)
3785                 vput(vp);
3786         return(error);
3787 }
3788
3789 /*
3790  * nfs fsinfo service
3791  */
3792 int
3793 nfsrv_fsinfo(nfsd, slp, td, mrq)
3794         struct nfsrv_descript *nfsd;
3795         struct nfssvc_sock *slp;
3796         struct thread *td;
3797         struct mbuf **mrq;
3798 {
3799         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3800         struct sockaddr *nam = nfsd->nd_nam;
3801         caddr_t dpos = nfsd->nd_dpos;
3802         struct ucred *cred = &nfsd->nd_cr;
3803         u_int32_t *tl;
3804         struct nfsv3_fsinfo *sip;
3805         int32_t t1;
3806         caddr_t bpos;
3807         int error = 0, rdonly, cache, getret = 1, pref;
3808         char *cp2;
3809         struct mbuf *mb, *mb2, *mreq;
3810         struct vnode *vp = NULL;
3811         struct vattr at;
3812         nfsfh_t nfh;
3813         fhandle_t *fhp;
3814         u_quad_t frev, maxfsize;
3815         struct statfs sb;
3816
3817         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3818 #ifndef nolint
3819         cache = 0;
3820 #endif
3821         fhp = &nfh.fh_generic;
3822         nfsm_srvmtofh(fhp);
3823         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3824                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3825         if (error) {
3826                 nfsm_reply(NFSX_UNSIGNED);
3827                 nfsm_srvpostop_attr(getret, &at);
3828                 error = 0;
3829                 goto nfsmout;
3830         }
3831
3832         /* XXX Try to make a guess on the max file size. */
3833         VFS_STATFS(vp->v_mount, &sb, td);
3834         maxfsize = (u_quad_t)0x80000000 * sb.f_bsize - 1;
3835
3836         getret = VOP_GETATTR(vp, &at, td);
3837         vput(vp);
3838         vp = NULL;
3839         nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
3840         nfsm_srvpostop_attr(getret, &at);
3841         nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
3842
3843         /*
3844          * XXX
3845          * There should be file system VFS OP(s) to get this information.
3846          * For now, assume ufs.
3847          */
3848         if (slp->ns_so->so_type == SOCK_DGRAM)
3849                 pref = NFS_MAXDGRAMDATA;
3850         else
3851                 pref = NFS_MAXDATA;
3852         sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
3853         sip->fs_rtpref = txdr_unsigned(pref);
3854         sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3855         sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
3856         sip->fs_wtpref = txdr_unsigned(pref);
3857         sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3858         sip->fs_dtpref = txdr_unsigned(pref);
3859         txdr_hyper(maxfsize, &sip->fs_maxfilesize);
3860         sip->fs_timedelta.nfsv3_sec = 0;
3861         sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3862         sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3863                 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3864                 NFSV3FSINFO_CANSETTIME);
3865 nfsmout:
3866         if (vp)
3867                 vput(vp);
3868         return(error);
3869 }
3870
3871 /*
3872  * nfs pathconf service
3873  */
3874 int
3875 nfsrv_pathconf(nfsd, slp, td, mrq)
3876         struct nfsrv_descript *nfsd;
3877         struct nfssvc_sock *slp;
3878         struct thread *td;
3879         struct mbuf **mrq;
3880 {
3881         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3882         struct sockaddr *nam = nfsd->nd_nam;
3883         caddr_t dpos = nfsd->nd_dpos;
3884         struct ucred *cred = &nfsd->nd_cr;
3885         u_int32_t *tl;
3886         struct nfsv3_pathconf *pc;
3887         int32_t t1;
3888         caddr_t bpos;
3889         int error = 0, rdonly, cache, getret = 1;
3890         register_t linkmax, namemax, chownres, notrunc;
3891         char *cp2;
3892         struct mbuf *mb, *mb2, *mreq;
3893         struct vnode *vp = NULL;
3894         struct vattr at;
3895         nfsfh_t nfh;
3896         fhandle_t *fhp;
3897         u_quad_t frev;
3898
3899         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3900 #ifndef nolint
3901         cache = 0;
3902 #endif
3903         fhp = &nfh.fh_generic;
3904         nfsm_srvmtofh(fhp);
3905         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3906                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3907         if (error) {
3908                 nfsm_reply(NFSX_UNSIGNED);
3909                 nfsm_srvpostop_attr(getret, &at);
3910                 error = 0;
3911                 goto nfsmout;