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