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