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