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