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