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