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