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