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