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