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