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