Change mbug allocation flags from M_ to MB_ to avoid confusion with malloc
[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.16 2004/06/02 14:43:04 eirikn Exp $
39  */
40
41 /*
42  * nfs version 2 and 3 server calls to vnode ops
43  * - these routines generally have 3 phases
44  *   1 - break down and validate rpc request in mbuf list
45  *   2 - do the vnode ops for the request
46  *       (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
47  *   3 - build the rpc reply in an mbuf list
48  *   nb:
49  *      - do not mix the phases, since the nfsm_?? macros can return failures
50  *        on a bad rpc or similar and do not do any vrele() or vput()'s
51  *
52  *      - the nfsm_reply() macro generates an nfs rpc reply with the nfs
53  *      error number iff error != 0 whereas
54  *      returning an error from the server function implies a fatal error
55  *      such as a badly constructed rpc request that should be dropped without
56  *      a reply.
57  *      For Version 3, nfsm_reply() does not return for the error case, since
58  *      most version 3 rpcs return more than the status for error cases.
59  *
60  * Other notes:
61  *      Warning: always pay careful attention to resource cleanup on return
62  *      and note that nfsm_*() macros can terminate a procedure on certain
63  *      errors.
64  *
65  *      lookup() and namei()
66  *      may return garbage in various structural fields/return elements
67  *      if an error is returned, and may garbage up nd.ni_dvp even if no
68  *      error is returned and you did not request LOCKPARENT or WANTPARENT.
69  *
70  *      We use the ni_cnd.cn_flags 'HASBUF' flag to track whether the name
71  *      buffer has been freed or not.
72  */
73
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/proc.h>
77 #include <sys/namei.h>
78 #include <sys/unistd.h>
79 #include <sys/vnode.h>
80 #include <sys/mount.h>
81 #include <sys/socket.h>
82 #include <sys/socketvar.h>
83 #include <sys/malloc.h>
84 #include <sys/mbuf.h>
85 #include <sys/dirent.h>
86 #include <sys/stat.h>
87 #include <sys/kernel.h>
88 #include <sys/sysctl.h>
89 #include <sys/buf.h>
90
91 #include <vm/vm.h>
92 #include <vm/vm_extern.h>
93 #include <vm/vm_zone.h>
94 #include <vm/vm_object.h>
95
96 #include <sys/buf2.h>
97
98 #include "nfsproto.h"
99 #include "rpcv2.h"
100 #include "nfs.h"
101 #include "xdr_subs.h"
102 #include "nfsm_subs.h"
103 #include "nqnfs.h"
104
105 #ifdef NFSRV_DEBUG
106 #define nfsdbprintf(info)       printf info
107 #else
108 #define nfsdbprintf(info)
109 #endif
110
111 #define MAX_COMMIT_COUNT        (1024 * 1024)
112
113 #define NUM_HEURISTIC           64
114 #define NHUSE_INIT              64
115 #define NHUSE_INC               16
116 #define NHUSE_MAX               2048
117
118 static struct nfsheur {
119     struct vnode *nh_vp;        /* vp to match (unreferenced pointer) */
120     off_t nh_nextr;             /* next offset for sequential detection */
121     int nh_use;                 /* use count for selection */
122     int nh_seqcount;            /* heuristic */
123 } nfsheur[NUM_HEURISTIC];
124
125 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
126                       NFFIFO, NFNON };
127 #ifndef NFS_NOSERVER 
128 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
129                       NFCHR, NFNON };
130 /* Global vars */
131 extern u_int32_t nfs_xdrneg1;
132 extern u_int32_t nfs_false, nfs_true;
133 extern enum vtype nv3tov_type[8];
134 extern struct nfsstats nfsstats;
135
136 int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
137 int nfsrvw_procrastinate_v3 = 0;
138
139 static struct timespec  nfsver;
140
141 SYSCTL_DECL(_vfs_nfs);
142
143 static int nfs_async;
144 SYSCTL_INT(_vfs_nfs, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, "");
145 static int nfs_commit_blks;
146 static int nfs_commit_miss;
147 SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks, 0, "");
148 SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss, 0, "");
149
150 static int nfsrv_access (struct vnode *,int,struct ucred *,int,
151                 struct thread *, int);
152 static void nfsrvw_coalesce (struct nfsrv_descript *,
153                 struct nfsrv_descript *);
154
155 /*
156  * Clear nameidata fields that are tested in nsfmout cleanup code prior
157  * to using first nfsm macro (that might jump to the cleanup code).
158  */
159
160 static __inline 
161 void
162 ndclear(struct nameidata *nd)
163 {
164         nd->ni_cnd.cn_flags = 0;
165         nd->ni_vp = NULL;
166         nd->ni_dvp = NULL;
167         nd->ni_startdir = NULL;
168 }
169
170 /*
171  * nfs v3 access service
172  */
173 int
174 nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
175               struct thread *td, struct mbuf **mrq)
176 {
177         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
178         struct sockaddr *nam = nfsd->nd_nam;
179         caddr_t dpos = nfsd->nd_dpos;
180         struct ucred *cred = &nfsd->nd_cr;
181         struct vnode *vp = NULL;
182         nfsfh_t nfh;
183         fhandle_t *fhp;
184         u_int32_t *tl;
185         int32_t t1;
186         caddr_t bpos;
187         int error = 0, rdonly, cache, getret;
188         char *cp2;
189         struct mbuf *mb, *mreq, *mb2;
190         struct vattr vattr, *vap = &vattr;
191         u_long testmode, nfsmode;
192         u_quad_t frev;
193
194         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
195 #ifndef nolint
196         cache = 0;
197 #endif
198         fhp = &nfh.fh_generic;
199         nfsm_srvmtofh(fhp);
200         nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
201         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
202             (nfsd->nd_flag & ND_KERBAUTH), TRUE);
203         if (error) {
204                 nfsm_reply(NFSX_UNSIGNED);
205                 nfsm_srvpostop_attr(1, (struct vattr *)0);
206                 error = 0;
207                 goto nfsmout;
208         }
209         nfsmode = fxdr_unsigned(u_int32_t, *tl);
210         if ((nfsmode & NFSV3ACCESS_READ) &&
211                 nfsrv_access(vp, VREAD, cred, rdonly, td, 0))
212                 nfsmode &= ~NFSV3ACCESS_READ;
213         if (vp->v_type == VDIR)
214                 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
215                         NFSV3ACCESS_DELETE);
216         else
217                 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
218         if ((nfsmode & testmode) &&
219                 nfsrv_access(vp, VWRITE, cred, rdonly, td, 0))
220                 nfsmode &= ~testmode;
221         if (vp->v_type == VDIR)
222                 testmode = NFSV3ACCESS_LOOKUP;
223         else
224                 testmode = NFSV3ACCESS_EXECUTE;
225         if ((nfsmode & testmode) &&
226                 nfsrv_access(vp, VEXEC, cred, rdonly, td, 0))
227                 nfsmode &= ~testmode;
228         getret = VOP_GETATTR(vp, vap, td);
229         vput(vp);
230         vp = NULL;
231         nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
232         nfsm_srvpostop_attr(getret, vap);
233         nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
234         *tl = txdr_unsigned(nfsmode);
235 nfsmout:
236         if (vp)
237                 vput(vp);
238         return(error);
239 }
240
241 /*
242  * nfs getattr service
243  */
244 int
245 nfsrv_getattr(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, NULL, 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 = 4;
845
846                 /*
847                  * Locate best candidate
848                  */
849
850                 hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) & (NUM_HEURISTIC - 1);
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 - 1);
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                         NDFREE(&nd, NDF_ONLY_PNBUF);
2091                 }
2092         }
2093         if (dirp && v3) {
2094                 diraft_ret = VOP_GETATTR(dirp, &diraft, td);
2095                 vrele(dirp);
2096                 dirp = NULL;
2097         }
2098         nfsm_reply(NFSX_WCCDATA(v3));
2099         if (v3) {
2100                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2101                 error = 0;
2102         }
2103 nfsmout:
2104         NDFREE(&nd, NDF_ONLY_PNBUF);
2105         if (nd.ni_dvp) {
2106                 if (nd.ni_dvp == nd.ni_vp)
2107                         vrele(nd.ni_dvp);
2108                 else
2109                         vput(nd.ni_dvp);
2110         }
2111         if (nd.ni_vp)
2112                 vput(nd.ni_vp);
2113         return(error);
2114 }
2115
2116 /*
2117  * nfs rename service
2118  */
2119 int
2120 nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2121              struct thread *td, struct mbuf **mrq)
2122 {
2123         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2124         struct sockaddr *nam = nfsd->nd_nam;
2125         caddr_t dpos = nfsd->nd_dpos;
2126         struct ucred *cred = &nfsd->nd_cr;
2127         u_int32_t *tl;
2128         int32_t t1;
2129         caddr_t bpos;
2130         int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
2131         int tdirfor_ret = 1, tdiraft_ret = 1;
2132         int v3 = (nfsd->nd_flag & ND_NFSV3);
2133         char *cp2;
2134         struct mbuf *mb, *mreq;
2135         struct nameidata fromnd, tond;
2136         struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0;
2137         struct vnode *tdirp = (struct vnode *)0;
2138         struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
2139         nfsfh_t fnfh, tnfh;
2140         fhandle_t *ffhp, *tfhp;
2141         u_quad_t frev;
2142         uid_t saved_uid;
2143
2144         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2145 #ifndef nolint
2146         fvp = (struct vnode *)0;
2147 #endif
2148         ffhp = &fnfh.fh_generic;
2149         tfhp = &tnfh.fh_generic;
2150
2151         /*
2152          * Clear fields incase goto nfsmout occurs from macro.
2153          */
2154
2155         ndclear(&fromnd);
2156         ndclear(&tond);
2157
2158         nfsm_srvmtofh(ffhp);
2159         nfsm_srvnamesiz(len);
2160         /*
2161          * Remember our original uid so that we can reset cr_uid before
2162          * the second nfs_namei() call, in case it is remapped.
2163          */
2164         saved_uid = cred->cr_uid;
2165         fromnd.ni_cnd.cn_cred = cred;
2166         fromnd.ni_cnd.cn_nameiop = NAMEI_DELETE;
2167         fromnd.ni_cnd.cn_flags = CNP_WANTPARENT | CNP_SAVESTART;
2168         error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
2169                 &dpos, &fdirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2170         if (fdirp) {
2171                 if (v3) {
2172                         fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, td);
2173                 } else {
2174                         vrele(fdirp);
2175                         fdirp = NULL;
2176                 }
2177         }
2178         if (error) {
2179                 nfsm_reply(2 * NFSX_WCCDATA(v3));
2180                 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
2181                 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
2182                 error = 0;
2183                 goto nfsmout;
2184         }
2185         fvp = fromnd.ni_vp;
2186         nfsm_srvmtofh(tfhp);
2187         nfsm_strsiz(len2, NFS_MAXNAMLEN);
2188         cred->cr_uid = saved_uid;
2189         tond.ni_cnd.cn_cred = cred;
2190         tond.ni_cnd.cn_nameiop = NAMEI_RENAME;
2191         tond.ni_cnd.cn_flags = CNP_LOCKPARENT | CNP_LOCKLEAF | 
2192                 CNP_NOCACHE | CNP_SAVESTART;
2193         error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
2194                 &dpos, &tdirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2195         if (tdirp) {
2196                 if (v3) {
2197                         tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, td);
2198                 } else {
2199                         vrele(tdirp);
2200                         tdirp = NULL;
2201                 }
2202         }
2203         if (error)
2204                 goto out1;
2205
2206         tdvp = tond.ni_dvp;
2207         tvp = tond.ni_vp;
2208         if (tvp != NULL) {
2209                 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2210                         if (v3)
2211                                 error = EEXIST;
2212                         else
2213                                 error = EISDIR;
2214                         goto out;
2215                 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2216                         if (v3)
2217                                 error = EEXIST;
2218                         else
2219                                 error = ENOTDIR;
2220                         goto out;
2221                 }
2222                 if (tvp->v_type == VDIR && tvp->v_mountedhere) {
2223                         if (v3)
2224                                 error = EXDEV;
2225                         else
2226                                 error = ENOTEMPTY;
2227                         goto out;
2228                 }
2229         }
2230         if (fvp->v_type == VDIR && fvp->v_mountedhere) {
2231                 if (v3)
2232                         error = EXDEV;
2233                 else
2234                         error = ENOTEMPTY;
2235                 goto out;
2236         }
2237         if (fvp->v_mount != tdvp->v_mount) {
2238                 if (v3)
2239                         error = EXDEV;
2240                 else
2241                         error = ENOTEMPTY;
2242                 goto out;
2243         }
2244         if (fvp == tdvp) {
2245                 if (v3)
2246                         error = EINVAL;
2247                 else
2248                         error = ENOTEMPTY;
2249         }
2250         /*
2251          * If source is the same as the destination (that is the
2252          * same vnode with the same name in the same directory),
2253          * then there is nothing to do.
2254          */
2255         if (fvp == tvp && fromnd.ni_dvp == tdvp &&
2256             fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2257             !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2258               fromnd.ni_cnd.cn_namelen))
2259                 error = -1;
2260 out:
2261         if (!error) {
2262                 /*
2263                  * The VOP_RENAME function releases all vnode references &
2264                  * locks prior to returning so we need to clear the pointers
2265                  * to bypass cleanup code later on.
2266                  */
2267                 nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
2268                 nqsrv_getl(tdvp, ND_WRITE);
2269                 if (tvp) {
2270                         nqsrv_getl(tvp, ND_WRITE);
2271                 }
2272                 error = VOP_RENAME(fromnd.ni_dvp, NCPNULL, fromnd.ni_vp, &fromnd.ni_cnd,
2273                                    tond.ni_dvp, NCPNULL, tond.ni_vp, &tond.ni_cnd);
2274                 fromnd.ni_dvp = NULL;
2275                 fromnd.ni_vp = NULL;
2276                 tond.ni_dvp = NULL;
2277                 tond.ni_vp = NULL;
2278                 if (error) {
2279                         fromnd.ni_cnd.cn_flags &= ~CNP_HASBUF;
2280                         tond.ni_cnd.cn_flags &= ~CNP_HASBUF;
2281                 }
2282         } else {
2283                 if (error == -1)
2284                         error = 0;
2285         }
2286         /* fall through */
2287
2288 out1:
2289         if (fdirp)
2290                 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, td);
2291         if (tdirp)
2292                 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, td);
2293         nfsm_reply(2 * NFSX_WCCDATA(v3));
2294         if (v3) {
2295                 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
2296                 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
2297         }
2298         error = 0;
2299         /* fall through */
2300
2301 nfsmout:
2302         /*
2303          * Clear out tond related fields
2304          */
2305         if (tdirp)
2306                 vrele(tdirp);
2307         if (tond.ni_startdir)
2308                 vrele(tond.ni_startdir);
2309         NDFREE(&tond, NDF_ONLY_PNBUF);
2310         if (tond.ni_dvp) {
2311                 if (tond.ni_dvp == tond.ni_vp)
2312                         vrele(tond.ni_dvp);
2313                 else
2314                         vput(tond.ni_dvp);
2315         }
2316         if (tond.ni_vp)
2317                 vput(tond.ni_vp);
2318
2319         /*
2320          * Clear out fromnd related fields
2321          */
2322         if (fdirp)
2323                 vrele(fdirp);
2324         if (fromnd.ni_startdir)
2325                 vrele(fromnd.ni_startdir);
2326         NDFREE(&fromnd, NDF_ONLY_PNBUF);
2327         if (fromnd.ni_dvp)
2328                 vrele(fromnd.ni_dvp);
2329         if (fromnd.ni_vp)
2330                 vrele(fromnd.ni_vp);
2331
2332         return (error);
2333 }
2334
2335 /*
2336  * nfs link service
2337  */
2338 int
2339 nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2340            struct thread *td, struct mbuf **mrq)
2341 {
2342         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2343         struct sockaddr *nam = nfsd->nd_nam;
2344         caddr_t dpos = nfsd->nd_dpos;
2345         struct ucred *cred = &nfsd->nd_cr;
2346         struct nameidata nd;
2347         u_int32_t *tl;
2348         int32_t t1;
2349         caddr_t bpos;
2350         int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1;
2351         int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
2352         char *cp2;
2353         struct mbuf *mb, *mreq;
2354         struct vnode *vp = NULL, *xp, *dirp = (struct vnode *)0;
2355         struct vattr dirfor, diraft, at;
2356         nfsfh_t nfh, dnfh;
2357         fhandle_t *fhp, *dfhp;
2358         u_quad_t frev;
2359
2360         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2361         ndclear(&nd);
2362
2363         fhp = &nfh.fh_generic;
2364         dfhp = &dnfh.fh_generic;
2365         nfsm_srvmtofh(fhp);
2366         nfsm_srvmtofh(dfhp);
2367         nfsm_srvnamesiz(len);
2368
2369         error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
2370                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
2371         if (error) {
2372                 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2373                 nfsm_srvpostop_attr(getret, &at);
2374                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2375                 vp = NULL;
2376                 error = 0;
2377                 goto nfsmout;
2378         }
2379         if (vp->v_type == VDIR) {
2380                 error = EPERM;          /* POSIX */
2381                 goto out1;
2382         }
2383         nd.ni_cnd.cn_cred = cred;
2384         nd.ni_cnd.cn_nameiop = NAMEI_CREATE;
2385         nd.ni_cnd.cn_flags = CNP_LOCKPARENT;
2386         error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
2387                 &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2388         if (dirp) {
2389                 if (v3) {
2390                         dirfor_ret = VOP_GETATTR(dirp, &dirfor, td);
2391                 } else {
2392                         vrele(dirp);
2393                         dirp = NULL;
2394                 }
2395         }
2396         if (error)
2397                 goto out1;
2398
2399         xp = nd.ni_vp;
2400         if (xp != NULL) {
2401                 error = EEXIST;
2402                 goto out;
2403         }
2404         xp = nd.ni_dvp;
2405         if (vp->v_mount != xp->v_mount)
2406                 error = EXDEV;
2407 out:
2408         if (!error) {
2409                 nqsrv_getl(vp, ND_WRITE);
2410                 nqsrv_getl(xp, ND_WRITE);
2411                 error = VOP_LINK(nd.ni_dvp, NCPNULL, vp, &nd.ni_cnd);
2412                 NDFREE(&nd, NDF_ONLY_PNBUF);
2413         }
2414         /* fall through */
2415
2416 out1:
2417         if (v3)
2418                 getret = VOP_GETATTR(vp, &at, td);
2419         if (dirp)
2420                 diraft_ret = VOP_GETATTR(dirp, &diraft, td);
2421         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2422         if (v3) {
2423                 nfsm_srvpostop_attr(getret, &at);
2424                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2425                 error = 0;
2426         }
2427         /* fall through */
2428
2429 nfsmout:
2430         NDFREE(&nd, NDF_ONLY_PNBUF);
2431         if (dirp)
2432                 vrele(dirp);
2433         if (vp)
2434                 vrele(vp);
2435         if (nd.ni_dvp) {
2436                 if (nd.ni_dvp == nd.ni_vp)
2437                         vrele(nd.ni_dvp);
2438                 else
2439                         vput(nd.ni_dvp);
2440         }
2441         if (nd.ni_vp)
2442                 vrele(nd.ni_vp);
2443         return(error);
2444 }
2445
2446 /*
2447  * nfs symbolic link service
2448  */
2449 int
2450 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2451               struct thread *td, struct mbuf **mrq)
2452 {
2453         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2454         struct sockaddr *nam = nfsd->nd_nam;
2455         caddr_t dpos = nfsd->nd_dpos;
2456         struct ucred *cred = &nfsd->nd_cr;
2457         struct vattr va, dirfor, diraft;
2458         struct nameidata nd;
2459         struct vattr *vap = &va;
2460         u_int32_t *tl;
2461         int32_t t1;
2462         struct nfsv2_sattr *sp;
2463         char *bpos, *pathcp = (char *)0, *cp2;
2464         struct uio io;
2465         struct iovec iv;
2466         int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1;
2467         int v3 = (nfsd->nd_flag & ND_NFSV3);
2468         struct mbuf *mb, *mreq, *mb2;
2469         struct vnode *dirp = (struct vnode *)0;
2470         nfsfh_t nfh;
2471         fhandle_t *fhp;
2472         u_quad_t frev;
2473
2474         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2475         ndclear(&nd);
2476
2477         fhp = &nfh.fh_generic;
2478         nfsm_srvmtofh(fhp);
2479         nfsm_srvnamesiz(len);
2480         nd.ni_cnd.cn_cred = cred;
2481         nd.ni_cnd.cn_nameiop = NAMEI_CREATE;
2482         nd.ni_cnd.cn_flags = CNP_LOCKPARENT | CNP_SAVESTART;
2483         error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2484                 &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2485         if (dirp) {
2486                 if (v3) {
2487                         dirfor_ret = VOP_GETATTR(dirp, &dirfor, td);
2488                 } else {
2489                         vrele(dirp);
2490                         dirp = NULL;
2491                 }
2492         }
2493         if (error)
2494                 goto out;
2495
2496         VATTR_NULL(vap);
2497         if (v3)
2498                 nfsm_srvsattr(vap);
2499         nfsm_strsiz(len2, NFS_MAXPATHLEN);
2500         MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
2501         iv.iov_base = pathcp;
2502         iv.iov_len = len2;
2503         io.uio_resid = len2;
2504         io.uio_offset = 0;
2505         io.uio_iov = &iv;
2506         io.uio_iovcnt = 1;
2507         io.uio_segflg = UIO_SYSSPACE;
2508         io.uio_rw = UIO_READ;
2509         io.uio_td = NULL;
2510         nfsm_mtouio(&io, len2);
2511         if (!v3) {
2512                 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2513                 vap->va_mode = nfstov_mode(sp->sa_mode);
2514         }
2515         *(pathcp + len2) = '\0';
2516         if (nd.ni_vp) {
2517                 error = EEXIST;
2518                 goto out;
2519         }
2520
2521         /*
2522          * issue symlink op.  SAVESTART is set so the underlying path component
2523          * is only freed by the VOP if an error occurs.
2524          */
2525         if (vap->va_mode == (mode_t)VNOVAL)
2526                 vap->va_mode = 0;
2527         nqsrv_getl(nd.ni_dvp, ND_WRITE);
2528         error = VOP_SYMLINK(nd.ni_dvp, NCPNULL, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
2529         if (error)
2530                 NDFREE(&nd, NDF_ONLY_PNBUF);
2531         else
2532                 vput(nd.ni_vp);
2533         nd.ni_vp = NULL;
2534         /*
2535          * releases directory prior to potential lookup op.
2536          */
2537         vput(nd.ni_dvp);
2538         nd.ni_dvp = NULL;
2539
2540         if (error == 0) {
2541             if (v3) {
2542                 /*
2543                  * Issue lookup.  Leave SAVESTART set so we can easily free
2544                  * the name buffer later on.
2545                  *
2546                  * since LOCKPARENT is not set, ni_dvp will be garbage on
2547                  * return whether an error occurs or not.
2548                  */
2549                 nd.ni_cnd.cn_nameiop = NAMEI_LOOKUP;
2550                 nd.ni_cnd.cn_flags &= ~(CNP_LOCKPARENT | CNP_FOLLOW);
2551                 nd.ni_cnd.cn_flags |= CNP_LOCKLEAF;
2552                 nd.ni_cnd.cn_td = td;
2553                 nd.ni_cnd.cn_cred = cred;
2554
2555                 error = lookup(&nd);
2556                 nd.ni_dvp = NULL;
2557
2558                 if (error == 0) {
2559                         bzero((caddr_t)fhp, sizeof(nfh));
2560                         fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
2561                         error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
2562                         if (!error)
2563                                 error = VOP_GETATTR(nd.ni_vp, vap, td);
2564                         vput(nd.ni_vp);
2565                         nd.ni_vp = NULL;
2566                 }
2567             }
2568         }
2569 out:
2570         /*
2571          * These releases aren't strictly required, does even doing them
2572          * make any sense? XXX can nfsm_reply() block?
2573          */
2574         if (pathcp) {
2575                 FREE(pathcp, M_TEMP);
2576                 pathcp = NULL;
2577         }
2578         if (dirp) {
2579                 diraft_ret = VOP_GETATTR(dirp, &diraft, td);
2580                 vrele(dirp);
2581                 dirp = NULL;
2582         }
2583         if (nd.ni_startdir) {
2584                 vrele(nd.ni_startdir);
2585                 nd.ni_startdir = NULL;
2586         }
2587         nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2588         if (v3) {
2589                 if (!error) {
2590                         nfsm_srvpostop_fh(fhp);
2591                         nfsm_srvpostop_attr(0, vap);
2592                 }
2593                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2594         }
2595         error = 0;
2596         /* fall through */
2597
2598 nfsmout:
2599         NDFREE(&nd, NDF_ONLY_PNBUF);
2600         if (nd.ni_dvp) {
2601                 if (nd.ni_dvp == nd.ni_vp)
2602                         vrele(nd.ni_dvp);
2603                 else
2604                         vput(nd.ni_dvp);
2605         }
2606         if (nd.ni_vp)
2607                 vrele(nd.ni_vp);
2608         if (nd.ni_startdir)
2609                 vrele(nd.ni_startdir);
2610         if (dirp)
2611                 vrele(dirp);
2612         if (pathcp)
2613                 FREE(pathcp, M_TEMP);
2614
2615         return (error);
2616 }
2617
2618 /*
2619  * nfs mkdir service
2620  */
2621 int
2622 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2623             struct thread *td, struct mbuf **mrq)
2624 {
2625         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2626         struct sockaddr *nam = nfsd->nd_nam;
2627         caddr_t dpos = nfsd->nd_dpos;
2628         struct ucred *cred = &nfsd->nd_cr;
2629         struct vattr va, dirfor, diraft;
2630         struct vattr *vap = &va;
2631         struct nfs_fattr *fp;
2632         struct nameidata nd;
2633         caddr_t cp;
2634         u_int32_t *tl;
2635         int32_t t1;
2636         caddr_t bpos;
2637         int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2638         int v3 = (nfsd->nd_flag & ND_NFSV3);
2639         char *cp2;
2640         struct mbuf *mb, *mb2, *mreq;
2641         struct vnode *dirp = NULL;
2642         int vpexcl = 0;
2643         nfsfh_t nfh;
2644         fhandle_t *fhp;
2645         u_quad_t frev;
2646
2647         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2648         ndclear(&nd);
2649
2650         fhp = &nfh.fh_generic;
2651         nfsm_srvmtofh(fhp);
2652         nfsm_srvnamesiz(len);
2653         nd.ni_cnd.cn_cred = cred;
2654         nd.ni_cnd.cn_nameiop = NAMEI_CREATE;
2655         nd.ni_cnd.cn_flags = CNP_LOCKPARENT;
2656
2657         error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2658                 &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2659         if (dirp) {
2660                 if (v3) {
2661                         dirfor_ret = VOP_GETATTR(dirp, &dirfor, td);
2662                 } else {
2663                         vrele(dirp);
2664                         dirp = NULL;
2665                 }
2666         }
2667         if (error) {
2668                 nfsm_reply(NFSX_WCCDATA(v3));
2669                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2670                 error = 0;
2671                 goto nfsmout;
2672         }
2673         VATTR_NULL(vap);
2674         if (v3) {
2675                 nfsm_srvsattr(vap);
2676         } else {
2677                 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
2678                 vap->va_mode = nfstov_mode(*tl++);
2679         }
2680
2681         /*
2682          * At this point nd.ni_dvp is referenced and exclusively locked and
2683          * nd.ni_vp, if it exists, is referenced but not locked.
2684          */
2685
2686         vap->va_type = VDIR;
2687         if (nd.ni_vp != NULL) {
2688                 NDFREE(&nd, NDF_ONLY_PNBUF);
2689                 error = EEXIST;
2690                 goto out;
2691         }
2692
2693         /*
2694          * Issue mkdir op.  Since SAVESTART is not set, the pathname 
2695          * component is freed by the VOP call.  This will fill-in
2696          * nd.ni_vp, reference, and exclusively lock it.
2697          */
2698         if (vap->va_mode == (mode_t)VNOVAL)
2699                 vap->va_mode = 0;
2700         nqsrv_getl(nd.ni_dvp, ND_WRITE);
2701         error = VOP_MKDIR(nd.ni_dvp, NCPNULL, &nd.ni_vp, &nd.ni_cnd, vap);
2702         NDFREE(&nd, NDF_ONLY_PNBUF);
2703         vpexcl = 1;
2704
2705         vput(nd.ni_dvp);
2706         nd.ni_dvp = NULL;
2707
2708         if (!error) {
2709                 bzero((caddr_t)fhp, sizeof(nfh));
2710                 fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
2711                 error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
2712                 if (!error)
2713                         error = VOP_GETATTR(nd.ni_vp, vap, td);
2714         }
2715 out:
2716         if (dirp)
2717                 diraft_ret = VOP_GETATTR(dirp, &diraft, td);
2718         nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2719         if (v3) {
2720                 if (!error) {
2721                         nfsm_srvpostop_fh(fhp);
2722                         nfsm_srvpostop_attr(0, vap);
2723                 }
2724                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2725         } else {
2726                 nfsm_srvfhtom(fhp, v3);
2727                 nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
2728                 nfsm_srvfillattr(vap, fp);
2729         }
2730         error = 0;
2731         /* fall through */
2732
2733 nfsmout:
2734         if (dirp)
2735                 vrele(dirp);
2736         if (nd.ni_dvp) {
2737                 NDFREE(&nd, NDF_ONLY_PNBUF);
2738                 if (nd.ni_dvp == nd.ni_vp && vpexcl)
2739                         vrele(nd.ni_dvp);
2740                 else
2741                         vput(nd.ni_dvp);
2742         }
2743         if (nd.ni_vp) {
2744                 if (vpexcl)
2745                         vput(nd.ni_vp);
2746                 else
2747                         vrele(nd.ni_vp);
2748         }
2749         return (error);
2750 }
2751
2752 /*
2753  * nfs rmdir service
2754  */
2755 int
2756 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2757             struct thread *td, struct mbuf **mrq)
2758 {
2759         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2760         struct sockaddr *nam = nfsd->nd_nam;
2761         caddr_t dpos = nfsd->nd_dpos;
2762         struct ucred *cred = &nfsd->nd_cr;
2763         u_int32_t *tl;
2764         int32_t t1;
2765         caddr_t bpos;
2766         int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2767         int v3 = (nfsd->nd_flag & ND_NFSV3);
2768         char *cp2;
2769         struct mbuf *mb, *mreq;
2770         struct vnode *vp, *dirp = (struct vnode *)0;
2771         struct vattr dirfor, diraft;
2772         nfsfh_t nfh;
2773         fhandle_t *fhp;
2774         struct nameidata nd;
2775         u_quad_t frev;
2776
2777         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2778         ndclear(&nd);
2779
2780         fhp = &nfh.fh_generic;
2781         nfsm_srvmtofh(fhp);
2782         nfsm_srvnamesiz(len);
2783         nd.ni_cnd.cn_cred = cred;
2784         nd.ni_cnd.cn_nameiop = NAMEI_DELETE;
2785         nd.ni_cnd.cn_flags = CNP_LOCKPARENT | CNP_LOCKLEAF;
2786         error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2787                 &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2788         if (dirp) {
2789                 if (v3) {
2790                         dirfor_ret = VOP_GETATTR(dirp, &dirfor, td);
2791                 } else {
2792                         vrele(dirp);
2793                         dirp = NULL;
2794                 }
2795         }
2796         if (error) {
2797                 nfsm_reply(NFSX_WCCDATA(v3));
2798                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2799                 error = 0;
2800                 goto nfsmout;
2801         }
2802         vp = nd.ni_vp;
2803         if (vp->v_type != VDIR) {
2804                 error = ENOTDIR;
2805                 goto out;
2806         }
2807         /*
2808          * No rmdir "." please.
2809          */
2810         if (nd.ni_dvp == vp) {
2811                 error = EINVAL;
2812                 goto out;
2813         }
2814         /*
2815          * The root of a mounted filesystem cannot be deleted.
2816          */
2817         if (vp->v_flag & VROOT)
2818                 error = EBUSY;
2819 out:
2820         /*
2821          * Issue or abort op.  Since SAVESTART is not set, path name
2822          * component is freed by the VOP after either.
2823          */
2824         if (!error) {
2825                 nqsrv_getl(nd.ni_dvp, ND_WRITE);
2826                 nqsrv_getl(vp, ND_WRITE);
2827                 error = VOP_RMDIR(nd.ni_dvp, NCPNULL, nd.ni_vp, &nd.ni_cnd);
2828         }
2829         NDFREE(&nd, NDF_ONLY_PNBUF);
2830
2831         if (dirp)
2832                 diraft_ret = VOP_GETATTR(dirp, &diraft, td);
2833         nfsm_reply(NFSX_WCCDATA(v3));
2834         if (v3) {
2835                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2836                 error = 0;
2837         }
2838         /* fall through */
2839
2840 nfsmout:
2841         NDFREE(&nd, NDF_ONLY_PNBUF);
2842         if (dirp)
2843                 vrele(dirp);
2844         if (nd.ni_dvp) {
2845                 if (nd.ni_dvp == nd.ni_vp)
2846                         vrele(nd.ni_dvp);
2847                 else
2848                         vput(nd.ni_dvp);
2849         }
2850         if (nd.ni_vp)
2851                 vput(nd.ni_vp);
2852
2853         return(error);
2854 }
2855
2856 /*
2857  * nfs readdir service
2858  * - mallocs what it thinks is enough to read
2859  *      count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2860  * - calls VOP_READDIR()
2861  * - loops around building the reply
2862  *      if the output generated exceeds count break out of loop
2863  *      The nfsm_clget macro is used here so that the reply will be packed
2864  *      tightly in mbuf clusters.
2865  * - it only knows that it has encountered eof when the VOP_READDIR()
2866  *      reads nothing
2867  * - as such one readdir rpc will return eof false although you are there
2868  *      and then the next will return eof
2869  * - it trims out records with d_fileno == 0
2870  *      this doesn't matter for Unix clients, but they might confuse clients
2871  *      for other os'.
2872  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2873  *      than requested, but this may not apply to all filesystems. For
2874  *      example, client NFS does not { although it is never remote mounted
2875  *      anyhow }
2876  *     The alternate call nfsrv_readdirplus() does lookups as well.
2877  * PS: The NFS protocol spec. does not clarify what the "count" byte
2878  *      argument is a count of.. just name strings and file id's or the
2879  *      entire reply rpc or ...
2880  *      I tried just file name and id sizes and it confused the Sun client,
2881  *      so I am using the full rpc size now. The "paranoia.." comment refers
2882  *      to including the status longwords that are not a part of the dir.
2883  *      "entry" structures, but are in the rpc.
2884  */
2885 struct flrep {
2886         nfsuint64       fl_off;
2887         u_int32_t       fl_postopok;
2888         u_int32_t       fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)];
2889         u_int32_t       fl_fhok;
2890         u_int32_t       fl_fhsize;
2891         u_int32_t       fl_nfh[NFSX_V3FH / sizeof (u_int32_t)];
2892 };
2893
2894 int
2895 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2896               struct thread *td, struct mbuf **mrq)
2897 {
2898         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2899         struct sockaddr *nam = nfsd->nd_nam;
2900         caddr_t dpos = nfsd->nd_dpos;
2901         struct ucred *cred = &nfsd->nd_cr;
2902         char *bp, *be;
2903         struct mbuf *mp;
2904         struct dirent *dp;
2905         caddr_t cp;
2906         u_int32_t *tl;
2907         int32_t t1;
2908         caddr_t bpos;
2909         struct mbuf *mb, *mb2, *mreq, *mp2;
2910         char *cpos, *cend, *cp2, *rbuf;
2911         struct vnode *vp = NULL;
2912         struct vattr at;
2913         nfsfh_t nfh;
2914         fhandle_t *fhp;
2915         struct uio io;
2916         struct iovec iv;
2917         int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2918         int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies;
2919         int v3 = (nfsd->nd_flag & ND_NFSV3);
2920         u_quad_t frev, off, toff, verf;
2921         u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */
2922
2923         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2924         fhp = &nfh.fh_generic;
2925         nfsm_srvmtofh(fhp);
2926         if (v3) {
2927                 nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2928                 toff = fxdr_hyper(tl);
2929                 tl += 2;
2930                 verf = fxdr_hyper(tl);
2931                 tl += 2;
2932         } else {
2933                 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2934                 toff = fxdr_unsigned(u_quad_t, *tl++);
2935                 verf = 0;       /* shut up gcc */
2936         }
2937         off = toff;
2938         cnt = fxdr_unsigned(int, *tl);
2939         siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2940         xfer = NFS_SRVMAXDATA(nfsd);
2941         if (cnt > xfer)
2942                 cnt = xfer;
2943         if (siz > xfer)
2944                 siz = xfer;
2945         fullsiz = siz;
2946         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2947                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
2948         if (!error && vp->v_type != VDIR) {
2949                 error = ENOTDIR;
2950                 vput(vp);
2951                 vp = NULL;
2952         }
2953         if (error) {
2954                 nfsm_reply(NFSX_UNSIGNED);
2955                 nfsm_srvpostop_attr(getret, &at);
2956                 error = 0;
2957                 goto nfsmout;
2958         }
2959
2960         /*
2961          * Obtain lock on vnode for this section of the code
2962          */
2963
2964         nqsrv_getl(vp, ND_READ);
2965         if (v3) {
2966                 error = getret = VOP_GETATTR(vp, &at, td);
2967 #if 0
2968                 /*
2969                  * XXX This check may be too strict for Solaris 2.5 clients.
2970                  */
2971                 if (!error && toff && verf && verf != at.va_filerev)
2972                         error = NFSERR_BAD_COOKIE;
2973 #endif
2974         }
2975         if (!error)
2976                 error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0);
2977         if (error) {
2978                 vput(vp);
2979                 vp = NULL;
2980                 nfsm_reply(NFSX_POSTOPATTR(v3));
2981                 nfsm_srvpostop_attr(getret, &at);
2982                 error = 0;
2983                 goto nfsmout;
2984         }
2985         VOP_UNLOCK(vp, NULL, 0, td);
2986
2987         /*
2988          * end section.  Allocate rbuf and continue
2989          */
2990         MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
2991 again:
2992         iv.iov_base = rbuf;
2993         iv.iov_len = fullsiz;
2994         io.uio_iov = &iv;
2995         io.uio_iovcnt = 1;
2996         io.uio_offset = (off_t)off;
2997         io.uio_resid = fullsiz;
2998         io.uio_segflg = UIO_SYSSPACE;
2999         io.uio_rw = UIO_READ;
3000         io.uio_td = NULL;
3001         eofflag = 0;
3002         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
3003         if (cookies) {
3004                 free((caddr_t)cookies, M_TEMP);
3005                 cookies = NULL;
3006         }
3007         error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
3008         off = (off_t)io.uio_offset;
3009         if (!cookies && !error)
3010                 error = NFSERR_PERM;
3011         if (v3) {
3012                 getret = VOP_GETATTR(vp, &at, td);
3013                 if (!error)
3014                         error = getret;
3015         }
3016         VOP_UNLOCK(vp, NULL, 0, td);
3017         if (error) {
3018                 vrele(vp);
3019                 vp = NULL;
3020                 free((caddr_t)rbuf, M_TEMP);
3021                 if (cookies)
3022                         free((caddr_t)cookies, M_TEMP);
3023                 nfsm_reply(NFSX_POSTOPATTR(v3));
3024                 nfsm_srvpostop_attr(getret, &at);
3025                 error = 0;
3026                 goto nfsmout;
3027         }
3028         if (io.uio_resid) {
3029                 siz -= io.uio_resid;
3030
3031                 /*
3032                  * If nothing read, return eof
3033                  * rpc reply
3034                  */
3035                 if (siz == 0) {
3036                         vrele(vp);
3037                         vp = NULL;
3038                         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
3039                                 2 * NFSX_UNSIGNED);
3040                         if (v3) {
3041                                 nfsm_srvpostop_attr(getret, &at);
3042                                 nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
3043                                 txdr_hyper(at.va_filerev, tl);
3044                                 tl += 2;
3045                         } else
3046                                 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3047                         *tl++ = nfs_false;
3048                         *tl = nfs_true;
3049                         FREE((caddr_t)rbuf, M_TEMP);
3050                         FREE((caddr_t)cookies, M_TEMP);
3051                         error = 0;
3052                         goto nfsmout;
3053                 }
3054         }
3055
3056         /*
3057          * Check for degenerate cases of nothing useful read.
3058          * If so go try again
3059          */
3060         cpos = rbuf;
3061         cend = rbuf + siz;
3062         dp = (struct dirent *)cpos;
3063         cookiep = cookies;
3064         /*
3065          * For some reason FreeBSD's ufs_readdir() chooses to back the
3066          * directory offset up to a block boundary, so it is necessary to
3067          * skip over the records that preceed the requested offset. This
3068          * requires the assumption that file offset cookies monotonically
3069          * increase.
3070          */
3071         while (cpos < cend && ncookies > 0 &&
3072                 (dp->d_fileno == 0 || dp->d_type == DT_WHT ||
3073                  ((u_quad_t)(*cookiep)) <= toff)) {
3074                 cpos += dp->d_reclen;
3075                 dp = (struct dirent *)cpos;
3076                 cookiep++;
3077                 ncookies--;
3078         }
3079         if (cpos >= cend || ncookies == 0) {
3080                 toff = off;
3081                 siz = fullsiz;
3082                 goto again;
3083         }
3084
3085         len = 3 * NFSX_UNSIGNED;        /* paranoia, probably can be 0 */
3086         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
3087         if (v3) {
3088                 nfsm_srvpostop_attr(getret, &at);
3089                 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3090                 txdr_hyper(at.va_filerev, tl);
3091         }
3092         mp = mp2 = mb;
3093         bp = bpos;
3094         be = bp + M_TRAILINGSPACE(mp);
3095
3096         /* Loop through the records and build reply */
3097         while (cpos < cend && ncookies > 0) {
3098                 if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
3099                         nlen = dp->d_namlen;
3100                         rem = nfsm_rndup(nlen) - nlen;
3101                         len += (4 * NFSX_UNSIGNED + nlen + rem);
3102                         if (v3)
3103                                 len += 2 * NFSX_UNSIGNED;
3104                         if (len > cnt) {
3105                                 eofflag = 0;
3106                                 break;
3107                         }
3108                         /*
3109                          * Build the directory record xdr from
3110                          * the dirent entry.
3111                          */
3112                         nfsm_clget;
3113                         *tl = nfs_true;
3114                         bp += NFSX_UNSIGNED;
3115                         if (v3) {
3116                                 nfsm_clget;
3117                                 *tl = 0;
3118                                 bp += NFSX_UNSIGNED;
3119                         }
3120                         nfsm_clget;
3121                         *tl = txdr_unsigned(dp->d_fileno);
3122                         bp += NFSX_UNSIGNED;
3123                         nfsm_clget;
3124                         *tl = txdr_unsigned(nlen);
3125                         bp += NFSX_UNSIGNED;
3126
3127                         /* And loop around copying the name */
3128                         xfer = nlen;
3129                         cp = dp->d_name;
3130                         while (xfer > 0) {
3131                                 nfsm_clget;
3132                                 if ((bp+xfer) > be)
3133                                         tsiz = be-bp;
3134                                 else
3135                                         tsiz = xfer;
3136                                 bcopy(cp, bp, tsiz);
3137                                 bp += tsiz;
3138                                 xfer -= tsiz;
3139                                 if (xfer > 0)
3140                                         cp += tsiz;
3141                         }
3142                         /* And null pad to a int32_t boundary */
3143                         for (i = 0; i < rem; i++)
3144                                 *bp++ = '\0';
3145                         nfsm_clget;
3146
3147                         /* Finish off the record */
3148                         if (v3) {
3149                                 *tl = 0;
3150                                 bp += NFSX_UNSIGNED;
3151                                 nfsm_clget;
3152                         }
3153                         *tl = txdr_unsigned(*cookiep);
3154                         bp += NFSX_UNSIGNED;
3155                 }
3156                 cpos += dp->d_reclen;
3157                 dp = (struct dirent *)cpos;
3158                 cookiep++;
3159                 ncookies--;
3160         }
3161         vrele(vp);
3162         vp = NULL;
3163         nfsm_clget;
3164         *tl = nfs_false;
3165         bp += NFSX_UNSIGNED;
3166         nfsm_clget;
3167         if (eofflag)
3168                 *tl = nfs_true;
3169         else
3170                 *tl = nfs_false;
3171         bp += NFSX_UNSIGNED;
3172         if (mp != mb) {
3173                 if (bp < be)
3174                         mp->m_len = bp - mtod(mp, caddr_t);
3175         } else
3176                 mp->m_len += bp - bpos;
3177         FREE((caddr_t)rbuf, M_TEMP);
3178         FREE((caddr_t)cookies, M_TEMP);
3179
3180 nfsmout:
3181         if (vp)
3182                 vrele(vp);
3183         return(error);
3184 }
3185
3186 int
3187 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3188                   struct thread *td, struct mbuf **mrq)
3189 {
3190         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3191         struct sockaddr *nam = nfsd->nd_nam;
3192         caddr_t dpos = nfsd->nd_dpos;
3193         struct ucred *cred = &nfsd->nd_cr;
3194         char *bp, *be;
3195         struct mbuf *mp;
3196         struct dirent *dp;
3197         caddr_t cp;
3198         u_int32_t *tl;
3199         int32_t t1;
3200         caddr_t bpos;
3201         struct mbuf *mb, *mb2, *mreq, *mp2;
3202         char *cpos, *cend, *cp2, *rbuf;
3203         struct vnode *vp = NULL, *nvp;
3204         struct flrep fl;
3205         nfsfh_t nfh;
3206         fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
3207         struct uio io;
3208         struct iovec iv;
3209         struct vattr va, at, *vap = &va;
3210         struct nfs_fattr *fp;
3211         int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
3212         int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies;
3213         u_quad_t frev, off, toff, verf;
3214         u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */
3215
3216         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3217         fhp = &nfh.fh_generic;
3218         nfsm_srvmtofh(fhp);
3219         nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
3220         toff = fxdr_hyper(tl);
3221         tl += 2;
3222         verf = fxdr_hyper(tl);
3223         tl += 2;
3224         siz = fxdr_unsigned(int, *tl++);
3225         cnt = fxdr_unsigned(int, *tl);
3226         off = toff;
3227         siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
3228         xfer = NFS_SRVMAXDATA(nfsd);
3229         if (cnt > xfer)
3230                 cnt = xfer;
3231         if (siz > xfer)
3232                 siz = xfer;
3233         fullsiz = siz;
3234         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3235                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3236         if (!error && vp->v_type != VDIR) {
3237                 error = ENOTDIR;
3238                 vput(vp);
3239                 vp = NULL;
3240         }
3241         if (error) {
3242                 nfsm_reply(NFSX_UNSIGNED);
3243                 nfsm_srvpostop_attr(getret, &at);
3244                 error = 0;
3245                 goto nfsmout;
3246         }
3247         error = getret = VOP_GETATTR(vp, &at, td);
3248 #if 0
3249         /*
3250          * XXX This check may be too strict for Solaris 2.5 clients.
3251          */
3252         if (!error && toff && verf && verf != at.va_filerev)
3253                 error = NFSERR_BAD_COOKIE;
3254 #endif
3255         if (!error) {
3256                 nqsrv_getl(vp, ND_READ);
3257                 error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0);
3258         }
3259         if (error) {
3260                 vput(vp);
3261                 vp = NULL;
3262                 nfsm_reply(NFSX_V3POSTOPATTR);
3263                 nfsm_srvpostop_attr(getret, &at);
3264                 error = 0;
3265                 goto nfsmout;
3266         }
3267         VOP_UNLOCK(vp, NULL, 0, td);
3268         MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
3269 again:
3270         iv.iov_base = rbuf;
3271         iv.iov_len = fullsiz;
3272         io.uio_iov = &iv;
3273         io.uio_iovcnt = 1;
3274         io.uio_offset = (off_t)off;
3275         io.uio_resid = fullsiz;
3276         io.uio_segflg = UIO_SYSSPACE;
3277         io.uio_rw = UIO_READ;
3278         io.uio_td = NULL;
3279         eofflag = 0;
3280         vn_lock(vp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
3281         if (cookies) {
3282                 free((caddr_t)cookies, M_TEMP);
3283                 cookies = NULL;
3284         }
3285         error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
3286         off = (u_quad_t)io.uio_offset;
3287         getret = VOP_GETATTR(vp, &at, td);
3288         VOP_UNLOCK(vp, NULL, 0, td);
3289         if (!cookies && !error)
3290                 error = NFSERR_PERM;
3291         if (!error)
3292                 error = getret;
3293         if (error) {
3294                 vrele(vp);
3295                 vp = NULL;
3296                 if (cookies)
3297                         free((caddr_t)cookies, M_TEMP);
3298                 free((caddr_t)rbuf, M_TEMP);
3299                 nfsm_reply(NFSX_V3POSTOPATTR);
3300                 nfsm_srvpostop_attr(getret, &at);
3301                 error = 0;
3302                 goto nfsmout;
3303         }
3304         if (io.uio_resid) {
3305                 siz -= io.uio_resid;
3306
3307                 /*
3308                  * If nothing read, return eof
3309                  * rpc reply
3310                  */
3311                 if (siz == 0) {
3312                         vrele(vp);
3313                         vp = NULL;
3314                         nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
3315                                 2 * NFSX_UNSIGNED);
3316                         nfsm_srvpostop_attr(getret, &at);
3317                         nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
3318                         txdr_hyper(at.va_filerev, tl);
3319                         tl += 2;
3320                         *tl++ = nfs_false;
3321                         *tl = nfs_true;
3322                         FREE((caddr_t)cookies, M_TEMP);
3323                         FREE((caddr_t)rbuf, M_TEMP);
3324                         error = 0;
3325                         goto nfsmout;
3326                 }
3327         }
3328
3329         /*
3330          * Check for degenerate cases of nothing useful read.
3331          * If so go try again
3332          */
3333         cpos = rbuf;
3334         cend = rbuf + siz;
3335         dp = (struct dirent *)cpos;
3336         cookiep = cookies;
3337         /*
3338          * For some reason FreeBSD's ufs_readdir() chooses to back the
3339          * directory offset up to a block boundary, so it is necessary to
3340          * skip over the records that preceed the requested offset. This
3341          * requires the assumption that file offset cookies monotonically
3342          * increase.
3343          */
3344         while (cpos < cend && ncookies > 0 &&
3345                 (dp->d_fileno == 0 || dp->d_type == DT_WHT ||
3346                  ((u_quad_t)(*cookiep)) <= toff)) {
3347                 cpos += dp->d_reclen;
3348                 dp = (struct dirent *)cpos;
3349                 cookiep++;
3350                 ncookies--;
3351         }
3352         if (cpos >= cend || ncookies == 0) {
3353                 toff = off;
3354                 siz = fullsiz;
3355                 goto again;
3356         }
3357
3358         /*
3359          * Probe one of the directory entries to see if the filesystem
3360          * supports VGET.
3361          */
3362         if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp) == EOPNOTSUPP) {
3363                 error = NFSERR_NOTSUPP;
3364                 vrele(vp);
3365                 vp = NULL;
3366                 free((caddr_t)cookies, M_TEMP);
3367                 free((caddr_t)rbuf, M_TEMP);
3368                 nfsm_reply(NFSX_V3POSTOPATTR);
3369                 nfsm_srvpostop_attr(getret, &at);
3370                 error = 0;
3371                 goto nfsmout;
3372         }
3373         vput(nvp);
3374         nvp = NULL;
3375             
3376         dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
3377         nfsm_reply(cnt);
3378         nfsm_srvpostop_attr(getret, &at);
3379         nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3380         txdr_hyper(at.va_filerev, tl);
3381         mp = mp2 = mb;
3382         bp = bpos;
3383         be = bp + M_TRAILINGSPACE(mp);
3384
3385         /* Loop through the records and build reply */
3386         while (cpos < cend && ncookies > 0) {
3387                 if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
3388                         nlen = dp->d_namlen;
3389                         rem = nfsm_rndup(nlen)-nlen;
3390
3391                         /*
3392                          * For readdir_and_lookup get the vnode using
3393                          * the file number.
3394                          */
3395                         if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
3396                                 goto invalid;
3397                         bzero((caddr_t)nfhp, NFSX_V3FH);
3398                         nfhp->fh_fsid =
3399                                 nvp->v_mount->mnt_stat.f_fsid;
3400                         if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
3401                                 vput(nvp);
3402                                 nvp = NULL;
3403                                 goto invalid;
3404                         }
3405                         if (VOP_GETATTR(nvp, vap, td)) {
3406                                 vput(nvp);
3407                                 nvp = NULL;
3408                                 goto invalid;
3409                         }
3410                         vput(nvp);
3411                         nvp = NULL;
3412
3413                         /*
3414                          * If either the dircount or maxcount will be
3415                          * exceeded, get out now. Both of these lengths
3416                          * are calculated conservatively, including all
3417                          * XDR overheads.
3418                          */
3419                         len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
3420                                 NFSX_V3POSTOPATTR);
3421                         dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
3422                         if (len > cnt || dirlen > fullsiz) {
3423                                 eofflag = 0;
3424                                 break;
3425                         }
3426
3427                         /*
3428                          * Build the directory record xdr from
3429                          * the dirent entry.
3430                          */
3431                         fp = (struct nfs_fattr *)&fl.fl_fattr;
3432                         nfsm_srvfillattr(vap, fp);
3433                         fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
3434                         fl.fl_fhok = nfs_true;
3435                         fl.fl_postopok = nfs_true;
3436                         fl.fl_off.nfsuquad[0] = 0;
3437                         fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
3438
3439                         nfsm_clget;
3440                         *tl = nfs_true;
3441                         bp += NFSX_UNSIGNED;
3442                         nfsm_clget;
3443                         *tl = 0;
3444                         bp += NFSX_UNSIGNED;
3445                         nfsm_clget;
3446                         *tl = txdr_unsigned(dp->d_fileno);
3447                         bp += NFSX_UNSIGNED;
3448                         nfsm_clget;
3449                         *tl = txdr_unsigned(nlen);
3450                         bp += NFSX_UNSIGNED;
3451
3452                         /* And loop around copying the name */
3453                         xfer = nlen;
3454                         cp = dp->d_name;
3455                         while (xfer > 0) {
3456                                 nfsm_clget;
3457                                 if ((bp + xfer) > be)
3458                                         tsiz = be - bp;
3459                                 else
3460                                         tsiz = xfer;
3461                                 bcopy(cp, bp, tsiz);
3462                                 bp += tsiz;
3463                                 xfer -= tsiz;
3464                                 if (xfer > 0)
3465                                         cp += tsiz;
3466                         }
3467                         /* And null pad to a int32_t boundary */
3468                         for (i = 0; i < rem; i++)
3469                                 *bp++ = '\0';
3470         
3471                         /*
3472                          * Now copy the flrep structure out.
3473                          */
3474                         xfer = sizeof (struct flrep);
3475                         cp = (caddr_t)&fl;
3476                         while (xfer > 0) {
3477                                 nfsm_clget;
3478                                 if ((bp + xfer) > be)
3479                                         tsiz = be - bp;
3480                                 else
3481                                         tsiz = xfer;
3482                                 bcopy(cp, bp, tsiz);
3483                                 bp += tsiz;
3484                                 xfer -= tsiz;
3485                                 if (xfer > 0)
3486                                         cp += tsiz;
3487                         }
3488                 }
3489 invalid:
3490                 cpos += dp->d_reclen;
3491                 dp = (struct dirent *)cpos;
3492                 cookiep++;
3493                 ncookies--;
3494         }
3495         vrele(vp);
3496         vp = NULL;
3497         nfsm_clget;
3498         *tl = nfs_false;
3499         bp += NFSX_UNSIGNED;
3500         nfsm_clget;
3501         if (eofflag)
3502                 *tl = nfs_true;
3503         else
3504                 *tl = nfs_false;
3505         bp += NFSX_UNSIGNED;
3506         if (mp != mb) {
3507                 if (bp < be)
3508                         mp->m_len = bp - mtod(mp, caddr_t);
3509         } else
3510                 mp->m_len += bp - bpos;
3511         FREE((caddr_t)cookies, M_TEMP);
3512         FREE((caddr_t)rbuf, M_TEMP);
3513 nfsmout:
3514         if (vp)
3515                 vrele(vp);
3516         return(error);
3517 }
3518
3519 /*
3520  * nfs commit service
3521  */
3522 int
3523 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3524              struct thread *td, struct mbuf **mrq)
3525 {
3526         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3527         struct sockaddr *nam = nfsd->nd_nam;
3528         caddr_t dpos = nfsd->nd_dpos;
3529         struct ucred *cred = &nfsd->nd_cr;
3530         struct vattr bfor, aft;
3531         struct vnode *vp = NULL;
3532         nfsfh_t nfh;
3533         fhandle_t *fhp;
3534         u_int32_t *tl;
3535         int32_t t1;
3536         caddr_t bpos;
3537         int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache;
3538         char *cp2;
3539         struct mbuf *mb, *mb2, *mreq;
3540         u_quad_t frev, off;
3541
3542         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3543 #ifndef nolint
3544         cache = 0;
3545 #endif
3546         fhp = &nfh.fh_generic;
3547         nfsm_srvmtofh(fhp);
3548         nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3549
3550         /*
3551          * XXX At this time VOP_FSYNC() does not accept offset and byte
3552          * count parameters, so these arguments are useless (someday maybe).
3553          */
3554         off = fxdr_hyper(tl);
3555         tl += 2;
3556         cnt = fxdr_unsigned(int, *tl);
3557         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3558                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3559         if (error) {
3560                 nfsm_reply(2 * NFSX_UNSIGNED);
3561                 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3562                 error = 0;
3563                 goto nfsmout;
3564         }
3565         for_ret = VOP_GETATTR(vp, &bfor, td);
3566
3567         if (cnt > MAX_COMMIT_COUNT) {
3568                 /*
3569                  * Give up and do the whole thing
3570                  */
3571                 if (vp->v_object &&
3572                    (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
3573                         vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC);
3574                 }
3575                 error = VOP_FSYNC(vp, MNT_WAIT, td);
3576         } else {
3577                 /*
3578                  * Locate and synchronously write any buffers that fall
3579                  * into the requested range.  Note:  we are assuming that
3580                  * f_iosize is a power of 2.
3581                  */
3582                 int iosize = vp->v_mount->mnt_stat.f_iosize;
3583                 int iomask = iosize - 1;
3584                 int s;
3585                 daddr_t lblkno;
3586
3587                 /*
3588                  * Align to iosize boundry, super-align to page boundry.
3589                  */
3590                 if (off & iomask) {
3591                         cnt += off & iomask;
3592                         off &= ~(u_quad_t)iomask;
3593                 }
3594                 if (off & PAGE_MASK) {
3595                         cnt += off & PAGE_MASK;
3596                         off &= ~(u_quad_t)PAGE_MASK;
3597                 }
3598                 lblkno = off / iosize;
3599
3600                 if (vp->v_object &&
3601                    (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
3602                         vm_object_page_clean(vp->v_object, off / PAGE_SIZE, (cnt + PAGE_MASK) / PAGE_SIZE, OBJPC_SYNC);
3603                 }
3604
3605                 s = splbio();
3606                 while (cnt > 0) {
3607                         struct buf *bp;
3608
3609                         /*
3610                          * If we have a buffer and it is marked B_DELWRI we
3611                          * have to lock and write it.  Otherwise the prior
3612                          * write is assumed to have already been committed.
3613                          */
3614                         if ((bp = gbincore(vp, lblkno)) != NULL && (bp->b_flags & B_DELWRI)) {
3615                                 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
3616                                         BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL);
3617                                         continue; /* retry */
3618                                 }
3619                                 bremfree(bp);
3620                                 bp->b_flags &= ~B_ASYNC;
3621                                 VOP_BWRITE(bp->b_vp, bp);
3622                                 ++nfs_commit_miss;
3623                         }
3624                         ++nfs_commit_blks;
3625                         if (cnt < iosize)
3626                                 break;
3627                         cnt -= iosize;
3628                         ++lblkno;
3629                 }
3630                 splx(s);
3631         }
3632
3633         aft_ret = VOP_GETATTR(vp, &aft, td);
3634         vput(vp);
3635         vp = NULL;
3636         nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
3637         nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3638         if (!error) {
3639                 nfsm_build(tl, u_int32_t *, NFSX_V3WRITEVERF);
3640                 if (nfsver.tv_sec == 0)
3641                         nfsver = boottime;
3642                 *tl++ = txdr_unsigned(nfsver.tv_sec);
3643                 *tl = txdr_unsigned(nfsver.tv_nsec / 1000);
3644         } else {
3645                 error = 0;
3646         }
3647 nfsmout:
3648         if (vp)
3649                 vput(vp);
3650         return(error);
3651 }
3652
3653 /*
3654  * nfs statfs service
3655  */
3656 int
3657 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3658              struct thread *td, struct mbuf **mrq)
3659 {
3660         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3661         struct sockaddr *nam = nfsd->nd_nam;
3662         caddr_t dpos = nfsd->nd_dpos;
3663         struct ucred *cred = &nfsd->nd_cr;
3664         struct statfs *sf;
3665         struct nfs_statfs *sfp;
3666         u_int32_t *tl;
3667         int32_t t1;
3668         caddr_t bpos;
3669         int error = 0, rdonly, cache, getret = 1;
3670         int v3 = (nfsd->nd_flag & ND_NFSV3);
3671         char *cp2;
3672         struct mbuf *mb, *mb2, *mreq;
3673         struct vnode *vp = NULL;
3674         struct vattr at;
3675         nfsfh_t nfh;
3676         fhandle_t *fhp;
3677         struct statfs statfs;
3678         u_quad_t frev, tval;
3679
3680         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3681 #ifndef nolint
3682         cache = 0;
3683 #endif
3684         fhp = &nfh.fh_generic;
3685         nfsm_srvmtofh(fhp);
3686         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3687                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3688         if (error) {
3689                 nfsm_reply(NFSX_UNSIGNED);
3690                 nfsm_srvpostop_attr(getret, &at);
3691                 error = 0;
3692                 goto nfsmout;
3693         }
3694         sf = &statfs;
3695         error = VFS_STATFS(vp->v_mount, sf, td);
3696         getret = VOP_GETATTR(vp, &at, td);
3697         vput(vp);
3698         vp = NULL;
3699         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
3700         if (v3)
3701                 nfsm_srvpostop_attr(getret, &at);
3702         if (error) {
3703                 error = 0;
3704                 goto nfsmout;
3705         }
3706         nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
3707         if (v3) {
3708                 tval = (u_quad_t)sf->f_blocks;
3709                 tval *= (u_quad_t)sf->f_bsize;
3710                 txdr_hyper(tval, &sfp->sf_tbytes);
3711                 tval = (u_quad_t)sf->f_bfree;
3712                 tval *= (u_quad_t)sf->f_bsize;
3713                 txdr_hyper(tval, &sfp->sf_fbytes);
3714                 tval = (u_quad_t)sf->f_bavail;
3715                 tval *= (u_quad_t)sf->f_bsize;
3716                 txdr_hyper(tval, &sfp->sf_abytes);
3717                 sfp->sf_tfiles.nfsuquad[0] = 0;
3718                 sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
3719                 sfp->sf_ffiles.nfsuquad[0] = 0;
3720                 sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3721                 sfp->sf_afiles.nfsuquad[0] = 0;
3722                 sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3723                 sfp->sf_invarsec = 0;
3724         } else {
3725                 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
3726                 sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
3727                 sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
3728                 sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
3729                 sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
3730         }
3731 nfsmout:
3732         if (vp)
3733                 vput(vp);
3734         return(error);
3735 }
3736
3737 /*
3738  * nfs fsinfo service
3739  */
3740 int
3741 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3742              struct thread *td, struct mbuf **mrq)
3743 {
3744         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3745         struct sockaddr *nam = nfsd->nd_nam;
3746         caddr_t dpos = nfsd->nd_dpos;
3747         struct ucred *cred = &nfsd->nd_cr;
3748         u_int32_t *tl;
3749         struct nfsv3_fsinfo *sip;
3750         int32_t t1;
3751         caddr_t bpos;
3752         int error = 0, rdonly, cache, getret = 1, pref;
3753         char *cp2;
3754         struct mbuf *mb, *mb2, *mreq;
3755         struct vnode *vp = NULL;
3756         struct vattr at;
3757         nfsfh_t nfh;
3758         fhandle_t *fhp;
3759         u_quad_t frev, maxfsize;
3760         struct statfs sb;
3761
3762         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3763 #ifndef nolint
3764         cache = 0;
3765 #endif
3766         fhp = &nfh.fh_generic;
3767         nfsm_srvmtofh(fhp);
3768         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3769                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3770         if (error) {
3771                 nfsm_reply(NFSX_UNSIGNED);
3772                 nfsm_srvpostop_attr(getret, &at);
3773                 error = 0;
3774                 goto nfsmout;
3775         }
3776
3777         /* XXX Try to make a guess on the max file size. */
3778         VFS_STATFS(vp->v_mount, &sb, td);
3779         maxfsize = (u_quad_t)0x80000000 * sb.f_bsize - 1;
3780
3781         getret = VOP_GETATTR(vp, &at, td);
3782         vput(vp);
3783         vp = NULL;
3784         nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
3785         nfsm_srvpostop_attr(getret, &at);
3786         nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
3787
3788         /*
3789          * XXX
3790          * There should be file system VFS OP(s) to get this information.
3791          * For now, assume ufs.
3792          */
3793         if (slp->ns_so->so_type == SOCK_DGRAM)
3794                 pref = NFS_MAXDGRAMDATA;
3795         else
3796                 pref = NFS_MAXDATA;
3797         sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
3798         sip->fs_rtpref = txdr_unsigned(pref);
3799         sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3800         sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
3801         sip->fs_wtpref = txdr_unsigned(pref);
3802         sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3803         sip->fs_dtpref = txdr_unsigned(pref);
3804         txdr_hyper(maxfsize, &sip->fs_maxfilesize);
3805         sip->fs_timedelta.nfsv3_sec = 0;
3806         sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3807         sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3808                 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3809                 NFSV3FSINFO_CANSETTIME);
3810 nfsmout:
3811         if (vp)
3812                 vput(vp);
3813         return(error);
3814 }
3815
3816 /*
3817  * nfs pathconf service
3818  */
3819 int
3820 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3821                struct thread *td, struct mbuf **mrq)
3822 {
3823         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3824         struct sockaddr *nam = nfsd->nd_nam;
3825         caddr_t dpos = nfsd->nd_dpos;
3826         struct ucred *cred = &nfsd->nd_cr;
3827         u_int32_t *tl;
3828         struct nfsv3_pathconf *pc;
3829         int32_t t1;
3830         caddr_t bpos;
3831         int error = 0, rdonly, cache, getret = 1;
3832         register_t linkmax, namemax, chownres, notrunc;
3833         char *cp2;
3834         struct mbuf *mb, *mb2, *mreq;
3835         struct vnode *vp = NULL;
3836         struct vattr at;
3837         nfsfh_t nfh;
3838         fhandle_t *fhp;
3839         u_quad_t frev;
3840
3841         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3842 #ifndef nolint
3843         cache = 0;
3844 #endif
3845         fhp = &nfh.fh_generic;
3846         nfsm_srvmtofh(fhp);
3847         error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3848                  &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3849         if (error) {
3850                 nfsm_reply(NFSX_UNSIGNED);
3851                 nfsm_srvpostop_attr(getret, &at);
3852                 error = 0;
3853                 goto nfsmout;
3854         }
3855         error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
3856         if (!error)
3857                 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
3858         if (!error)
3859                 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
3860         if (!error)
3861                 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc);
3862         getret = VOP_GETATTR(vp, &at, td);
3863         vput(vp);
3864         vp = NULL;
3865         nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
3866         nfsm_srvpostop_attr(getret, &at);
3867         if (error) {
3868                 error = 0;
3869                 goto nfsmout;
3870         }
3871         nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
3872
3873         pc->pc_linkmax = txdr_unsigned(linkmax);
3874         pc->pc_namemax = txdr_unsigned(namemax);
3875         pc->pc_notrunc = txdr_unsigned(notrunc);
3876         pc->pc_chownrestricted = txdr_unsigned(chownres);
3877
3878         /*
3879          * These should probably be supported by VOP_PATHCONF(), but
3880          * until msdosfs is exportable (why would you want to?), the
3881          * Unix defaults should be ok.
3882          */
3883         pc->pc_caseinsensitive = nfs_false;
3884         pc->pc_casepreserving = nfs_true;
3885 nfsmout:
3886         if (vp) 
3887                 vput(vp);
3888         return(error);
3889 }
3890
3891 /*
3892  * Null operation, used by clients to ping server
3893  */
3894 /* ARGSUSED */
3895 int
3896 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3897            struct thread *td, struct mbuf **mrq)
3898 {
3899         struct mbuf *mrep = nfsd->nd_mrep;
3900         caddr_t bpos;
3901         int error = NFSERR_RETVOID, cache;
3902         struct mbuf *mb, *mreq;
3903         u_quad_t frev;
3904
3905         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3906 #ifndef nolint
3907         cache = 0;
3908 #endif
3909         nfsm_reply(0);
3910         nfsm_srvdone;
3911 }
3912
3913 /*
3914  * No operation, used for obsolete procedures
3915  */
3916 /* ARGSUSED */
3917 int
3918 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3919            struct thread *td, struct mbuf **mrq)
3920 {
3921         struct mbuf *mrep = nfsd->nd_mrep;
3922         caddr_t bpos;
3923         int error, cache;
3924         struct mbuf *mb, *mreq;
3925         u_quad_t frev;
3926
3927         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3928 #ifndef nolint
3929         cache = 0;
3930 #endif
3931         if (nfsd->nd_repstat)
3932                 error = nfsd->nd_repstat;
3933         else
3934                 error = EPROCUNAVAIL;
3935         nfsm_reply(0);
3936         error = 0;
3937         nfsm_srvdone;
3938 }
3939
3940 /*
3941  * Perform access checking for vnodes obtained from file handles that would
3942  * refer to files already opened by a Unix client. You cannot just use
3943  * vn_writechk() and VOP_ACCESS() for two reasons.
3944  * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
3945  * 2 - The owner is to be given access irrespective of mode bits for some
3946  *     operations, so that processes that chmod after opening a file don't
3947  *     break. I don't like this because it opens a security hole, but since
3948  *     the nfs server opens a security hole the size of a barn door anyhow,
3949  *     what the heck.
3950  *
3951  * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
3952  * will return EPERM instead of EACCESS. EPERM is always an error.
3953  */
3954 static int
3955 nfsrv_access(struct vnode *vp, int flags, struct ucred *cred,
3956              int rdonly, struct thread *td, int override)
3957 {
3958         struct vattr vattr;
3959         int error;
3960
3961         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3962         if (flags & VWRITE) {
3963                 /* Just vn_writechk() changed to check rdonly */
3964                 /*
3965                  * Disallow write attempts on read-only file systems;
3966                  * unless the file is a socket or a block or character
3967                  * device resident on the file system.
3968                  */
3969                 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3970                         switch (vp->v_type) {
3971                         case VREG:
3972                         case VDIR:
3973                         case VLNK:
3974                                 return (EROFS);
3975                         default:
3976                                 break;
3977                         }
3978                 }
3979                 /*
3980                  * If there's shared text associated with
3981                  * the inode, we can't allow writing.
3982                  */
3983                 if (vp->v_flag & VTEXT)
3984                         return (ETXTBSY);
3985         }
3986         error = VOP_GETATTR(vp, &vattr, td);
3987         if (error)
3988                 return (error);
3989         error = VOP_ACCESS(vp, flags, cred, td);
3990         /*
3991          * Allow certain operations for the owner (reads and writes
3992          * on files that are already open).
3993          */
3994         if (override && error == EACCES && cred->cr_uid == vattr.va_uid)
3995                 error = 0;
3996         return error;
3997 }
3998 #endif /* NFS_NOSERVER */
3999