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