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