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