kernel/vfs: Remove some unused variables.
[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 $
38 */
39
40/*
41 * nfs version 2 and 3 server calls to vnode ops
42 * - these routines generally have 3 phases
43 * 1 - break down and validate rpc request in mbuf list
44 * 2 - do the vnode ops for the request
45 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
46 * 3 - build the rpc reply in an mbuf list
47 * nb:
48 * - do not mix the phases, since the nfsm_?? macros can return failures
49 * on a bad rpc or similar and do not do any vrele() or vput()'s
50 *
51 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
52 * error number iff error != 0 whereas
53 * returning an error from the server function implies a fatal error
54 * such as a badly constructed rpc request that should be dropped without
55 * a reply.
56 * For Version 3, nfsm_reply() does not return for the error case, since
57 * most version 3 rpcs return more than the status for error cases.
58 *
59 * Other notes:
60 * Warning: always pay careful attention to resource cleanup on return
61 * and note that nfsm_*() macros can terminate a procedure on certain
62 * errors.
984263bc
MD
63 */
64
65#include <sys/param.h>
66#include <sys/systm.h>
67#include <sys/proc.h>
895c1f85 68#include <sys/priv.h>
fad57d0e 69#include <sys/nlookup.h>
984263bc
MD
70#include <sys/namei.h>
71#include <sys/unistd.h>
72#include <sys/vnode.h>
73#include <sys/mount.h>
74#include <sys/socket.h>
75#include <sys/socketvar.h>
76#include <sys/malloc.h>
77#include <sys/mbuf.h>
78#include <sys/dirent.h>
79#include <sys/stat.h>
80#include <sys/kernel.h>
81#include <sys/sysctl.h>
82#include <sys/buf.h>
83
84#include <vm/vm.h>
85#include <vm/vm_extern.h>
984263bc
MD
86#include <vm/vm_object.h>
87
3020e3be
MD
88#include <sys/buf2.h>
89
165dba55
DR
90#include <sys/thread2.h>
91
1f2de5d4
MD
92#include "nfsproto.h"
93#include "rpcv2.h"
94#include "nfs.h"
95#include "xdr_subs.h"
96#include "nfsm_subs.h"
984263bc
MD
97
98#ifdef NFSRV_DEBUG
086c1d7e 99#define nfsdbprintf(info) kprintf info
984263bc
MD
100#else
101#define nfsdbprintf(info)
102#endif
103
e820d193 104#define MAX_REORDERED_RPC (16)
984263bc
MD
105#define MAX_COMMIT_COUNT (1024 * 1024)
106
a084b5c3 107#define NUM_HEURISTIC 1031
984263bc
MD
108#define NHUSE_INIT 64
109#define NHUSE_INC 16
110#define NHUSE_MAX 2048
111
112static struct nfsheur {
113 struct vnode *nh_vp; /* vp to match (unreferenced pointer) */
a084b5c3 114 off_t nh_nextoff; /* next offset for sequential detection */
984263bc
MD
115 int nh_use; /* use count for selection */
116 int nh_seqcount; /* heuristic */
117} nfsheur[NUM_HEURISTIC];
118
119nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
120 NFFIFO, NFNON };
121#ifndef NFS_NOSERVER
122nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
123 NFCHR, NFNON };
984263bc
MD
124
125int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
126int nfsrvw_procrastinate_v3 = 0;
127
3a6f9faf 128static struct timespec nfsver;
984263bc
MD
129
130SYSCTL_DECL(_vfs_nfs);
131
a482a28a 132int nfs_async;
093e85dc
SG
133SYSCTL_INT(_vfs_nfs, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
134 "Enable unstable and fast writes");
984263bc
MD
135static int nfs_commit_blks;
136static int nfs_commit_miss;
093e85dc 137SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks, 0,
d3977199 138 "Number of committed blocks");
093e85dc
SG
139SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss, 0,
140 "Number of nfs blocks committed from dirty buffers");
984263bc 141
67863d04
MD
142static int nfsrv_access (struct mount *, struct vnode *, int,
143 struct ucred *, int, struct thread *, int);
a6ee311a
RG
144static void nfsrvw_coalesce (struct nfsrv_descript *,
145 struct nfsrv_descript *);
984263bc 146
a084b5c3
VS
147/*
148 * Heuristic to detect sequential operation.
149 */
150static struct nfsheur *
151nfsrv_sequential_heuristic(struct uio *uio, struct vnode *vp, int writeop)
152{
153 struct nfsheur *nh;
154 int hi, try;
155
156 /* Locate best candidate */
157 try = 32;
158 hi = ((int)(vm_offset_t) vp / sizeof(struct vnode)) % NUM_HEURISTIC;
159 nh = &nfsheur[hi];
160
161 while (try--) {
162 if (nfsheur[hi].nh_vp == vp) {
163 nh = &nfsheur[hi];
164 break;
165 }
166 if (nfsheur[hi].nh_use > 0)
167 --nfsheur[hi].nh_use;
168 hi = (hi + 1) % NUM_HEURISTIC;
169 if (nfsheur[hi].nh_use < nh->nh_use)
170 nh = &nfsheur[hi];
171 }
172
173 /* Initialize hint if this is a new file */
174 if (nh->nh_vp != vp) {
175 nh->nh_vp = vp;
176 nh->nh_nextoff = uio->uio_offset;
177 nh->nh_use = NHUSE_INIT;
178 if (uio->uio_offset == 0)
179 nh->nh_seqcount = 4;
180 else
181 nh->nh_seqcount = 1;
182 }
183
184 /*
185 * Calculate heuristic
186 *
187 * See vfs_vnops.c:sequential_heuristic().
188 */
189 if ((uio->uio_offset == 0 && nh->nh_seqcount > 0) ||
190 uio->uio_offset == nh->nh_nextoff) {
191 nh->nh_seqcount += howmany(uio->uio_resid, 16384);
192 if (nh->nh_seqcount > IO_SEQMAX)
193 nh->nh_seqcount = IO_SEQMAX;
e820d193
VS
194 } else if (qabs(uio->uio_offset - nh->nh_nextoff) <= MAX_REORDERED_RPC *
195 imax(vp->v_mount->mnt_stat.f_iosize, uio->uio_resid)) {
196 /* Probably a reordered RPC, leave seqcount alone. */
a084b5c3 197 } else if (nh->nh_seqcount > 1) {
e820d193 198 nh->nh_seqcount /= 2;
a084b5c3
VS
199 } else {
200 nh->nh_seqcount = 0;
201 }
202 nh->nh_use += NHUSE_INC;
203 if (nh->nh_use > NHUSE_MAX)
204 nh->nh_use = NHUSE_MAX;
205 return (nh);
206}
207
984263bc
MD
208/*
209 * nfs v3 access service
210 */
211int
dadab5e9 212nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
e851b29e 213 struct thread *td, struct mbuf **mrq)
984263bc 214{
984263bc 215 struct sockaddr *nam = nfsd->nd_nam;
984263bc
MD
216 struct ucred *cred = &nfsd->nd_cr;
217 struct vnode *vp = NULL;
67863d04 218 struct mount *mp = NULL;
984263bc
MD
219 nfsfh_t nfh;
220 fhandle_t *fhp;
e07fef60 221 int error = 0, rdonly, getret;
984263bc
MD
222 struct vattr vattr, *vap = &vattr;
223 u_long testmode, nfsmode;
42edf14f
MD
224 struct nfsm_info info;
225 u_int32_t *tl;
226
227 info.dpos = nfsd->nd_dpos;
228 info.md = nfsd->nd_md;
229 info.mrep = nfsd->nd_mrep;
230 info.mreq = NULL;
984263bc
MD
231
232 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
984263bc 233 fhp = &nfh.fh_generic;
42edf14f
MD
234 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
235 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
67863d04 236 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, &rdonly,
984263bc
MD
237 (nfsd->nd_flag & ND_KERBAUTH), TRUE);
238 if (error) {
42edf14f
MD
239 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error));
240 nfsm_srvpostop_attr(&info, nfsd, 1, NULL);
984263bc
MD
241 error = 0;
242 goto nfsmout;
243 }
244 nfsmode = fxdr_unsigned(u_int32_t, *tl);
245 if ((nfsmode & NFSV3ACCESS_READ) &&
67863d04 246 nfsrv_access(mp, vp, VREAD, cred, rdonly, td, 0))
984263bc
MD
247 nfsmode &= ~NFSV3ACCESS_READ;
248 if (vp->v_type == VDIR)
249 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
250 NFSV3ACCESS_DELETE);
251 else
252 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
253 if ((nfsmode & testmode) &&
67863d04 254 nfsrv_access(mp, vp, VWRITE, cred, rdonly, td, 0))
984263bc
MD
255 nfsmode &= ~testmode;
256 if (vp->v_type == VDIR)
257 testmode = NFSV3ACCESS_LOOKUP;
258 else
259 testmode = NFSV3ACCESS_EXECUTE;
260 if ((nfsmode & testmode) &&
67863d04 261 nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0))
984263bc 262 nfsmode &= ~testmode;
87de5057 263 getret = VOP_GETATTR(vp, vap);
984263bc
MD
264 vput(vp);
265 vp = NULL;
42edf14f
MD
266 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
267 NFSX_POSTOPATTR(1) + NFSX_UNSIGNED, &error));
268 nfsm_srvpostop_attr(&info, nfsd, getret, vap);
269 tl = nfsm_build(&info, NFSX_UNSIGNED);
984263bc
MD
270 *tl = txdr_unsigned(nfsmode);
271nfsmout:
42edf14f 272 *mrq = info.mreq;
984263bc
MD
273 if (vp)
274 vput(vp);
275 return(error);
276}
277
278/*
279 * nfs getattr service
280 */
281int
e851b29e
CP
282nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
283 struct thread *td, struct mbuf **mrq)
984263bc 284{
984263bc 285 struct sockaddr *nam = nfsd->nd_nam;
984263bc 286 struct ucred *cred = &nfsd->nd_cr;
dadab5e9 287 struct nfs_fattr *fp;
984263bc 288 struct vattr va;
dadab5e9 289 struct vattr *vap = &va;
984263bc 290 struct vnode *vp = NULL;
67863d04 291 struct mount *mp = NULL;
984263bc
MD
292 nfsfh_t nfh;
293 fhandle_t *fhp;
e07fef60 294 int error = 0, rdonly;
42edf14f
MD
295 struct nfsm_info info;
296
297 info.mrep = nfsd->nd_mrep;
298 info.md = nfsd->nd_md;
299 info.dpos = nfsd->nd_dpos;
300 info.mreq = NULL;
984263bc
MD
301
302 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
303 fhp = &nfh.fh_generic;
42edf14f 304 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
67863d04 305 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
984263bc
MD
306 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
307 if (error) {
42edf14f 308 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error));
984263bc
MD
309 error = 0;
310 goto nfsmout;
311 }
87de5057 312 error = VOP_GETATTR(vp, vap);
984263bc
MD
313 vput(vp);
314 vp = NULL;
42edf14f
MD
315 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
316 NFSX_FATTR(nfsd->nd_flag & ND_NFSV3), &error));
984263bc
MD
317 if (error) {
318 error = 0;
319 goto nfsmout;
320 }
42edf14f
MD
321 fp = nfsm_build(&info, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
322 nfsm_srvfattr(nfsd, vap, fp);
984263bc
MD
323 /* fall through */
324
325nfsmout:
42edf14f 326 *mrq = info.mreq;
984263bc
MD
327 if (vp)
328 vput(vp);
329 return(error);
330}
331
332/*
333 * nfs setattr service
334 */
335int
e851b29e
CP
336nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
337 struct thread *td, struct mbuf **mrq)
984263bc 338{
984263bc 339 struct sockaddr *nam = nfsd->nd_nam;
984263bc
MD
340 struct ucred *cred = &nfsd->nd_cr;
341 struct vattr va, preat;
dadab5e9
MD
342 struct vattr *vap = &va;
343 struct nfsv2_sattr *sp;
344 struct nfs_fattr *fp;
984263bc 345 struct vnode *vp = NULL;
67863d04 346 struct mount *mp = NULL;
984263bc
MD
347 nfsfh_t nfh;
348 fhandle_t *fhp;
dadab5e9 349 u_int32_t *tl;
e07fef60 350 int error = 0, rdonly, preat_ret = 1, postat_ret = 1;
42edf14f 351 int gcheck = 0;
984263bc 352 struct timespec guard;
42edf14f
MD
353 struct nfsm_info info;
354
355 info.mrep = nfsd->nd_mrep;
356 info.mreq = NULL;
357 info.md = nfsd->nd_md;
358 info.dpos = nfsd->nd_dpos;
359 info.v3 = (nfsd->nd_flag & ND_NFSV3);
984263bc 360
d557216f
MD
361 guard.tv_sec = 0; /* fix compiler warning */
362 guard.tv_nsec = 0;
363
984263bc
MD
364 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
365 fhp = &nfh.fh_generic;
42edf14f 366 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
984263bc 367 VATTR_NULL(vap);
42edf14f
MD
368 if (info.v3) {
369 ERROROUT(nfsm_srvsattr(&info, vap));
370 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
984263bc
MD
371 gcheck = fxdr_unsigned(int, *tl);
372 if (gcheck) {
42edf14f 373 NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED));
984263bc
MD
374 fxdr_nfsv3time(tl, &guard);
375 }
376 } else {
42edf14f 377 NULLOUT(sp = nfsm_dissect(&info, NFSX_V2SATTR));
984263bc
MD
378 /*
379 * Nah nah nah nah na nah
380 * There is a bug in the Sun client that puts 0xffff in the mode
381 * field of sattr when it should put in 0xffffffff. The u_short
382 * doesn't sign extend.
383 * --> check the low order 2 bytes for 0xffff
384 */
385 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
386 vap->va_mode = nfstov_mode(sp->sa_mode);
387 if (sp->sa_uid != nfs_xdrneg1)
388 vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
389 if (sp->sa_gid != nfs_xdrneg1)
390 vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
391 if (sp->sa_size != nfs_xdrneg1)
392 vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
393 if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
394#ifdef notyet
395 fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime);
396#else
397 vap->va_atime.tv_sec =
398 fxdr_unsigned(int32_t, sp->sa_atime.nfsv2_sec);
399 vap->va_atime.tv_nsec = 0;
400#endif
401 }
402 if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
403 fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
404
405 }
406
407 /*
408 * Now that we have all the fields, lets do it.
409 */
67863d04 410 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, &rdonly,
984263bc
MD
411 (nfsd->nd_flag & ND_KERBAUTH), TRUE);
412 if (error) {
42edf14f
MD
413 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
414 2 * NFSX_UNSIGNED, &error));
415 nfsm_srvwcc_data(&info, nfsd, preat_ret, &preat,
416 postat_ret, vap);
984263bc
MD
417 error = 0;
418 goto nfsmout;
419 }
420
421 /*
422 * vp now an active resource, pay careful attention to cleanup
423 */
424
42edf14f 425 if (info.v3) {
87de5057 426 error = preat_ret = VOP_GETATTR(vp, &preat);
984263bc
MD
427 if (!error && gcheck &&
428 (preat.va_ctime.tv_sec != guard.tv_sec ||
429 preat.va_ctime.tv_nsec != guard.tv_nsec))
430 error = NFSERR_NOT_SYNC;
431 if (error) {
432 vput(vp);
433 vp = NULL;
42edf14f
MD
434 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
435 NFSX_WCCDATA(info.v3), &error));
436 nfsm_srvwcc_data(&info, nfsd, preat_ret, &preat,
437 postat_ret, vap);
984263bc
MD
438 error = 0;
439 goto nfsmout;
440 }
441 }
442
443 /*
444 * If the size is being changed write acces is required, otherwise
445 * just check for a read only file system.
446 */
447 if (vap->va_size == ((u_quad_t)((quad_t) -1))) {
67863d04 448 if (rdonly || (mp->mnt_flag & MNT_RDONLY)) {
984263bc
MD
449 error = EROFS;
450 goto out;
451 }
452 } else {
453 if (vp->v_type == VDIR) {
454 error = EISDIR;
455 goto out;
67863d04 456 } else if ((error = nfsrv_access(mp, vp, VWRITE, cred, rdonly,
dadab5e9 457 td, 0)) != 0){
984263bc 458 goto out;
dadab5e9 459 }
984263bc 460 }
87de5057
MD
461 error = VOP_SETATTR(vp, vap, cred);
462 postat_ret = VOP_GETATTR(vp, vap);
984263bc
MD
463 if (!error)
464 error = postat_ret;
465out:
466 vput(vp);
467 vp = NULL;
42edf14f
MD
468 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
469 NFSX_WCCORFATTR(info.v3), &error));
470 if (info.v3) {
471 nfsm_srvwcc_data(&info, nfsd, preat_ret, &preat,
472 postat_ret, vap);
984263bc
MD
473 error = 0;
474 goto nfsmout;
475 } else {
42edf14f
MD
476 fp = nfsm_build(&info, NFSX_V2FATTR);
477 nfsm_srvfattr(nfsd, vap, fp);
984263bc
MD
478 }
479 /* fall through */
480
481nfsmout:
42edf14f 482 *mrq = info.mreq;
984263bc
MD
483 if (vp)
484 vput(vp);
485 return(error);
486}
487
488/*
489 * nfs lookup rpc
490 */
491int
e851b29e
CP
492nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
493 struct thread *td, struct mbuf **mrq)
984263bc 494{
984263bc 495 struct sockaddr *nam = nfsd->nd_nam;
984263bc 496 struct ucred *cred = &nfsd->nd_cr;
dadab5e9 497 struct nfs_fattr *fp;
fad57d0e
MD
498 struct nlookupdata nd;
499 struct vnode *vp;
500 struct vnode *dirp;
28623bf9 501 struct nchandle nch;
984263bc
MD
502 nfsfh_t nfh;
503 fhandle_t *fhp;
e07fef60 504 int error = 0, len, dirattr_ret = 1;
42edf14f 505 int pubflag;
984263bc 506 struct vattr va, dirattr, *vap = &va;
42edf14f
MD
507 struct nfsm_info info;
508
509 info.mrep = nfsd->nd_mrep;
510 info.mreq = NULL;
511 info.md = nfsd->nd_md;
512 info.dpos = nfsd->nd_dpos;
513 info.v3 = (nfsd->nd_flag & ND_NFSV3);
984263bc
MD
514
515 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fad57d0e
MD
516 nlookup_zero(&nd);
517 dirp = NULL;
518 vp = NULL;
984263bc
MD
519
520 fhp = &nfh.fh_generic;
42edf14f
MD
521 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
522 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
984263bc
MD
523
524 pubflag = nfs_ispublicfh(fhp);
525
3a907475 526 error = nfs_namei(&nd, cred, 0, NULL, &vp,
42edf14f 527 fhp, len, slp, nam, &info.md, &info.dpos,
dadab5e9 528 &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), pubflag);
984263bc
MD
529
530 /*
531 * namei failure, only dirp to cleanup. Clear out garbarge from
532 * structure in case macros jump to nfsmout.
533 */
534
535 if (error) {
536 if (dirp) {
42edf14f 537 if (info.v3)
87de5057 538 dirattr_ret = VOP_GETATTR(dirp, &dirattr);
984263bc
MD
539 vrele(dirp);
540 dirp = NULL;
541 }
42edf14f
MD
542 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
543 NFSX_POSTOPATTR(info.v3), &error));
544 nfsm_srvpostop_attr(&info, nfsd, dirattr_ret, &dirattr);
984263bc
MD
545 error = 0;
546 goto nfsmout;
547 }
548
549 /*
550 * Locate index file for public filehandle
551 *
552 * error is 0 on entry and 0 on exit from this block.
553 */
554
555 if (pubflag) {
fad57d0e 556 if (vp->v_type == VDIR && nfs_pub.np_index != NULL) {
984263bc
MD
557 /*
558 * Setup call to lookup() to see if we can find
559 * the index file. Arguably, this doesn't belong
560 * in a kernel.. Ugh. If an error occurs, do not
561 * try to install an index file and then clear the
562 * error.
563 *
564 * When we replace nd with ind and redirect ndp,
565 * maintenance of ni_startdir and ni_vp shift to
566 * ind and we have to clean them up in the old nd.
567 * However, the cnd resource continues to be maintained
568 * via the original nd. Confused? You aren't alone!
569 */
a11aaa81 570 vn_unlock(vp);
28623bf9 571 cache_copy(&nd.nl_nch, &nch);
fad57d0e
MD
572 nlookup_done(&nd);
573 error = nlookup_init_raw(&nd, nfs_pub.np_index,
28623bf9
MD
574 UIO_SYSSPACE, 0, cred, &nch);
575 cache_drop(&nch);
fad57d0e
MD
576 if (error == 0)
577 error = nlookup(&nd);
984263bc
MD
578
579 if (error == 0) {
580 /*
581 * Found an index file. Get rid of
fad57d0e
MD
582 * the old references. transfer vp and
583 * load up the new vp. Fortunately we do
584 * not have to deal with dvp, that would be
585 * a huge mess.
984263bc
MD
586 */
587 if (dirp)
588 vrele(dirp);
fad57d0e
MD
589 dirp = vp;
590 vp = NULL;
28623bf9 591 error = cache_vget(&nd.nl_nch, nd.nl_cred,
fad57d0e
MD
592 LK_EXCLUSIVE, &vp);
593 KKASSERT(error == 0);
984263bc
MD
594 }
595 error = 0;
596 }
597 /*
598 * If the public filehandle was used, check that this lookup
599 * didn't result in a filehandle outside the publicly exported
600 * filesystem. We clear the poor vp here to avoid lockups due
601 * to NFS I/O.
602 */
603
fad57d0e
MD
604 if (vp->v_mount != nfs_pub.np_mount) {
605 vput(vp);
606 vp = NULL;
984263bc
MD
607 error = EPERM;
608 }
609 }
610
611 if (dirp) {
42edf14f 612 if (info.v3)
87de5057 613 dirattr_ret = VOP_GETATTR(dirp, &dirattr);
984263bc
MD
614 vrele(dirp);
615 dirp = NULL;
616 }
617
618 /*
619 * Resources at this point:
620 * ndp->ni_vp may not be NULL
621 *
622 */
623
624 if (error) {
42edf14f
MD
625 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
626 NFSX_POSTOPATTR(info.v3), &error));
627 nfsm_srvpostop_attr(&info, nfsd, dirattr_ret, &dirattr);
984263bc
MD
628 error = 0;
629 goto nfsmout;
630 }
631
984263bc
MD
632 /*
633 * Clear out some resources prior to potentially blocking. This
634 * is not as critical as ni_dvp resources in other routines, but
635 * it helps.
636 */
fad57d0e 637 nlookup_done(&nd);
984263bc
MD
638
639 /*
640 * Get underlying attribute, then release remaining resources ( for
641 * the same potential blocking reason ) and reply.
642 */
67863d04 643 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid));
984263bc
MD
644 error = VFS_VPTOFH(vp, &fhp->fh_fid);
645 if (!error)
87de5057 646 error = VOP_GETATTR(vp, vap);
984263bc
MD
647
648 vput(vp);
fad57d0e 649 vp = NULL;
42edf14f
MD
650 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
651 NFSX_SRVFH(info.v3) +
652 NFSX_POSTOPORFATTR(info.v3) +
653 NFSX_POSTOPATTR(info.v3),
654 &error));
984263bc 655 if (error) {
42edf14f 656 nfsm_srvpostop_attr(&info, nfsd, dirattr_ret, &dirattr);
984263bc
MD
657 error = 0;
658 goto nfsmout;
659 }
42edf14f
MD
660 nfsm_srvfhtom(&info, fhp);
661 if (info.v3) {
662 nfsm_srvpostop_attr(&info, nfsd, 0, vap);
663 nfsm_srvpostop_attr(&info, nfsd, dirattr_ret, &dirattr);
984263bc 664 } else {
42edf14f
MD
665 fp = nfsm_build(&info, NFSX_V2FATTR);
666 nfsm_srvfattr(nfsd, vap, fp);
984263bc
MD
667 }
668
669nfsmout:
42edf14f 670 *mrq = info.mreq;
984263bc
MD
671 if (dirp)
672 vrele(dirp);
fad57d0e
MD
673 nlookup_done(&nd); /* may be called twice */
674 if (vp)
675 vput(vp);
984263bc
MD
676 return (error);
677}
678
679/*
680 * nfs readlink service
681 */
682int
e851b29e
CP
683nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
684 struct thread *td, struct mbuf **mrq)
984263bc 685{
984263bc 686 struct sockaddr *nam = nfsd->nd_nam;
984263bc
MD
687 struct ucred *cred = &nfsd->nd_cr;
688 struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
dadab5e9 689 struct iovec *ivp = iv;
dadab5e9 690 u_int32_t *tl;
e07fef60 691 int error = 0, rdonly, i, tlen, len, getret;
42edf14f 692 struct mbuf *mp1, *mp2, *mp3;
984263bc 693 struct vnode *vp = NULL;
67863d04 694 struct mount *mp = NULL;
984263bc
MD
695 struct vattr attr;
696 nfsfh_t nfh;
697 fhandle_t *fhp;
698 struct uio io, *uiop = &io;
42edf14f
MD
699 struct nfsm_info info;
700
701 info.mrep = nfsd->nd_mrep;
702 info.mreq = NULL;
703 info.md = nfsd->nd_md;
704 info.dpos = nfsd->nd_dpos;
705 info.v3 = (nfsd->nd_flag & ND_NFSV3);
984263bc 706
e020caea
VS
707 bzero(&io, sizeof(struct uio));
708
984263bc
MD
709 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
710#ifndef nolint
60233e58 711 mp2 = NULL;
984263bc
MD
712#endif
713 mp3 = NULL;
714 fhp = &nfh.fh_generic;
42edf14f 715 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
984263bc
MD
716 len = 0;
717 i = 0;
718 while (len < NFS_MAXPATHLEN) {
67863d04
MD
719 mp1 = m_getcl(MB_WAIT, MT_DATA, 0);
720 mp1->m_len = MCLBYTES;
984263bc 721 if (len == 0)
67863d04 722 mp3 = mp2 = mp1;
984263bc 723 else {
67863d04
MD
724 mp2->m_next = mp1;
725 mp2 = mp1;
984263bc 726 }
67863d04
MD
727 if ((len + mp1->m_len) > NFS_MAXPATHLEN) {
728 mp1->m_len = NFS_MAXPATHLEN-len;
984263bc
MD
729 len = NFS_MAXPATHLEN;
730 } else
67863d04
MD
731 len += mp1->m_len;
732 ivp->iov_base = mtod(mp1, caddr_t);
733 ivp->iov_len = mp1->m_len;
984263bc
MD
734 i++;
735 ivp++;
736 }
737 uiop->uio_iov = iv;
738 uiop->uio_iovcnt = i;
739 uiop->uio_offset = 0;
740 uiop->uio_resid = len;
741 uiop->uio_rw = UIO_READ;
742 uiop->uio_segflg = UIO_SYSSPACE;
dadab5e9 743 uiop->uio_td = NULL;
67863d04 744 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
984263bc
MD
745 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
746 if (error) {
42edf14f
MD
747 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
748 2 * NFSX_UNSIGNED, &error));
749 nfsm_srvpostop_attr(&info, nfsd, 1, NULL);
984263bc
MD
750 error = 0;
751 goto nfsmout;
752 }
753 if (vp->v_type != VLNK) {
42edf14f 754 if (info.v3)
984263bc
MD
755 error = EINVAL;
756 else
757 error = ENXIO;
758 goto out;
759 }
984263bc
MD
760 error = VOP_READLINK(vp, uiop, cred);
761out:
87de5057 762 getret = VOP_GETATTR(vp, &attr);
984263bc
MD
763 vput(vp);
764 vp = NULL;
42edf14f
MD
765 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
766 NFSX_POSTOPATTR(info.v3) + NFSX_UNSIGNED,
767 &error));
768 if (info.v3) {
769 nfsm_srvpostop_attr(&info, nfsd, getret, &attr);
984263bc
MD
770 if (error) {
771 error = 0;
772 goto nfsmout;
773 }
774 }
775 if (uiop->uio_resid > 0) {
776 len -= uiop->uio_resid;
777 tlen = nfsm_rndup(len);
778 nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
779 }
42edf14f 780 tl = nfsm_build(&info, NFSX_UNSIGNED);
984263bc 781 *tl = txdr_unsigned(len);
42edf14f 782 info.mb->m_next = mp3;
984263bc
MD
783 mp3 = NULL;
784nfsmout:
42edf14f 785 *mrq = info.mreq;
984263bc
MD
786 if (mp3)
787 m_freem(mp3);
788 if (vp)
789 vput(vp);
790 return(error);
791}
792
793/*
794 * nfs read service
795 */
796int
e851b29e
CP
797nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
798 struct thread *td, struct mbuf **mrq)
984263bc 799{
42edf14f 800 struct nfsm_info info;
984263bc 801 struct sockaddr *nam = nfsd->nd_nam;
984263bc 802 struct ucred *cred = &nfsd->nd_cr;
dadab5e9 803 struct iovec *iv;
984263bc 804 struct iovec *iv2;
dadab5e9
MD
805 struct mbuf *m;
806 struct nfs_fattr *fp;
807 u_int32_t *tl;
dadab5e9 808 int i;
42edf14f 809 int reqlen;
e07fef60 810 int error = 0, rdonly, cnt, len, left, siz, tlen, getret;
984263bc
MD
811 struct mbuf *m2;
812 struct vnode *vp = NULL;
67863d04 813 struct mount *mp = NULL;
984263bc
MD
814 nfsfh_t nfh;
815 fhandle_t *fhp;
816 struct uio io, *uiop = &io;
817 struct vattr va, *vap = &va;
818 struct nfsheur *nh;
819 off_t off;
820 int ioflag = 0;
984263bc 821
42edf14f
MD
822 info.mrep = nfsd->nd_mrep;
823 info.mreq = NULL;
824 info.md = nfsd->nd_md;
825 info.dpos = nfsd->nd_dpos;
826 info.v3 = (nfsd->nd_flag & ND_NFSV3);
827
984263bc
MD
828 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
829 fhp = &nfh.fh_generic;
42edf14f
MD
830 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
831 if (info.v3) {
832 NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED));
984263bc
MD
833 off = fxdr_hyper(tl);
834 } else {
42edf14f 835 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
984263bc
MD
836 off = (off_t)fxdr_unsigned(u_int32_t, *tl);
837 }
42edf14f
MD
838 NEGREPLYOUT(reqlen = nfsm_srvstrsiz(&info,
839 NFS_SRVMAXDATA(nfsd), &error));
984263bc
MD
840
841 /*
842 * Reference vp. If an error occurs, vp will be invalid, but we
843 * have to NULL it just in case. The macros might goto nfsmout
844 * as well.
845 */
846
67863d04 847 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
984263bc
MD
848 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
849 if (error) {
850 vp = NULL;
42edf14f
MD
851 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
852 2 * NFSX_UNSIGNED, &error));
853 nfsm_srvpostop_attr(&info, nfsd, 1, NULL);
984263bc
MD
854 error = 0;
855 goto nfsmout;
856 }
857
858 if (vp->v_type != VREG) {
42edf14f 859 if (info.v3)
984263bc
MD
860 error = EINVAL;
861 else
862 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
863 }
864 if (!error) {
67863d04
MD
865 if ((error = nfsrv_access(mp, vp, VREAD, cred, rdonly, td, 1)) != 0)
866 error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 1);
984263bc 867 }
87de5057 868 getret = VOP_GETATTR(vp, vap);
984263bc
MD
869 if (!error)
870 error = getret;
871 if (error) {
872 vput(vp);
873 vp = NULL;
42edf14f
MD
874 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
875 NFSX_POSTOPATTR(info.v3), &error));
876 nfsm_srvpostop_attr(&info, nfsd, getret, vap);
984263bc
MD
877 error = 0;
878 goto nfsmout;
879 }
880
881 /*
882 * Calculate byte count to read
883 */
884
885 if (off >= vap->va_size)
886 cnt = 0;
887 else if ((off + reqlen) > vap->va_size)
888 cnt = vap->va_size - off;
889 else
890 cnt = reqlen;
891
42edf14f
MD
892 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
893 NFSX_POSTOPORFATTR(info.v3) +
894 3 * NFSX_UNSIGNED + nfsm_rndup(cnt),
895 &error));
896 if (info.v3) {
897 tl = nfsm_build(&info, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
984263bc
MD
898 *tl++ = nfs_true;
899 fp = (struct nfs_fattr *)tl;
900 tl += (NFSX_V3FATTR / sizeof (u_int32_t));
901 } else {
42edf14f 902 tl = nfsm_build(&info, NFSX_V2FATTR + NFSX_UNSIGNED);
984263bc
MD
903 fp = (struct nfs_fattr *)tl;
904 tl += (NFSX_V2FATTR / sizeof (u_int32_t));
905 }
906 len = left = nfsm_rndup(cnt);
907 if (cnt > 0) {
908 /*
909 * Generate the mbuf list with the uio_iov ref. to it.
910 */
911 i = 0;
42edf14f 912 m = m2 = info.mb;
984263bc
MD
913 while (left > 0) {
914 siz = min(M_TRAILINGSPACE(m), left);
915 if (siz > 0) {
916 left -= siz;
917 i++;
918 }
919 if (left > 0) {
50503f0f 920 m = m_getcl(MB_WAIT, MT_DATA, 0);
984263bc
MD
921 m->m_len = 0;
922 m2->m_next = m;
923 m2 = m;
924 }
925 }
884717e1 926 iv = kmalloc(i * sizeof(struct iovec), M_TEMP, M_WAITOK);
984263bc 927 uiop->uio_iov = iv2 = iv;
42edf14f 928 m = info.mb;
984263bc
MD
929 left = len;
930 i = 0;
931 while (left > 0) {
932 if (m == NULL)
933 panic("nfsrv_read iov");
934 siz = min(M_TRAILINGSPACE(m), left);
935 if (siz > 0) {
936 iv->iov_base = mtod(m, caddr_t) + m->m_len;
937 iv->iov_len = siz;
938 m->m_len += siz;
939 left -= siz;
940 iv++;
941 i++;
942 }
943 m = m->m_next;
944 }
945 uiop->uio_iovcnt = i;
946 uiop->uio_offset = off;
947 uiop->uio_resid = len;
948 uiop->uio_rw = UIO_READ;
949 uiop->uio_segflg = UIO_SYSSPACE;
a084b5c3
VS
950 nh = nfsrv_sequential_heuristic(uiop, vp, 0);
951 ioflag |= nh->nh_seqcount << IO_SEQSHIFT;
984263bc 952 error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred);
a084b5c3
VS
953 if (error == 0) {
954 off = uiop->uio_offset;
955 nh->nh_nextoff = off;
956 }
884717e1 957 kfree((caddr_t)iv2, M_TEMP);
87de5057 958 if (error || (getret = VOP_GETATTR(vp, vap))) {
984263bc
MD
959 if (!error)
960 error = getret;
42edf14f
MD
961 m_freem(info.mreq);
962 info.mreq = NULL;
984263bc
MD
963 vput(vp);
964 vp = NULL;
42edf14f
MD
965 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
966 NFSX_POSTOPATTR(info.v3),
967 &error));
968 nfsm_srvpostop_attr(&info, nfsd, getret, vap);
984263bc
MD
969 error = 0;
970 goto nfsmout;
971 }
972 } else {
973 uiop->uio_resid = 0;
974 }
975 vput(vp);
976 vp = NULL;
42edf14f 977 nfsm_srvfattr(nfsd, vap, fp);
984263bc
MD
978 tlen = len - uiop->uio_resid;
979 cnt = cnt < tlen ? cnt : tlen;
980 tlen = nfsm_rndup(cnt);
981 if (len != tlen || tlen != cnt)
42edf14f
MD
982 nfsm_adj(info.mb, len - tlen, tlen - cnt);
983 if (info.v3) {
984263bc 984 *tl++ = txdr_unsigned(cnt);
a084b5c3 985 if (cnt < reqlen)
984263bc
MD
986 *tl++ = nfs_true;
987 else
988 *tl++ = nfs_false;
989 }
990 *tl = txdr_unsigned(cnt);
991nfsmout:
42edf14f 992 *mrq = info.mreq;
984263bc
MD
993 if (vp)
994 vput(vp);
995 return(error);
996}
997
998/*
999 * nfs write service
1000 */
1001int
e851b29e
CP
1002nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1003 struct thread *td, struct mbuf **mrq)
984263bc 1004{
984263bc 1005 struct sockaddr *nam = nfsd->nd_nam;
984263bc 1006 struct ucred *cred = &nfsd->nd_cr;
dadab5e9
MD
1007 struct iovec *ivp;
1008 int i, cnt;
67863d04 1009 struct mbuf *mp1;
dadab5e9 1010 struct nfs_fattr *fp;
984263bc
MD
1011 struct iovec *iv;
1012 struct vattr va, forat;
dadab5e9
MD
1013 struct vattr *vap = &va;
1014 u_int32_t *tl;
e07fef60 1015 int error = 0, rdonly, len, forat_ret = 1;
984263bc
MD
1016 int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
1017 int stable = NFSV3WRITE_FILESYNC;
984263bc 1018 struct vnode *vp = NULL;
67863d04 1019 struct mount *mp = NULL;
a084b5c3 1020 struct nfsheur *nh;
984263bc
MD
1021 nfsfh_t nfh;
1022 fhandle_t *fhp;
1023 struct uio io, *uiop = &io;
42edf14f 1024 struct nfsm_info info;
984263bc 1025 off_t off;
984263bc 1026
42edf14f
MD
1027 info.mrep = nfsd->nd_mrep;
1028 info.mreq = NULL;
1029 info.md = nfsd->nd_md;
1030 info.dpos = nfsd->nd_dpos;
1031 info.v3 = (nfsd->nd_flag & ND_NFSV3);
1032
984263bc 1033 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
42edf14f 1034 if (info.mrep == NULL) {
984263bc
MD
1035 error = 0;
1036 goto nfsmout;
1037 }
1038 fhp = &nfh.fh_generic;
42edf14f
MD
1039 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
1040 if (info.v3) {
1041 NULLOUT(tl = nfsm_dissect(&info, 5 * NFSX_UNSIGNED));
984263bc
MD
1042 off = fxdr_hyper(tl);
1043 tl += 3;
1044 stable = fxdr_unsigned(int, *tl++);
1045 } else {
42edf14f 1046 NULLOUT(tl = nfsm_dissect(&info, 4 * NFSX_UNSIGNED));
984263bc
MD
1047 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
1048 tl += 2;
1049 if (nfs_async)
1050 stable = NFSV3WRITE_UNSTABLE;
1051 }
1052 retlen = len = fxdr_unsigned(int32_t, *tl);
1053 cnt = i = 0;
1054
1055 /*
1056 * For NFS Version 2, it is not obvious what a write of zero length
1057 * should do, but I might as well be consistent with Version 3,
1058 * which is to return ok so long as there are no permission problems.
1059 */
1060 if (len > 0) {
1061 zeroing = 1;
42edf14f 1062 mp1 = info.mrep;
67863d04 1063 while (mp1) {
42edf14f 1064 if (mp1 == info.md) {
984263bc 1065 zeroing = 0;
42edf14f 1066 adjust = info.dpos - mtod(mp1, caddr_t);
67863d04
MD
1067 mp1->m_len -= adjust;
1068 if (mp1->m_len > 0 && adjust > 0)
42edf14f 1069 mp1->m_data += adjust;
984263bc
MD
1070 }
1071 if (zeroing)
67863d04
MD
1072 mp1->m_len = 0;
1073 else if (mp1->m_len > 0) {
1074 i += mp1->m_len;
984263bc 1075 if (i > len) {
67863d04 1076 mp1->m_len -= (i - len);
984263bc
MD
1077 zeroing = 1;
1078 }
67863d04 1079 if (mp1->m_len > 0)
984263bc
MD
1080 cnt++;
1081 }
67863d04 1082 mp1 = mp1->m_next;
984263bc
MD
1083 }
1084 }
1085 if (len > NFS_MAXDATA || len < 0 || i < len) {
1086 error = EIO;
42edf14f
MD
1087 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1088 2 * NFSX_UNSIGNED, &error));
1089 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1090 aftat_ret, vap);
984263bc
MD
1091 error = 0;
1092 goto nfsmout;
1093 }
67863d04 1094 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
984263bc
MD
1095 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
1096 if (error) {
1097 vp = NULL;
42edf14f
MD
1098 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1099 2 * NFSX_UNSIGNED, &error));
1100 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1101 aftat_ret, vap);
984263bc
MD
1102 error = 0;
1103 goto nfsmout;
1104 }
42edf14f 1105 if (info.v3)
87de5057 1106 forat_ret = VOP_GETATTR(vp, &forat);
984263bc 1107 if (vp->v_type != VREG) {
42edf14f 1108 if (info.v3)
984263bc
MD
1109 error = EINVAL;
1110 else
1111 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1112 }
1113 if (!error) {
67863d04 1114 error = nfsrv_access(mp, vp, VWRITE, cred, rdonly, td, 1);
984263bc
MD
1115 }
1116 if (error) {
1117 vput(vp);
1118 vp = NULL;
42edf14f
MD
1119 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1120 NFSX_WCCDATA(info.v3), &error));
1121 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1122 aftat_ret, vap);
984263bc
MD
1123 error = 0;
1124 goto nfsmout;
1125 }
1126
1127 if (len > 0) {
884717e1 1128 ivp = kmalloc(cnt * sizeof(struct iovec), M_TEMP, M_WAITOK);
984263bc
MD
1129 uiop->uio_iov = iv = ivp;
1130 uiop->uio_iovcnt = cnt;
42edf14f 1131 mp1 = info.mrep;
67863d04
MD
1132 while (mp1) {
1133 if (mp1->m_len > 0) {
1134 ivp->iov_base = mtod(mp1, caddr_t);
1135 ivp->iov_len = mp1->m_len;
984263bc
MD
1136 ivp++;
1137 }
67863d04 1138 mp1 = mp1->m_next;
984263bc
MD
1139 }
1140
1141 /*
1142 * XXX
1143 * The IO_METASYNC flag indicates that all metadata (and not just
1144 * enough to ensure data integrity) mus be written to stable storage
1145 * synchronously.
1146 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1147 */
1148 if (stable == NFSV3WRITE_UNSTABLE)
1149 ioflags = IO_NODELOCKED;
1150 else if (stable == NFSV3WRITE_DATASYNC)
1151 ioflags = (IO_SYNC | IO_NODELOCKED);
1152 else
1153 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1154 uiop->uio_resid = len;
1155 uiop->uio_rw = UIO_WRITE;
1156 uiop->uio_segflg = UIO_SYSSPACE;
dadab5e9 1157 uiop->uio_td = NULL;
984263bc 1158 uiop->uio_offset = off;
a084b5c3
VS
1159 nh = nfsrv_sequential_heuristic(uiop, vp, 1);
1160 ioflags |= nh->nh_seqcount << IO_SEQSHIFT;
984263bc 1161 error = VOP_WRITE(vp, uiop, ioflags, cred);
a084b5c3
VS
1162 if (error == 0)
1163 nh->nh_nextoff = uiop->uio_offset;
984263bc 1164 nfsstats.srvvop_writes++;
884717e1 1165 kfree((caddr_t)iv, M_TEMP);
984263bc 1166 }
87de5057 1167 aftat_ret = VOP_GETATTR(vp, vap);
984263bc
MD
1168 vput(vp);
1169 vp = NULL;
1170 if (!error)
1171 error = aftat_ret;
42edf14f
MD
1172 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1173 NFSX_PREOPATTR(info.v3) +
1174 NFSX_POSTOPORFATTR(info.v3) +
1175 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(info.v3),
1176 &error));
1177 if (info.v3) {
1178 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1179 aftat_ret, vap);
984263bc
MD
1180 if (error) {
1181 error = 0;
1182 goto nfsmout;
1183 }
42edf14f 1184 tl = nfsm_build(&info, 4 * NFSX_UNSIGNED);
984263bc
MD
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);
3a6f9faf 1201 *tl = txdr_unsigned(nfsver.tv_nsec / 1000);
984263bc 1202 } else {
42edf14f
MD
1203 fp = nfsm_build(&info, NFSX_V2FATTR);
1204 nfsm_srvfattr(nfsd, vap, fp);
984263bc
MD
1205 }
1206nfsmout:
42edf14f 1207 *mrq = info.mreq;
984263bc
MD
1208 if (vp)
1209 vput(vp);
1210 return(error);
1211}
1212
1213/*
1214 * NFS write service with write gathering support. Called when
1215 * nfsrvw_procrastinate > 0.
1216 * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1217 * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1218 * Jan. 1994.
1219 */
1220int
e851b29e
CP
1221nfsrv_writegather(struct nfsrv_descript **ndp, struct nfssvc_sock *slp,
1222 struct thread *td, struct mbuf **mrq)
984263bc 1223{
dadab5e9 1224 struct iovec *ivp;
dadab5e9
MD
1225 struct nfsrv_descript *wp, *nfsd, *owp, *swp;
1226 struct nfs_fattr *fp;
1227 int i;
984263bc
MD
1228 struct iovec *iov;
1229 struct nfsrvw_delayhash *wpp;
1230 struct ucred *cred;
1231 struct vattr va, forat;
dadab5e9 1232 u_int32_t *tl;
e07fef60 1233 int error = 0, rdonly, len, forat_ret = 1;
42edf14f
MD
1234 int ioflags, aftat_ret = 1, adjust, zeroing;
1235 struct mbuf *mp1;
984263bc 1236 struct vnode *vp = NULL;
67863d04 1237 struct mount *mp = NULL;
984263bc 1238 struct uio io, *uiop = &io;
e07fef60 1239 u_quad_t cur_usec;
42edf14f 1240 struct nfsm_info info;
984263bc 1241
8bfa5617
MD
1242 info.mreq = NULL;
1243
984263bc
MD
1244 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
1245#ifndef nolint
1246 i = 0;
1247 len = 0;
1248#endif
984263bc
MD
1249 if (*ndp) {
1250 nfsd = *ndp;
1251 *ndp = NULL;
42edf14f
MD
1252 info.mrep = nfsd->nd_mrep;
1253 info.mreq = NULL;
1254 info.md = nfsd->nd_md;
1255 info.dpos = nfsd->nd_dpos;
1256 info.v3 = (nfsd->nd_flag & ND_NFSV3);
984263bc 1257 cred = &nfsd->nd_cr;
984263bc
MD
1258 LIST_INIT(&nfsd->nd_coalesce);
1259 nfsd->nd_mreq = NULL;
1260 nfsd->nd_stable = NFSV3WRITE_FILESYNC;
1261 cur_usec = nfs_curusec();
1262 nfsd->nd_time = cur_usec +
42edf14f 1263 (info.v3 ? nfsrvw_procrastinate_v3 : nfsrvw_procrastinate);
984263bc
MD
1264
1265 /*
1266 * Now, get the write header..
1267 */
42edf14f
MD
1268 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, &nfsd->nd_fh, &error));
1269 if (info.v3) {
1270 NULLOUT(tl = nfsm_dissect(&info, 5 * NFSX_UNSIGNED));
984263bc
MD
1271 nfsd->nd_off = fxdr_hyper(tl);
1272 tl += 3;
1273 nfsd->nd_stable = fxdr_unsigned(int, *tl++);
1274 } else {
42edf14f 1275 NULLOUT(tl = nfsm_dissect(&info, 4 * NFSX_UNSIGNED));
984263bc
MD
1276 nfsd->nd_off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
1277 tl += 2;
1278 if (nfs_async)
1279 nfsd->nd_stable = NFSV3WRITE_UNSTABLE;
1280 }
1281 len = fxdr_unsigned(int32_t, *tl);
1282 nfsd->nd_len = len;
1283 nfsd->nd_eoff = nfsd->nd_off + len;
1284
1285 /*
1286 * Trim the header out of the mbuf list and trim off any trailing
1287 * junk so that the mbuf list has only the write data.
1288 */
1289 zeroing = 1;
1290 i = 0;
42edf14f 1291 mp1 = info.mrep;
67863d04 1292 while (mp1) {
42edf14f 1293 if (mp1 == info.md) {
984263bc 1294 zeroing = 0;
42edf14f 1295 adjust = info.dpos - mtod(mp1, caddr_t);
67863d04
MD
1296 mp1->m_len -= adjust;
1297 if (mp1->m_len > 0 && adjust > 0)
42edf14f 1298 mp1->m_data += adjust;
984263bc
MD
1299 }
1300 if (zeroing)
67863d04 1301 mp1->m_len = 0;
984263bc 1302 else {
67863d04 1303 i += mp1->m_len;
984263bc 1304 if (i > len) {
67863d04 1305 mp1->m_len -= (i - len);
984263bc
MD
1306 zeroing = 1;
1307 }
1308 }
67863d04 1309 mp1 = mp1->m_next;
984263bc
MD
1310 }
1311 if (len > NFS_MAXDATA || len < 0 || i < len) {
1312nfsmout:
42edf14f
MD
1313 m_freem(info.mrep);
1314 info.mrep = NULL;
984263bc 1315 error = EIO;
42edf14f
MD
1316 nfsm_writereply(&info, nfsd, slp, error, 2 * NFSX_UNSIGNED);
1317 if (info.v3) {
1318 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1319 aftat_ret, &va);
1320 }
1321 nfsd->nd_mreq = info.mreq;
984263bc
MD
1322 nfsd->nd_mrep = NULL;
1323 nfsd->nd_time = 0;
1324 }
1325
1326 /*
1327 * Add this entry to the hash and time queues.
1328 */
984263bc
MD
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 }
984263bc
MD
1371 }
1372
1373 /*
1374 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1375 * and generate the associated reply mbuf list(s).
1376 */
1377loop1:
1378 cur_usec = nfs_curusec();
984263bc
MD
1379 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
1380 owp = nfsd->nd_tq.le_next;
1381 if (nfsd->nd_time > cur_usec)
1382 break;
1383 if (nfsd->nd_mreq)
1384 continue;
1385 NFS_DPF(WG, ("P%03x", nfsd->nd_retxid & 0xfff));
1386 LIST_REMOVE(nfsd, nd_tq);
1387 LIST_REMOVE(nfsd, nd_hash);
42edf14f 1388 info.mrep = nfsd->nd_mrep;
5e6f1ca5 1389 info.mreq = NULL;
42edf14f 1390 info.v3 = (nfsd->nd_flag & ND_NFSV3);
984263bc
MD
1391 nfsd->nd_mrep = NULL;
1392 cred = &nfsd->nd_cr;
984263bc 1393 forat_ret = aftat_ret = 1;
67863d04 1394 error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &mp, &vp, cred, slp,
5e6f1ca5
MD
1395 nfsd->nd_nam, &rdonly,
1396 (nfsd->nd_flag & ND_KERBAUTH), TRUE);
984263bc 1397 if (!error) {
42edf14f 1398 if (info.v3)
87de5057 1399 forat_ret = VOP_GETATTR(vp, &forat);
984263bc 1400 if (vp->v_type != VREG) {
42edf14f 1401 if (info.v3)
984263bc
MD
1402 error = EINVAL;
1403 else
1404 error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1405 }
1406 } else {
1407 vp = NULL;
1408 }
1409 if (!error) {
67863d04 1410 error = nfsrv_access(mp, vp, VWRITE, cred, rdonly, td, 1);
984263bc
MD
1411 }
1412
1413 if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1414 ioflags = IO_NODELOCKED;
1415 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1416 ioflags = (IO_SYNC | IO_NODELOCKED);
1417 else
1418 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1419 uiop->uio_rw = UIO_WRITE;
1420 uiop->uio_segflg = UIO_SYSSPACE;
dadab5e9 1421 uiop->uio_td = NULL;
984263bc
MD
1422 uiop->uio_offset = nfsd->nd_off;
1423 uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
1424 if (uiop->uio_resid > 0) {
42edf14f 1425 mp1 = info.mrep;
984263bc 1426 i = 0;
67863d04
MD
1427 while (mp1) {
1428 if (mp1->m_len > 0)
984263bc 1429 i++;
67863d04 1430 mp1 = mp1->m_next;
984263bc
MD
1431 }
1432 uiop->uio_iovcnt = i;
884717e1 1433 iov = kmalloc(i * sizeof(struct iovec), M_TEMP, M_WAITOK);
984263bc 1434 uiop->uio_iov = ivp = iov;
42edf14f 1435 mp1 = info.mrep;
67863d04
MD
1436 while (mp1) {
1437 if (mp1->m_len > 0) {
1438 ivp->iov_base = mtod(mp1, caddr_t);
1439 ivp->iov_len = mp1->m_len;
984263bc
MD
1440 ivp++;
1441 }
67863d04 1442 mp1 = mp1->m_next;
984263bc
MD
1443 }
1444 if (!error) {
1445 error = VOP_WRITE(vp, uiop, ioflags, cred);
1446 nfsstats.srvvop_writes++;
1447 }
884717e1 1448 kfree((caddr_t)iov, M_TEMP);
984263bc 1449 }
42edf14f
MD
1450 m_freem(info.mrep);
1451 info.mrep = NULL;
984263bc 1452 if (vp) {
87de5057 1453 aftat_ret = VOP_GETATTR(vp, &va);
984263bc
MD
1454 vput(vp);
1455 vp = NULL;
1456 }
1457
1458 /*
1459 * Loop around generating replies for all write rpcs that have
1460 * now been completed.
1461 */
1462 swp = nfsd;
1463 do {
1464 NFS_DPF(WG, ("R%03x", nfsd->nd_retxid & 0xfff));
1465 if (error) {
42edf14f
MD
1466 nfsm_writereply(&info, nfsd, slp, error,
1467 NFSX_WCCDATA(info.v3));
1468 if (info.v3) {
1469 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1470 aftat_ret, &va);
984263bc
MD
1471 }
1472 } else {
42edf14f
MD
1473 nfsm_writereply(&info, nfsd, slp, error,
1474 NFSX_PREOPATTR(info.v3) +
1475 NFSX_POSTOPORFATTR(info.v3) +
1476 2 * NFSX_UNSIGNED +
1477 NFSX_WRITEVERF(info.v3));
1478 if (info.v3) {
1479 nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1480 aftat_ret, &va);
1481 tl = nfsm_build(&info, 4 * NFSX_UNSIGNED);
984263bc
MD
1482 *tl++ = txdr_unsigned(nfsd->nd_len);
1483 *tl++ = txdr_unsigned(swp->nd_stable);
1484 /*
1485 * Actually, there is no need to txdr these fields,
1486 * but it may make the values more human readable,
1487 * for debugging purposes.
1488 */
1489 if (nfsver.tv_sec == 0)
1490 nfsver = boottime;
1491 *tl++ = txdr_unsigned(nfsver.tv_sec);
3a6f9faf 1492 *tl = txdr_unsigned(nfsver.tv_nsec / 1000);
984263bc 1493 } else {
42edf14f
MD
1494 fp = nfsm_build(&info, NFSX_V2FATTR);
1495 nfsm_srvfattr(nfsd, &va, fp);
984263bc
MD
1496 }
1497 }
42edf14f 1498 nfsd->nd_mreq = info.mreq;
984263bc
MD
1499 if (nfsd->nd_mrep)
1500 panic("nfsrv_write: nd_mrep not free");
1501
1502 /*
1503 * Done. Put it at the head of the timer queue so that
1504 * the final phase can return the reply.
1505 */
984263bc
MD
1506 if (nfsd != swp) {
1507 nfsd->nd_time = 0;
1508 LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1509 }
1510 nfsd = swp->nd_coalesce.lh_first;
1511 if (nfsd) {
1512 LIST_REMOVE(nfsd, nd_tq);
1513 }
984263bc 1514 } while (nfsd);
984263bc
MD
1515 swp->nd_time = 0;
1516 LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
984263bc
MD
1517 goto loop1;
1518 }
984263bc
MD
1519
1520 /*
1521 * Search for a reply to return.
1522 */
5e6f1ca5 1523 for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next) {
984263bc
MD
1524 if (nfsd->nd_mreq) {
1525 NFS_DPF(WG, ("X%03x", nfsd->nd_retxid & 0xfff));
1526 LIST_REMOVE(nfsd, nd_tq);
984263bc
MD
1527 break;
1528 }
5e6f1ca5
MD
1529 }
1530 if (nfsd) {
1531 *ndp = nfsd;
1532 *mrq = nfsd->nd_mreq;
1533 } else {
1534 *ndp = NULL;
1535 *mrq = NULL;
1536 }
984263bc
MD
1537 return (0);
1538}
1539
1540/*
1541 * Coalesce the write request nfsd into owp. To do this we must:
1542 * - remove nfsd from the queues
1543 * - merge nfsd->nd_mrep into owp->nd_mrep
1544 * - update the nd_eoff and nd_stable for owp
1545 * - put nfsd on owp's nd_coalesce list
1546 * NB: Must be called at splsoftclock().
1547 */
1548static void
dadab5e9 1549nfsrvw_coalesce(struct nfsrv_descript *owp, struct nfsrv_descript *nfsd)
984263bc 1550{
dadab5e9 1551 int overlap;
67863d04 1552 struct mbuf *mp1;
984263bc
MD
1553 struct nfsrv_descript *p;
1554
1555 NFS_DPF(WG, ("C%03x-%03x",
1556 nfsd->nd_retxid & 0xfff, owp->nd_retxid & 0xfff));
1557 LIST_REMOVE(nfsd, nd_hash);
1558 LIST_REMOVE(nfsd, nd_tq);
1559 if (owp->nd_eoff < nfsd->nd_eoff) {
1560 overlap = owp->nd_eoff - nfsd->nd_off;
1561 if (overlap < 0)
1562 panic("nfsrv_coalesce: bad off");
1563 if (overlap > 0)
1564 m_adj(nfsd->nd_mrep, overlap);
67863d04
MD
1565 mp1 = owp->nd_mrep;
1566 while (mp1->m_next)
1567 mp1 = mp1->m_next;
1568 mp1->m_next = nfsd->nd_mrep;
984263bc
MD
1569 owp->nd_eoff = nfsd->nd_eoff;
1570 } else
1571 m_freem(nfsd->nd_mrep);
1572 nfsd->nd_mrep = NULL;
1573 if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1574 owp->nd_stable = NFSV3WRITE_FILESYNC;
1575 else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1576 owp->nd_stable == NFSV3WRITE_UNSTABLE)
1577 owp->nd_stable = NFSV3WRITE_DATASYNC;
1578 LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1579
1580 /*
1581 * If nfsd had anything else coalesced into it, transfer them
1582 * to owp, otherwise their replies will never get sent.
1583 */
1584 for (p = nfsd->nd_coalesce.lh_first; p;
1585 p = nfsd->nd_coalesce.lh_first) {
1586 LIST_REMOVE(p, nd_tq);
1587 LIST_INSERT_HEAD(&owp->nd_coalesce, p, nd_tq);
1588 }
1589}
1590
1591/*
1592 * nfs create service
1593 * now does a truncate to 0 length via. setattr if it already exists
1594 */
1595int
e851b29e
CP
1596nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1597 struct thread *td, struct mbuf **mrq)
984263bc 1598{
984263bc 1599 struct sockaddr *nam = nfsd->nd_nam;
984263bc 1600 struct ucred *cred = &nfsd->nd_cr;
dadab5e9 1601 struct nfs_fattr *fp;
984263bc 1602 struct vattr va, dirfor, diraft;
dadab5e9
MD
1603 struct vattr *vap = &va;
1604 struct nfsv2_sattr *sp;
1605 u_int32_t *tl;
fad57d0e 1606 struct nlookupdata nd;
0e9b9130
MD
1607 int error = 0, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1608 udev_t rdev = NOUDEV;
984263bc 1609 caddr_t cp;
42edf14f 1610 int how, exclusive_flag = 0;
fad57d0e
MD
1611 struct vnode *dirp;
1612 struct vnode *dvp;
1613 struct vnode *vp;
67863d04 1614 struct mount *mp;
984263bc
MD
1615 nfsfh_t nfh;
1616 fhandle_t *fhp;
e07fef60 1617 u_quad_t tempsize;
984263bc 1618 u_char cverf[NFSX_V3CREATEVERF];
42edf14f 1619 struct nfsm_info info;
984263bc
MD
1620
1621 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fad57d0e
MD
1622 nlookup_zero(&nd);
1623 dirp = NULL;
1624 dvp = NULL;
1625 vp = NULL;
984263bc 1626
42edf14f
MD
1627 info.mrep = nfsd->nd_mrep;
1628 info.mreq = NULL;
1629 info.md = nfsd->nd_md;
1630 info.dpos = nfsd->nd_dpos;
1631 info.v3 = (nfsd->nd_flag & ND_NFSV3);
1632
984263bc 1633 fhp = &nfh.fh_generic;
42edf14f
MD
1634 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
1635 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
984263bc 1636
984263bc
MD
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 */
3a907475 1646 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
42edf14f 1647 fhp, len, slp, nam, &info.md, &info.dpos, &dirp,
fad57d0e 1648 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
67863d04
MD
1649 mp = vfs_getvfs(&fhp->fh_fsid);
1650
984263bc 1651 if (dirp) {
42edf14f 1652 if (info.v3) {
87de5057 1653 dirfor_ret = VOP_GETATTR(dirp, &dirfor);
984263bc
MD
1654 } else {
1655 vrele(dirp);
1656 dirp = NULL;
1657 }
1658 }
1659 if (error) {
42edf14f
MD
1660 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1661 NFSX_WCCDATA(info.v3), &error));
1662 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
1663 diraft_ret, &diraft);
984263bc
MD
1664 error = 0;
1665 goto nfsmout;
1666 }
1667
1668 /*
1669 * No error. Continue. State:
1670 *
984263bc 1671 * dirp may be valid
fad57d0e
MD
1672 * vp may be valid or NULL if the target does not
1673 * exist.
1674 * dvp is valid
984263bc
MD
1675 *
1676 * The error state is set through the code and we may also do some
1677 * opportunistic releasing of vnodes to avoid holding locks through
1678 * NFS I/O. The cleanup at the end is a catch-all
1679 */
1680
1681 VATTR_NULL(vap);
42edf14f
MD
1682 if (info.v3) {
1683 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
984263bc
MD
1684 how = fxdr_unsigned(int, *tl);
1685 switch (how) {
1686 case NFSV3CREATE_GUARDED:
fad57d0e 1687 if (vp) {
984263bc
MD
1688 error = EEXIST;
1689 break;
1690 }
1691 /* fall through */
1692 case NFSV3CREATE_UNCHECKED:
42edf14f 1693 ERROROUT(nfsm_srvsattr(&info, vap));
984263bc
MD
1694 break;
1695 case NFSV3CREATE_EXCLUSIVE:
42edf14f 1696 NULLOUT(cp = nfsm_dissect(&info, NFSX_V3CREATEVERF));
984263bc
MD
1697 bcopy(cp, cverf, NFSX_V3CREATEVERF);
1698 exclusive_flag = 1;
1699 break;
1700 };
1701 vap->va_type = VREG;
1702 } else {
42edf14f 1703 NULLOUT(sp = nfsm_dissect(&info, NFSX_V2SATTR));
984263bc
MD
1704 vap->va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1705 if (vap->va_type == VNON)
1706 vap->va_type = VREG;
1707 vap->va_mode = nfstov_mode(sp->sa_mode);
1708 switch (vap->va_type) {
1709 case VREG:
1710 tsize = fxdr_unsigned(int32_t, sp->sa_size);
1711 if (tsize != -1)
1712 vap->va_size = (u_quad_t)tsize;
1713 break;
1714 case VCHR:
1715 case VBLK:
1716 case VFIFO:
1717 rdev = fxdr_unsigned(long, sp->sa_size);
1718 break;
1719 default:
1720 break;
1721 };
1722 }
1723
1724 /*
1725 * Iff doesn't exist, create it
1726 * otherwise just truncate to 0 length
1727 * should I set the mode too ?
1728 *
1729 * The only possible error we can have at this point is EEXIST.
1730 * nd.ni_vp will also be non-NULL in that case.
1731 */
fad57d0e 1732 if (vp == NULL) {
984263bc
MD
1733 if (vap->va_mode == (mode_t)VNOVAL)
1734 vap->va_mode = 0;
1735 if (vap->va_type == VREG || vap->va_type == VSOCK) {
08daea96
MD
1736 vn_unlock(dvp);
1737 error = VOP_NCREATE(&nd.nl_nch, dvp, &vp,
1738 nd.nl_cred, vap);
1739 vrele(dvp);
d6593715 1740 dvp = NULL;
fad57d0e 1741 if (error == 0) {
984263bc
MD
1742 if (exclusive_flag) {
1743 exclusive_flag = 0;
1744 VATTR_NULL(vap);
1745 bcopy(cverf, (caddr_t)&vap->va_atime,
1746 NFSX_V3CREATEVERF);
87de5057 1747 error = VOP_SETATTR(vp, vap, cred);
984263bc
MD
1748 }
1749 }
1750 } else if (
1751 vap->va_type == VCHR ||
1752 vap->va_type == VBLK ||
1753 vap->va_type == VFIFO
1754 ) {
1755 /*
1756 * Handle SysV FIFO node special cases. All other
1757 * devices require super user to access.
1758 */
1759 if (vap->va_type == VCHR && rdev == 0xffffffff)
1760 vap->va_type = VFIFO;
1761 if (vap->va_type != VFIFO &&
895c1f85 1762 (error = priv_check_cred(cred, PRIV_ROOT, 0))) {
984263bc
MD
1763 goto nfsmreply0;
1764 }
0e9b9130
MD
1765 vap->va_rmajor = umajor(rdev);
1766 vap->va_rminor = uminor(rdev);
984263bc 1767
08daea96
MD
1768 vn_unlock(dvp);
1769 error = VOP_NMKNOD(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap);
1770 vrele(dvp);
d6593715 1771 dvp = NULL;
fad57d0e 1772 if (error)
984263bc 1773 goto nfsmreply0;
fad57d0e
MD
1774#if 0
1775 /*
1776 * XXX what is this junk supposed to do ?
1777 */
1778
1779 vput(vp);
1780 vp = NULL;
984263bc
MD
1781
1782 /*
1783 * release dvp prior to lookup
1784 */
fad57d0e
MD
1785 vput(dvp);
1786 dvp = NULL;
984263bc
MD
1787
1788 /*
1789 * Setup for lookup.
1790 *
1791 * Even though LOCKPARENT was cleared, ni_dvp may
1792 * be garbage.
1793 */
2b69e610
MD
1794 nd.ni_cnd.cn_nameiop = NAMEI_LOOKUP;
1795 nd.ni_cnd.cn_flags &= ~(CNP_LOCKPARENT);
dadab5e9 1796 nd.ni_cnd.cn_td = td;
984263bc
MD
1797 nd.ni_cnd.cn_cred = cred;
1798
1799 error = lookup(&nd);
1800 nd.ni_dvp = NULL;
1801
1802 if (error != 0) {
42edf14f
MD
1803 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1804 0, &error));
984263bc
MD
1805 /* fall through on certain errors */
1806 }
1807 nfsrv_object_create(nd.ni_vp);
2b69e610 1808 if (nd.ni_cnd.cn_flags & CNP_ISSYMLINK) {
984263bc
MD
1809 error = EINVAL;
1810 goto nfsmreply0;
1811 }
fad57d0e 1812#endif
984263bc
MD
1813 } else {
1814 error = ENXIO;
1815 }
1816 } else {
1817 if (vap->va_size != -1) {
67863d04 1818 error = nfsrv_access(mp, vp, VWRITE, cred,
fad57d0e 1819 (nd.nl_flags & NLC_NFS_RDONLY), td, 0);
984263bc 1820 if (!error) {
984263bc
MD
1821 tempsize = vap->va_size;
1822 VATTR_NULL(vap);
1823 vap->va_size = tempsize;
87de5057 1824 error = VOP_SETATTR(vp, vap, cred);
984263bc
MD
1825 }
1826 }
1827 }
1828
1829 if (!error) {
67863d04 1830 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid));
fad57d0e 1831 error = VFS_VPTOFH(vp, &fhp->fh_fid);
984263bc 1832 if (!error)
87de5057 1833 error = VOP_GETATTR(vp, vap);
984263bc 1834 }
42edf14f 1835 if (info.v3) {
984263bc
MD
1836 if (exclusive_flag && !error &&
1837 bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF))
1838 error = EEXIST;
87de5057 1839 diraft_ret = VOP_GETATTR(dirp, &diraft);
984263bc
MD
1840 vrele(dirp);
1841 dirp = NULL;
1842 }
42edf14f
MD
1843 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1844 NFSX_SRVFH(info.v3) + NFSX_FATTR(info.v3) +
1845 NFSX_WCCDATA(info.v3),
1846 &error));
1847 if (info.v3) {
984263bc 1848 if (!error) {
42edf14f
MD
1849 nfsm_srvpostop_fh(&info, fhp);
1850 nfsm_srvpostop_attr(&info, nfsd, 0, vap);
984263bc 1851 }
42edf14f
MD
1852 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
1853 diraft_ret, &diraft);
984263bc
MD
1854 error = 0;
1855 } else {
42edf14f
MD
1856 nfsm_srvfhtom(&info, fhp);
1857 fp = nfsm_build(&info, NFSX_V2FATTR);
1858 nfsm_srvfattr(nfsd, vap, fp);
984263bc
MD
1859 }
1860 goto nfsmout;
1861
1862nfsmreply0:
42edf14f 1863 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error));
984263bc
MD
1864 error = 0;
1865 /* fall through */
1866
1867nfsmout:
8bfa5617 1868 *mrq = info.mreq;
984263bc
MD
1869 if (dirp)
1870 vrele(dirp);
fad57d0e
MD
1871 nlookup_done(&nd);
1872 if (dvp) {
1873 if (dvp == vp)
1874 vrele(dvp);
984263bc 1875 else
fad57d0e 1876 vput(dvp);
984263bc 1877 }
fad57d0e
MD
1878 if (vp)
1879 vput(vp);
984263bc
MD
1880 return (error);
1881}
1882
1883/*
1884 * nfs v3 mknod service
1885 */
1886int
e851b29e
CP
1887nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1888 struct thread *td, struct mbuf **mrq)
984263bc 1889{
984263bc 1890 struct sockaddr *nam = nfsd->nd_nam;
984263bc
MD
1891 struct ucred *cred = &nfsd->nd_cr;
1892 struct vattr va, dirfor, diraft;
dadab5e9
MD
1893 struct vattr *vap = &va;
1894 u_int32_t *tl;
fad57d0e 1895 struct nlookupdata nd;
e07fef60 1896 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
984263bc 1897 enum vtype vtyp;
fad57d0e
MD
1898 struct vnode *dirp;
1899 struct vnode *dvp;
1900 struct vnode *vp;
984263bc
MD
1901 nfsfh_t nfh;
1902 fhandle_t *fhp;
42edf14f 1903 struct nfsm_info info;
984263bc
MD
1904
1905 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fad57d0e
MD
1906 nlookup_zero(&nd);
1907 dirp = NULL;
1908 dvp = NULL;
1909 vp = NULL;
984263bc 1910
42edf14f
MD
1911 info.mrep = nfsd->nd_mrep;
1912 info.mreq = NULL;
1913 info.md = nfsd->nd_md;
1914 info.dpos = nfsd->nd_dpos;
1915
984263bc 1916 fhp = &nfh.fh_generic;
42edf14f
MD
1917 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
1918 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
984263bc 1919
984263bc
MD
1920 /*
1921 * Handle nfs_namei() call. If an error occurs, the nd structure
1922 * is not valid. However, nfsm_*() routines may still jump to
1923 * nfsmout.
1924 */
1925
3a907475 1926 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
42edf14f 1927 fhp, len, slp, nam, &info.md, &info.dpos, &dirp,
fad57d0e 1928 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
984263bc 1929 if (dirp)
87de5057 1930 dirfor_ret = VOP_GETATTR(dirp, &dirfor);
984263bc 1931 if (error) {
42edf14f
MD
1932 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1933 NFSX_WCCDATA(1), &error));
1934 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
1935 diraft_ret, &diraft);
984263bc
MD
1936 error = 0;
1937 goto nfsmout;
1938 }
42edf14f 1939 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
984263bc
MD
1940 vtyp = nfsv3tov_type(*tl);
1941 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1942 error = NFSERR_BADTYPE;
1943 goto out;
1944 }
1945 VATTR_NULL(vap);
42edf14f 1946 ERROROUT(nfsm_srvsattr(&info, vap));
984263bc 1947 if (vtyp == VCHR || vtyp == VBLK) {
42edf14f 1948 NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED));
0e9b9130
MD
1949 vap->va_rmajor = fxdr_unsigned(u_int32_t, *tl++);
1950 vap->va_rminor = fxdr_unsigned(u_int32_t, *tl);
984263bc
MD
1951 }
1952
1953 /*
1954 * Iff doesn't exist, create it.
1955 */
fad57d0e 1956 if (vp) {
984263bc
MD
1957 error = EEXIST;
1958 goto out;
1959 }
1960 vap->va_type = vtyp;
1961 if (vap->va_mode == (mode_t)VNOVAL)
1962 vap->va_mode = 0;
1963 if (vtyp == VSOCK) {
08daea96
MD
1964 vn_unlock(dvp);
1965 error = VOP_NCREATE(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap);
1966 vrele(dvp);
1967 dvp = NULL;
984263bc 1968 } else {
895c1f85 1969 if (vtyp != VFIFO && (error = priv_check_cred(cred, PRIV_ROOT, 0)))
984263bc 1970 goto out;
984263bc 1971
08daea96
MD
1972 vn_unlock(dvp);
1973 error = VOP_NMKNOD(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap);
1974 vrele(dvp);
fad57d0e 1975 dvp = NULL;
984263bc
MD
1976 if (error)
1977 goto out;
984263bc
MD
1978 }
1979
1980 /*
1981 * send response, cleanup, return.
1982 */
1983out:
fad57d0e
MD
1984 nlookup_done(&nd);
1985 if (dvp) {
1986 if (dvp == vp)
1987 vrele(dvp);
984263bc 1988 else
fad57d0e
MD
1989 vput(dvp);
1990 dvp = NULL;
984263bc 1991 }
984263bc 1992 if (!error) {
67863d04 1993 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid));
984263bc
MD
1994 error = VFS_VPTOFH(vp, &fhp->fh_fid);
1995 if (!error)
87de5057 1996 error = VOP_GETATTR(vp, vap);
984263bc
MD
1997 }
1998 if (vp) {
1999 vput(vp);
2000 vp = NULL;
984263bc 2001 }
87de5057 2002 diraft_ret = VOP_GETATTR(dirp, &diraft);
984263bc
MD
2003 if (dirp) {
2004 vrele(dirp);
2005 dirp = NULL;
2006 }
42edf14f
MD
2007 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2008 NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) +
2009 NFSX_WCCDATA(1), &error));
984263bc 2010 if (!error) {
42edf14f
MD
2011 nfsm_srvpostop_fh(&info, fhp);
2012 nfsm_srvpostop_attr(&info, nfsd, 0, vap);
984263bc 2013 }
42edf14f
MD
2014 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2015 diraft_ret, &diraft);
8bfa5617 2016 *mrq = info.mreq;
984263bc
MD
2017 return (0);
2018nfsmout:
42edf14f 2019 *mrq = info.mreq;
984263bc
MD
2020 if (dirp)
2021 vrele(dirp);
fad57d0e
MD
2022 nlookup_done(&nd);
2023 if (dvp) {
2024 if (dvp == vp)
2025 vrele(dvp);
984263bc 2026 else
fad57d0e 2027 vput(dvp);
984263bc 2028 }
fad57d0e
MD
2029 if (vp)
2030 vput(vp);
984263bc
MD
2031 return (error);
2032}
2033
2034/*
2035 * nfs remove service
2036 */
2037int
e851b29e
CP
2038nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2039 struct thread *td, struct mbuf **mrq)
984263bc 2040{
984263bc 2041 struct sockaddr *nam = nfsd->nd_nam;
984263bc 2042 struct ucred *cred = &nfsd->nd_cr;
fad57d0e 2043 struct nlookupdata nd;
e07fef60 2044 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
984263bc 2045 struct vnode *dirp;
fad57d0e
MD
2046 struct vnode *dvp;
2047 struct vnode *vp;
984263bc
MD
2048 struct vattr dirfor, diraft;
2049 nfsfh_t nfh;
2050 fhandle_t *fhp;
42edf14f 2051 struct nfsm_info info;
984263bc
MD
2052
2053 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fad57d0e
MD
2054 nlookup_zero(&nd);
2055 dirp = NULL;
2056 dvp = NULL;
2057 vp = NULL;
984263bc 2058
42edf14f
MD
2059 info.mrep = nfsd->nd_mrep;
2060 info.mreq = NULL;
2061 info.md = nfsd->nd_md;
2062 info.dpos = nfsd->nd_dpos;
2063 info.v3 = (nfsd->nd_flag & ND_NFSV3);
2064
984263bc 2065 fhp = &nfh.fh_generic;
42edf14f
MD
2066 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
2067 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
984263bc 2068
3a907475 2069 error = nfs_namei(&nd, cred, NLC_DELETE, &dvp, &vp,
42edf14f 2070 fhp, len, slp, nam, &info.md, &info.dpos, &dirp,
fad57d0e 2071 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
984263bc 2072 if (dirp) {
42edf14f 2073 if (info.v3)
87de5057 2074 dirfor_ret = VOP_GETATTR(dirp, &dirfor);
984263bc
MD
2075 }
2076 if (error == 0) {
fad57d0e 2077 if (vp->v_type == VDIR) {
984263bc
MD
2078 error = EPERM; /* POSIX */
2079 goto out;
2080 }
2081 /*
2082 * The root of a mounted filesystem cannot be deleted.
2083 */
fad57d0e 2084 if (vp->v_flag & VROOT) {
984263bc
MD
2085 error = EBUSY;
2086 goto out;
2087 }
2088out:
2089 if (!error) {
08daea96
MD
2090 if (dvp != vp)
2091 vn_unlock(dvp);
d9ba7ca9
MD
2092 if (vp) {
2093 vput(vp);
2094 vp = NULL;
2095 }
08daea96
MD
2096 error = VOP_NREMOVE(&nd.nl_nch, dvp, nd.nl_cred);
2097 vrele(dvp);
2098 dvp = NULL;
984263bc
MD
2099 }
2100 }
42edf14f 2101 if (dirp && info.v3)
87de5057 2102 diraft_ret = VOP_GETATTR(dirp, &diraft);
42edf14f
MD
2103 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_WCCDATA(info.v3), &error));
2104 if (info.v3) {
2105 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2106 diraft_ret, &diraft);
984263bc
MD
2107 error = 0;
2108 }
2109nfsmout:
42edf14f 2110 *mrq = info.mreq;
fad57d0e
MD
2111 nlookup_done(&nd);
2112 if (dirp)
2113 vrele(dirp);
2114 if (dvp) {
2115 if (dvp == vp)
2116 vrele(dvp);
984263bc 2117 else
fad57d0e 2118 vput(dvp);
984263bc 2119 }
fad57d0e
MD
2120 if (vp)
2121 vput(vp);
984263bc
MD
2122 return(error);
2123}
2124
2125/*
2126 * nfs rename service
2127 */
2128int
e851b29e
CP
2129nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2130 struct thread *td, struct mbuf **mrq)
984263bc 2131{
984263bc 2132 struct sockaddr *nam = nfsd->nd_nam;
984263bc 2133 struct ucred *cred = &nfsd->nd_cr;
e07fef60 2134 int error = 0, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
984263bc 2135 int tdirfor_ret = 1, tdiraft_ret = 1;
fad57d0e 2136 struct nlookupdata fromnd, tond;
08daea96
MD
2137 struct vnode *fvp, *fdirp, *fdvp;
2138 struct vnode *tvp, *tdirp, *tdvp;
fad57d0e 2139 struct namecache *ncp;
984263bc
MD
2140 struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
2141 nfsfh_t fnfh, tnfh;
2142 fhandle_t *ffhp, *tfhp;
984263bc 2143 uid_t saved_uid;
42edf14f
MD
2144 struct nfsm_info info;
2145
2146 info.mrep = nfsd->nd_mrep;
2147 info.mreq = NULL;
2148 info.md = nfsd->nd_md;
2149 info.dpos = nfsd->nd_dpos;
2150 info.v3 = (nfsd->nd_flag & ND_NFSV3);
984263bc
MD
2151
2152 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2153#ifndef nolint
60233e58 2154 fvp = NULL;
984263bc
MD
2155#endif
2156 ffhp = &fnfh.fh_generic;
2157 tfhp = &tnfh.fh_generic;
2158
2159 /*
2160 * Clear fields incase goto nfsmout occurs from macro.
2161 */
2162
fad57d0e
MD
2163 nlookup_zero(&fromnd);
2164 nlookup_zero(&tond);
2165 fdirp = NULL;
2166 tdirp = NULL;
984263bc 2167
42edf14f
MD
2168 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, ffhp, &error));
2169 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
2170
984263bc
MD
2171 /*
2172 * Remember our original uid so that we can reset cr_uid before
2173 * the second nfs_namei() call, in case it is remapped.
2174 */
2175 saved_uid = cred->cr_uid;
3a907475
MD
2176 error = nfs_namei(&fromnd, cred, NLC_RENAME_SRC,
2177 NULL, NULL,
42edf14f 2178 ffhp, len, slp, nam, &info.md, &info.dpos, &fdirp,
fad57d0e 2179 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
984263bc 2180 if (fdirp) {
42edf14f 2181 if (info.v3)
87de5057 2182 fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor);
984263bc
MD
2183 }
2184 if (error) {
42edf14f
MD
2185 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2186 2 * NFSX_WCCDATA(info.v3), &error));
2187 nfsm_srvwcc_data(&info, nfsd, fdirfor_ret, &fdirfor,
2188 fdiraft_ret, &fdiraft);
2189 nfsm_srvwcc_data(&info, nfsd, tdirfor_ret, &tdirfor,
2190 tdiraft_ret, &tdiraft);
984263bc
MD
2191 error = 0;
2192 goto nfsmout;
2193 }
fad57d0e
MD
2194
2195 /*
2196 * We have to unlock the from ncp before we can safely lookup
2197 * the target ncp.
2198 */
2199 KKASSERT(fromnd.nl_flags & NLC_NCPISLOCKED);
28623bf9 2200 cache_unlock(&fromnd.nl_nch);
fad57d0e 2201 fromnd.nl_flags &= ~NLC_NCPISLOCKED;
42edf14f
MD
2202 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, tfhp, &error));
2203 NEGATIVEOUT(len2 = nfsm_strsiz(&info, NFS_MAXNAMLEN));
984263bc 2204 cred->cr_uid = saved_uid;
fad57d0e 2205
3a907475 2206 error = nfs_namei(&tond, cred, NLC_RENAME_DST, NULL, NULL,
42edf14f 2207 tfhp, len2, slp, nam, &info.md, &info.dpos, &tdirp,
fad57d0e 2208 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
984263bc 2209 if (tdirp) {
42edf14f 2210 if (info.v3)
87de5057 2211 tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor);
984263bc
MD
2212 }
2213 if (error)
2214 goto out1;
2215
fad57d0e
MD
2216 /*
2217 * relock the source
2218 */
28623bf9
MD
2219 if (cache_lock_nonblock(&fromnd.nl_nch) == 0) {
2220 cache_resolve(&fromnd.nl_nch, fromnd.nl_cred);
2221 } else if (fromnd.nl_nch.ncp > tond.nl_nch.ncp) {
2222 cache_lock(&fromnd.nl_nch);
2223 cache_resolve(&fromnd.nl_nch, fromnd.nl_cred);
fad57d0e 2224 } else {
28623bf9
MD
2225 cache_unlock(&tond.nl_nch);
2226 cache_lock(&fromnd.nl_nch);
2227 cache_resolve(&fromnd.nl_nch, fromnd.nl_cred);
2228 cache_lock(&tond.nl_nch);
2229 cache_resolve(&tond.nl_nch, tond.nl_cred);
fad57d0e
MD
2230 }
2231 fromnd.nl_flags |= NLC_NCPISLOCKED;
2232
28623bf9 2233 fvp = fromnd.nl_nch.ncp->nc_vp;
08daea96
MD
2234 tvp = tond.nl_nch.ncp->nc_vp;
2235
2236 /*
2237 * Set fdvp and tdvp. We haven't done all the topology checks
2238 * so these can wind up NULL (e.g. if either fvp or tvp is a mount
2239 * point). If we get through the checks these will be guarenteed
2240 * to be non-NULL.
2241 *
2242 * Holding the children ncp's should be sufficient to prevent
2243 * fdvp and tdvp ripouts.
2244 */
2245 if (fromnd.nl_nch.ncp->nc_parent)
2246 fdvp = fromnd.nl_nch.ncp->nc_parent->nc_vp;
2247 else
2248 fdvp = NULL;
2249 if (tond.nl_nch.ncp->nc_parent)
2250 tdvp = tond.nl_nch.ncp->nc_parent->nc_vp;
2251 else
2252 tdvp = NULL;
fad57d0e 2253
984263bc
MD
2254 if (tvp != NULL) {
2255 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
42edf14f 2256 if (info.v3)
984263bc
MD
2257 error = EEXIST;
2258 else
2259 error = EISDIR;
2260 goto out;
2261 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
42edf14f 2262 if (info.v3)
984263bc
MD
2263 error = EEXIST;
2264 else
2265 error = ENOTDIR;
2266 goto out;
2267 }
28623bf9 2268 if (tvp->v_type == VDIR && (tond.nl_nch.ncp->nc_flag & NCF_ISMOUNTPT)) {
42edf14f 2269 if (info.v3)
984263bc
MD
2270 error = EXDEV;
2271 else
2272 error = ENOTEMPTY;
2273 goto out;
2274 }
2275 }
28623bf9 2276 if (fvp->v_type == VDIR && (fromnd.nl_nch.ncp->nc_flag & NCF_ISMOUNTPT)) {
42edf14f 2277 if (info.v3)
984263bc
MD
2278 error = EXDEV;
2279 else
2280 error = ENOTEMPTY;
2281 goto out;
2282 }
28623bf9 2283 if (fromnd.nl_nch.mount != tond.nl_nch.mount) {
42edf14f 2284 if (info.v3)
984263bc
MD
2285 error = EXDEV;
2286 else
2287 error = ENOTEMPTY;
2288 goto out;
2289 }
28623bf9 2290 if (fromnd.nl_nch.ncp == tond.nl_nch.ncp->nc_parent) {
42edf14f 2291 if (info.v3)
984263bc
MD
2292 error = EINVAL;
2293 else
2294 error = ENOTEMPTY;
2295 }
fad57d0e
MD
2296
2297 /*
2298 * You cannot rename a source into itself or a subdirectory of itself.
2299 * We check this by travsering the target directory upwards looking
2300 * for a match against the source.
2301 */
2302 if (error == 0) {
28623bf9
MD
2303 for (ncp = tond.nl_nch.ncp; ncp; ncp = ncp->nc_parent) {
2304 if (fromnd.nl_nch.ncp == ncp) {
fad57d0e
MD
2305 error = EINVAL;
2306 break;
2307 }
2308 }
2309 }
2310
984263bc
MD
2311 /*
2312 * If source is the same as the destination (that is the
2313 * same vnode with the same name in the same directory),
2314 * then there is nothing to do.
2315 */
28623bf9 2316 if (fromnd.nl_nch.ncp == tond.nl_nch.ncp)
984263bc
MD
2317 error = -1;
2318out:
2319 if (!error) {
2320 /*
fad57d0e 2321 * The VOP_NRENAME function releases all vnode references &
984263bc
MD
2322 * locks prior to returning so we need to clear the pointers
2323 * to bypass cleanup code later on.
2324 */
08daea96
MD
2325 error = VOP_NRENAME(&fromnd.nl_nch, &tond.nl_nch,
2326 fdvp, tdvp, tond.nl_cred);
984263bc
MD
2327 } else {
2328 if (error == -1)
2329 error = 0;
2330 }
2331 /* fall through */
2332
2333out1:
2334 if (fdirp)
87de5057 2335 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft);
984263bc 2336 if (tdirp)
87de5057 2337 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft);
42edf14f
MD
2338 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2339 2 * NFSX_WCCDATA(info.v3), &error));
2340 if (info.v3) {
2341 nfsm_srvwcc_data(&info, nfsd, fdirfor_ret, &fdirfor,
2342 fdiraft_ret, &fdiraft);
2343 nfsm_srvwcc_data(&info, nfsd, tdirfor_ret, &tdirfor,
2344 tdiraft_ret, &tdiraft);
984263bc
MD
2345 }
2346 error = 0;
2347 /* fall through */
2348
2349nfsmout:
42edf14f 2350 *mrq = info.mreq;
984263bc
MD
2351 if (tdirp)
2352 vrele(tdirp);
fad57d0e 2353 nlookup_done(&tond);
984263bc
MD
2354 if (fdirp)
2355 vrele(fdirp);
fad57d0e 2356 nlookup_done(&fromnd);
984263bc
MD
2357 return (error);
2358}
2359
2360/*
2361 * nfs link service
2362 */
2363int
e851b29e
CP
2364nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2365 struct thread *td, struct mbuf **mrq)
984263bc 2366{
984263bc 2367 struct sockaddr *nam = nfsd->nd_nam;
984263bc 2368 struct ucred *cred = &nfsd->nd_cr;
fad57d0e 2369 struct nlookupdata nd;
e07fef60 2370 int error = 0, rdonly, len, dirfor_ret = 1, diraft_ret = 1;
42edf14f 2371 int getret = 1;
fad57d0e
MD
2372 struct vnode *dirp;
2373 struct vnode *dvp;
2374 struct vnode *vp;
2375 struct vnode *xp;
67863d04 2376 struct mount *xmp;
984263bc
MD
2377 struct vattr dirfor, diraft, at;
2378 nfsfh_t nfh, dnfh;
2379 fhandle_t *fhp, *dfhp;
42edf14f
MD
2380 struct nfsm_info info;
2381
2382 info.mrep = nfsd->nd_mrep;
2383 info.mreq = NULL;
2384 info.md = nfsd->nd_md;
2385 info.dpos = nfsd->nd_dpos;
2386 info.v3 = (nfsd->nd_flag & ND_NFSV3);
984263bc
MD
2387
2388 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fad57d0e
MD
2389 nlookup_zero(&nd);
2390 dirp = dvp = vp = xp = NULL;
1d0de3d3 2391 xmp = NULL;
984263bc
MD
2392
2393 fhp = &nfh.fh_generic;
2394 dfhp = &dnfh.fh_generic;
42edf14f
MD
2395 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
2396 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, dfhp, &error));
2397 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
984263bc 2398
67863d04 2399 error = nfsrv_fhtovp(fhp, FALSE, &xmp, &xp, cred, slp, nam,
984263bc
MD
2400 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
2401 if (error) {
42edf14f
MD
2402 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2403 NFSX_POSTOPATTR(info.v3) +
2404 NFSX_WCCDATA(info.v3),
2405 &error));
2406 nfsm_srvpostop_attr(&info, nfsd, getret, &at);
2407 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2408 diraft_ret, &diraft);
fad57d0e 2409 xp = NULL;
984263bc
MD
2410 error = 0;
2411 goto nfsmout;
2412 }
fad57d0e 2413 if (xp->v_type == VDIR) {
984263bc
MD
2414 error = EPERM; /* POSIX */
2415 goto out1;
2416 }
fad57d0e 2417
3a907475 2418 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
42edf14f 2419 dfhp, len, slp, nam, &info.md, &info.dpos, &dirp,
fad57d0e 2420 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
984263bc 2421 if (dirp) {
42edf14f 2422 if (info.v3)
87de5057 2423 dirfor_ret = VOP_GETATTR(dirp, &dirfor);
984263bc
MD
2424 }
2425 if (error)
2426 goto out1;
2427
fad57d0e 2428 if (vp != NULL) {
984263bc
MD
2429 error = EEXIST;
2430 goto out;
2431 }
fad57d0e 2432 if (xp->v_mount != dvp->v_mount)
984263bc
MD
2433 error = EXDEV;
2434out:
2435 if (!error) {
08daea96
MD
2436 vn_unlock(dvp);
2437 error = VOP_NLINK(&nd.nl_nch, dvp, xp, nd.nl_cred);
2438 vrele(dvp);
2439 dvp = NULL;
984263bc
MD
2440 }
2441 /* fall through */
2442
2443out1:
42edf14f 2444 if (info.v3)
87de5057 2445 getret = VOP_GETATTR(xp, &at);
984263bc 2446 if (dirp)
87de5057 2447 diraft_ret = VOP_GETATTR(dirp, &diraft);
42edf14f
MD
2448 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2449 NFSX_POSTOPATTR(info.v3) + NFSX_WCCDATA(info.v3),
2450 &error));
2451 if (info.v3) {
2452 nfsm_srvpostop_attr(&info, nfsd, getret, &at);
2453 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2454 diraft_ret, &diraft);
984263bc
MD
2455 error = 0;
2456 }
2457 /* fall through */
2458
2459nfsmout:
42edf14f 2460 *mrq = info.mreq;
fad57d0e 2461 nlookup_done(&nd);
984263bc
MD
2462 if (dirp)
2463 vrele(dirp);
fad57d0e
MD
2464 if (xp)
2465 vrele(xp);
2466 if (dvp) {
2467 if (dvp == vp)
2468 vrele(dvp);
984263bc 2469 else
fad57d0e 2470 vput(dvp);
984263bc 2471 }
fad57d0e
MD
2472 if (vp)
2473 vput(vp);
984263bc
MD
2474 return(error);
2475}
2476
2477/*
2478 * nfs symbolic link service
2479 */
2480int
e851b29e
CP
2481nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2482 struct thread *td, struct mbuf **mrq)
984263bc 2483{
984263bc 2484 struct sockaddr *nam = nfsd->nd_nam;
984263bc
MD
2485 struct ucred *cred = &nfsd->nd_cr;
2486 struct vattr va, dirfor, diraft;
fad57d0e 2487 struct nlookupdata nd;
dadab5e9 2488 struct vattr *vap = &va;
984263bc 2489 struct nfsv2_sattr *sp;
42edf14f 2490 char *pathcp = NULL;
984263bc
MD
2491 struct uio io;
2492 struct iovec iv;
e07fef60 2493 int error = 0, len, len2, dirfor_ret = 1, diraft_ret = 1;
fad57d0e
MD
2494 struct vnode *dirp;
2495 struct vnode *vp;
08daea96 2496 struct vnode *dvp;
984263bc
MD
2497 nfsfh_t nfh;
2498 fhandle_t *fhp;
42edf14f 2499 struct nfsm_info info;
984263bc
MD
2500
2501 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fad57d0e 2502 nlookup_zero(&nd);
08daea96
MD
2503 dirp = NULL;
2504 dvp = NULL;
2505 vp = NULL;
984263bc 2506
42edf14f
MD
2507 info.mrep = nfsd->nd_mrep;
2508 info.mreq = NULL;
2509 info.md = nfsd->nd_md;
2510 info.dpos = nfsd->nd_dpos;
2511 info.v3 = (nfsd->nd_flag & ND_NFSV3);
2512
984263bc 2513 fhp = &nfh.fh_generic;
42edf14f
MD
2514 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
2515 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
fad57d0e 2516
3a907475 2517 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
42edf14f 2518 fhp, len, slp, nam, &info.md, &info.dpos, &dirp,
fad57d0e 2519 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
984263bc 2520 if (dirp) {
42edf14f 2521 if (info.v3)
87de5057 2522 dirfor_ret = VOP_GETATTR(dirp, &dirfor);
984263bc
MD
2523 }
2524 if (error)
2525 goto out;
2526
2527 VATTR_NULL(vap);
42edf14f
MD
2528 if (info.v3) {
2529 ERROROUT(nfsm_srvsattr(&info, vap));
2530 }
2531 NEGATIVEOUT(len2 = nfsm_strsiz(&info, NFS_MAXPATHLEN));
884717e1 2532 pathcp = kmalloc(len2 + 1, M_TEMP, M_WAITOK);
984263bc
MD
2533 iv.iov_base = pathcp;
2534 iv.iov_len = len2;
2535 io.uio_resid = len2;
2536 io.uio_offset = 0;
2537 io.uio_iov = &iv;
2538 io.uio_iovcnt = 1;
2539 io.uio_segflg = UIO_SYSSPACE;
2540 io.uio_rw = UIO_READ;
dadab5e9 2541 io.uio_td = NULL;
42edf14f
MD
2542 ERROROUT(nfsm_mtouio(&info, &io, len2));
2543 if (info.v3 == 0) {
2544 NULLOUT(sp = nfsm_dissect(&info, NFSX_V2SATTR));
984263bc
MD
2545 vap->va_mode = nfstov_mode(sp->sa_mode);
2546 }
2547 *(pathcp + len2) = '\0';
fad57d0e 2548 if (vp) {
984263bc
MD
2549 error = EEXIST;
2550 goto out;
2551 }
2552
984263bc
MD
2553 if (vap->va_mode == (mode_t)VNOVAL)
2554 vap->va_mode = 0;
08daea96
MD
2555 if (dvp != vp)
2556 vn_unlock(dvp);
2557 error = VOP_NSYMLINK(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap, pathcp);
2558 vrele(dvp);
2559 dvp = NULL;
fad57d0e 2560 if (error == 0) {
67863d04 2561 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid));
fad57d0e
MD
2562 error = VFS_VPTOFH(vp, &fhp->fh_fid);
2563 if (!error)
87de5057 2564 error = VOP_GETATTR(vp, vap);
fad57d0e
MD
2565 }
2566
984263bc 2567out:
08daea96
MD
2568 if (dvp) {
2569 if (dvp == vp)
2570 vrele(dvp);
2571 else
2572 vput(dvp);
2573 }
fad57d0e
MD
2574 if (vp) {
2575 vput(vp);
2576 vp = NULL;
2577 }
984263bc 2578 if (pathcp) {
884717e1 2579 kfree(pathcp, M_TEMP);
984263bc
MD
2580 pathcp = NULL;
2581 }
2582 if (dirp) {
87de5057 2583 diraft_ret = VOP_GETATTR(dirp, &diraft);
984263bc
MD
2584 vrele(dirp);
2585 dirp = NULL;
2586 }
42edf14f
MD
2587 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2588 NFSX_SRVFH(info.v3) + NFSX_POSTOPATTR(info.v3) +
2589 NFSX_WCCDATA(info.v3),
2590 &error));
2591 if (info.v3) {
984263bc 2592 if (!error) {
42edf14f
MD
2593 nfsm_srvpostop_fh(&info, fhp);
2594 nfsm_srvpostop_attr(&info, nfsd, 0, vap);
984263bc 2595 }
42edf14f
MD
2596 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2597 diraft_ret, &diraft);
984263bc
MD
2598 }
2599 error = 0;
2600 /* fall through */
2601
2602nfsmout:
42edf14f 2603 *mrq = info.mreq;
fad57d0e
MD
2604 nlookup_done(&nd);
2605 if (vp)
2606 vput(vp);
984263bc
MD
2607 if (dirp)
2608 vrele(dirp);
2609 if (pathcp)
884717e1 2610 kfree(pathcp, M_TEMP);
984263bc
MD
2611 return (error);
2612}
2613
2614/*
2615 * nfs mkdir service
2616 */
2617int
e851b29e
CP
2618nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2619 struct thread *td, struct mbuf **mrq)
984263bc 2620{
984263bc 2621 struct sockaddr *nam = nfsd->nd_nam;
984263bc
MD
2622 struct ucred *cred = &nfsd->nd_cr;
2623 struct vattr va, dirfor, diraft;
dadab5e9
MD
2624 struct vattr *vap = &va;
2625 struct nfs_fattr *fp;
fad57d0e 2626 struct nlookupdata nd;
dadab5e9 2627 u_int32_t *tl;
e07fef60 2628 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
fad57d0e 2629 struct vnode *dirp;
08daea96 2630 struct vnode *dvp;
fad57d0e 2631 struct vnode *vp;
984263bc
MD
2632 nfsfh_t nfh;
2633 fhandle_t *fhp;
42edf14f 2634 struct nfsm_info info;
984263bc
MD
2635
2636 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fad57d0e
MD
2637 nlookup_zero(&nd);
2638 dirp = NULL;
08daea96 2639 dvp = NULL;
fad57d0e 2640 vp = NULL;
984263bc 2641
42edf14f
MD
2642 info.dpos = nfsd->nd_dpos;
2643 info.mrep = nfsd->nd_mrep;
2644 info.mreq = NULL;
2645 info.md = nfsd->nd_md;
2646 info.v3 = (nfsd->nd_flag & ND_NFSV3);
2647
984263bc 2648 fhp = &nfh.fh_generic;
42edf14f
MD
2649 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
2650 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
984263bc 2651
3a907475 2652 error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
42edf14f 2653 fhp, len, slp, nam, &info.md, &info.dpos, &dirp,
fad57d0e 2654 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
984263bc 2655 if (dirp) {
42edf14f 2656 if (info.v3)
87de5057 2657 dirfor_ret = VOP_GETATTR(dirp, &dirfor);
984263bc
MD
2658 }
2659 if (error) {
42edf14f
MD
2660 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2661 NFSX_WCCDATA(info.v3), &error));
2662 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2663 diraft_ret, &diraft);
984263bc
MD
2664 error = 0;
2665 goto nfsmout;
2666 }
2667 VATTR_NULL(vap);
42edf14f
MD
2668 if (info.v3) {
2669 ERROROUT(nfsm_srvsattr(&info, vap));
984263bc 2670 } else {
42edf14f 2671 NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
984263bc
MD
2672 vap->va_mode = nfstov_mode(*tl++);
2673 }
2674
2675 /*
2676 * At this point nd.ni_dvp is referenced and exclusively locked and
2677 * nd.ni_vp, if it exists, is referenced but not locked.
2678 */
2679
2680 vap->va_type = VDIR;
fad57d0e 2681 if (vp != NULL) {
984263bc
MD
2682 error = EEXIST;
2683 goto out;
2684 }
2685
2686 /*
2687 * Issue mkdir op. Since SAVESTART is not set, the pathname
2688 * component is freed by the VOP call. This will fill-in
2689 * nd.ni_vp, reference, and exclusively lock it.
2690 */
2691 if (vap->va_mode == (mode_t)VNOVAL)
2692 vap->va_mode = 0;
08daea96
MD
2693 vn_unlock(dvp);
2694 error = VOP_NMKDIR(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap);
2695 vrele(dvp);
2696 dvp = NULL;
984263bc 2697
fad57d0e 2698 if (error == 0) {
67863d04 2699 bzero(&fhp->fh_fid, sizeof(fhp->fh_fid));
fad57d0e
MD
2700 error = VFS_VPTOFH(vp, &fhp->fh_fid);
2701 if (error == 0)
87de5057 2702 error = VOP_GETATTR(vp, vap);
984263bc
MD
2703 }
2704out:
2705 if (dirp)
87de5057 2706 diraft_ret = VOP_GETATTR(dirp, &diraft);
42edf14f
MD
2707 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2708 NFSX_SRVFH(info.v3) + NFSX_POSTOPATTR(info.v3) +
2709 NFSX_WCCDATA(info.v3),
2710 &error));
2711 if (info.v3) {
984263bc 2712 if (!error) {
42edf14f
MD
2713 nfsm_srvpostop_fh(&info, fhp);
2714 nfsm_srvpostop_attr(&info, nfsd, 0, vap);
984263bc 2715 }
42edf14f
MD
2716 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2717 diraft_ret, &diraft);
984263bc 2718 } else {
42edf14f
MD
2719 nfsm_srvfhtom(&info, fhp);
2720 fp = nfsm_build(&info, NFSX_V2FATTR);
2721 nfsm_srvfattr(nfsd, vap, fp);
984263bc
MD
2722 }
2723 error = 0;
2724 /* fall through */
2725
2726nfsmout:
42edf14f 2727 *mrq = info.mreq;
fad57d0e 2728 nlookup_done(&nd);
984263bc
MD
2729 if (dirp)
2730 vrele(dirp);
08daea96
MD
2731 if (dvp) {
2732 if (dvp == vp)
2733 vrele(dvp);
2734 else
2735 vput(dvp);
2736 }
fad57d0e
MD
2737 if (vp)
2738 vput(vp);
984263bc
MD
2739 return (error);
2740}
2741
2742/*
2743 * nfs rmdir service
2744 */
2745int
e851b29e
CP
2746nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2747 struct thread *td, struct mbuf **mrq)
984263bc 2748{
984263bc 2749 struct sockaddr *nam = nfsd->nd_nam;
984263bc 2750 struct ucred *cred = &nfsd->nd_cr;
e07fef60 2751 int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
fad57d0e 2752 struct vnode *dirp;
08daea96 2753 struct vnode *dvp;
fad57d0e 2754 struct vnode *vp;
984263bc
MD
2755 struct vattr dirfor, diraft;
2756 nfsfh_t nfh;
2757 fhandle_t *fhp;
fad57d0e 2758 struct nlookupdata nd;
42edf14f 2759 struct nfsm_info info;
984263bc
MD
2760
2761 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fad57d0e
MD
2762 nlookup_zero(&nd);
2763 dirp = NULL;
08daea96 2764 dvp = NULL;
fad57d0e 2765 vp = NULL;
984263bc 2766
42edf14f
MD
2767 info.mrep = nfsd->nd_mrep;
2768 info.mreq = NULL;
2769 info.md = nfsd->nd_md;
2770 info.dpos = nfsd->nd_dpos;
2771 info.v3 = (nfsd->nd_flag & ND_NFSV3);
2772
984263bc 2773 fhp = &nfh.fh_generic;
42edf14f
MD
2774 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
2775 NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
fad57d0e 2776
3a907475 2777 error = nfs_namei(&nd, cred, NLC_DELETE, &dvp, &vp,
42edf14f 2778 fhp, len, slp, nam, &info.md, &info.dpos, &dirp,
fad57d0e 2779 td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
984263bc 2780 if (dirp) {
42edf14f 2781 if (info.v3)
87de5057 2782 dirfor_ret = VOP_GETATTR(dirp, &dirfor);
984263bc
MD
2783 }
2784 if (error) {
42edf14f
MD
2785 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2786 NFSX_WCCDATA(info.v3), &error));
2787 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2788 diraft_ret, &diraft);
984263bc
MD
2789 error = 0;
2790 goto nfsmout;
2791 }
984263bc
MD
2792 if (vp->v_type != VDIR) {
2793 error = ENOTDIR;
2794 goto out;
2795 }
fad57d0e 2796
984263bc
MD
2797 /*
2798 * The root of a mounted filesystem cannot be deleted.
2799 */
2800 if (vp->v_flag & VROOT)
2801 error = EBUSY;
2802out:
2803 /*
2804 * Issue or abort op. Since SAVESTART is not set, path name
2805 * component is freed by the VOP after either.
2806 */
2807 if (!error) {
08daea96
MD
2808 if (dvp != vp)
2809 vn_unlock(dvp);
fad57d0e
MD
2810 vput(vp);
2811 vp = NULL;
08daea96
MD
2812 error = VOP_NRMDIR(&nd.nl_nch, dvp, nd.nl_cred);
2813 vrele(dvp);
2814 dvp = NULL;
984263bc 2815 }
fad57d0e 2816 nlookup_done(&nd);
984263bc
MD
2817
2818 if (dirp)
87de5057 2819 diraft_ret = VOP_GETATTR(dirp, &diraft);
42edf14f
MD
2820 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_WCCDATA(info.v3), &error));
2821 if (info.v3) {
2822 nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2823 diraft_ret, &diraft);
984263bc
MD
2824 error = 0;
2825 }
2826 /* fall through */
2827
2828nfsmout:
42edf14f 2829 *mrq = info.mreq;
08daea96
MD
2830 if (dvp) {
2831 if (dvp == vp)
2832 vrele(dvp);
2833 else
2834 vput(dvp);
2835 }
fad57d0e 2836 nlookup_done(&nd);
984263bc
MD
2837 if (dirp)
2838 vrele(dirp);
fad57d0e
MD
2839 if (vp)
2840 vput(vp);
984263bc
MD
2841 return(error);
2842}
2843
2844/*
2845 * nfs readdir service
2846 * - mallocs what it thinks is enough to read
2847 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2848 * - calls VOP_READDIR()
2849 * - loops around building the reply
2850 * if the output generated exceeds count break out of loop
2851 * The nfsm_clget macro is used here so that the reply will be packed
2852 * tightly in mbuf clusters.
2853 * - it only knows that it has encountered eof when the VOP_READDIR()
2854 * reads nothing
2855 * - as such one readdir rpc will return eof false although you are there
2856 * and then the next will return eof
2857 * - it trims out records with d_fileno == 0
2858 * this doesn't matter for Unix clients, but they might confuse clients
2859 * for other os'.
2860 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2861 * than requested, but this may not apply to all filesystems. For
2862 * example, client NFS does not { although it is never remote mounted
2863 * anyhow }
2864 * The alternate call nfsrv_readdirplus() does lookups as well.
2865 * PS: The NFS protocol spec. does not clarify what the "count" byte
2866 * argument is a count of.. just name strings and file id's or the
2867 * entire reply rpc or ...
2868 * I tried just file name and id sizes and it confused the Sun client,
2869 * so I am using the full rpc size now. The "paranoia.." comment refers
2870 * to including the status longwords that are not a part of the dir.
2871 * "entry" structures, but are in the rpc.
2872 */
2873struct flrep {
2874 nfsuint64 fl_off;
2875 u_int32_t fl_postopok;
2876 u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)];
2877 u_int32_t fl_fhok;
2878 u_int32_t fl_fhsize;
2879 u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)];
2880};
2881
2882int
e851b29e
CP
2883nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2884 struct thread *td, struct mbuf **mrq)
984263bc 2885{
984263bc 2886 struct sockaddr *nam = nfsd->nd_nam;
984263bc 2887 struct ucred *cred = &nfsd->nd_cr;
dadab5e9 2888 char *bp, *be;
dadab5e9
MD
2889 struct dirent *dp;
2890 caddr_t cp;
2891 u_int32_t *tl;
42edf14f
MD
2892 struct mbuf *mp1, *mp2;
2893 char *cpos, *cend, *rbuf;
984263bc 2894 struct vnode *vp = NULL;
67863d04 2895 struct mount *mp = NULL;
984263bc
MD
2896 struct vattr at;
2897 nfsfh_t nfh;
2898 fhandle_t *fhp;
2899 struct uio io;
2900 struct iovec iv;
2901 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
e07fef60 2902 int siz, cnt, fullsiz, eofflag, rdonly, ncookies;
1d0de3d3
SW
2903 u_quad_t off, toff;
2904#if 0
2905 u_quad_t verf;
2906#endif
6676af76 2907 off_t *cookies = NULL, *cookiep;
42edf14f
MD
2908 struct nfsm_info info;
2909
2910 info.mrep = nfsd->nd_mrep;
2911 info.mreq = NULL;
2912 info.md = nfsd->nd_md;
2913 info.dpos = nfsd->nd_dpos;
2914 info.v3 = (nfsd->nd_flag & ND_NFSV3);
984263bc
MD
2915
2916 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2917 fhp = &nfh.fh_generic;
42edf14f
MD
2918 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
2919 if (info.v3) {
2920 NULLOUT(tl = nfsm_dissect(&info, 5 * NFSX_UNSIGNED));
984263bc
MD
2921 toff = fxdr_hyper(tl);
2922 tl += 2;
1d0de3d3 2923#if 0
984263bc 2924 verf = fxdr_hyper(tl);
1d0de3d3 2925#endif
984263bc
MD
2926 tl += 2;
2927 } else {
42edf14f 2928 NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED));
984263bc 2929 toff = fxdr_unsigned(u_quad_t, *tl++);
1d0de3d3 2930#if 0
984263bc 2931 verf = 0; /* shut up gcc */
1d0de3d3 2932#endif
984263bc
MD
2933 }
2934 off = toff;
2935 cnt = fxdr_unsigned(int, *tl);
2936 siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2937 xfer = NFS_SRVMAXDATA(nfsd);
ebaced37 2938 if ((unsigned)cnt > xfer)
984263bc 2939 cnt = xfer;
ebaced37 2940 if ((unsigned)siz > xfer)
984263bc
MD
2941 siz = xfer;
2942 fullsiz = siz;
67863d04 2943 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
984263bc
MD
2944 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
2945 if (!error && vp->v_type != VDIR) {
2946 error = ENOTDIR;
2947 vput(vp);
2948 vp = NULL;
2949 }
2950 if (error) {
42edf14f
MD
2951 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error));
2952 nfsm_srvpostop_attr(&info, nfsd, getret, &at);
984263bc
MD
2953 error = 0;
2954 goto nfsmout;
2955 }
2956
2957 /*
2958 * Obtain lock on vnode for this section of the code
2959 */
2960
42edf14f 2961 if (info.v3) {
87de5057 2962 error = getret = VOP_GETATTR(vp, &at);
984263bc
MD
2963#if 0
2964 /*
2965 * XXX This check may be too strict for Solaris 2.5 clients.
2966 */
2967 if (!error && toff && verf && verf != at.va_filerev)
2968 error = NFSERR_BAD_COOKIE;
2969#endif
2970 }
2971 if (!error)
67863d04 2972 error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0);
984263bc
MD
2973 if (error) {
2974 vput(vp);
2975 vp = NULL;
42edf14f
MD
2976 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2977 NFSX_POSTOPATTR(info.v3), &error));
2978 nfsm_srvpostop_attr(&info, nfsd, getret, &at);
984263bc
MD
2979 error = 0;
2980 goto nfsmout;
2981 }
a11aaa81 2982 vn_unlock(vp);
984263bc
MD
2983
2984 /*
2985 * end section. Allocate rbuf and continue
2986 */
884717e1 2987 rbuf = kmalloc(siz, M_TEMP, M_WAITOK);
984263bc
MD
2988again:
2989 iv.iov_base = rbuf;
2990 iv.iov_len = fullsiz;
2991 io.uio_iov = &iv;
2992 io.uio_iovcnt = 1;
2993 io.uio_offset = (off_t)off;
2994 io.uio_resid = fullsiz;
2995 io.uio_segflg = UIO_SYSSPACE;
2996 io.uio_rw = UIO_READ;
dadab5e9 2997 io.uio_td = NULL;
984263bc 2998 eofflag = 0;
984263bc 2999 if (cookies) {
efda3bd0 3000 kfree((caddr_t)cookies, M_TEMP);
984263bc
MD
3001 cookies = NULL;
3002 }
3003 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
3004 off = (off_t)io.uio_offset;
3005 if (!cookies && !error)
3006 error = NFSERR_PERM;
42edf14f 3007 if (info.v3) {
87de5057 3008 getret = VOP_GETATTR(vp, &at);
984263bc
MD
3009 if (!error)
3010 error = getret;
3011 }
984263bc
MD
3012 if (error) {
3013 vrele(vp);
3014 vp = NULL;
efda3bd0 3015 kfree((caddr_t)rbuf, M_TEMP);
984263bc 3016 if (cookies)
efda3bd0 3017 kfree((caddr_t)cookies, M_TEMP);
42edf14f
MD
3018 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3019 NFSX_POSTOPATTR(info.v3), &error));
3020 nfsm_srvpostop_attr(&info, nfsd, getret, &at);
984263bc
MD
3021 error = 0;
3022 goto nfsmout;
3023 }
3024 if (io.uio_resid) {
3025 siz -= io.uio_resid;
3026
3027 /*
3028 * If nothing read, return eof
3029 * rpc reply
3030 */
3031 if (siz == 0) {
3032 vrele(vp);
3033 vp = NULL;
42edf14f
MD
3034 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3035 NFSX_POSTOPATTR(info.v3) +
3036 NFSX_COOKIEVERF(info.v3) +
3037 2 * NFSX_UNSIGNED,
3038 &error));
3039 if (info.v3) {
3040 nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3041 tl = nfsm_build(&info, 4 * NFSX_UNSIGNED);
984263bc
MD
3042 txdr_hyper(at.va_filerev, tl);
3043 tl += 2;
3044 } else
42edf14f 3045 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED);
984263bc
MD
3046 *tl++ = nfs_false;
3047 *tl = nfs_true;
884717e1
SW
3048 kfree((caddr_t)rbuf, M_TEMP);
3049 kfree((caddr_t)cookies, M_TEMP);
984263bc
MD
3050 error = 0;
3051 goto nfsmout;
3052 }
3053 }
3054
3055 /*
3056 * Check for degenerate cases of nothing useful read.
3057 * If so go try again
3058 */
3059 cpos = rbuf;
3060 cend = rbuf + siz;
3061 dp = (struct dirent *)cpos;
3062 cookiep = cookies;
3063 /*
3064 * For some reason FreeBSD's ufs_readdir() chooses to back the
3065 * directory offset up to a block boundary, so it is necessary to
3066 * skip over the records that preceed the requested offset. This
3067 * requires the assumption that file offset cookies monotonically
3068 * increase.
3069 */
3070 while (cpos < cend && ncookies > 0 &&
01f31ab3 3071 (dp->d_ino == 0 || dp->d_type == DT_WHT ||
984263bc 3072 ((u_quad_t)(*cookiep)) <= toff)) {
01f31ab3
JS
3073 dp = _DIRENT_NEXT(dp);
3074 cpos = (char *)dp;
984263bc
MD
3075 cookiep++;
3076 ncookies--;
3077 }
3078 if (cpos >= cend || ncookies == 0) {
3079 toff = off;
3080 siz = fullsiz;
3081 goto again;
3082 }
3083
3084 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
42edf14f
MD
3085 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3086 NFSX_POSTOPATTR(info.v3) +
3087 NFSX_COOKIEVERF(info.v3) + siz,
3088 &error));
3089 if (info.v3) {
3090 nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3091 tl = nfsm_build(&info, 2 * NFSX_UNSIGNED);
984263bc
MD
3092 txdr_hyper(at.va_filerev, tl);
3093 }
42edf14f
MD
3094 mp1 = mp2 = info.mb;
3095 bp = info.bpos;
67863d04 3096 be = bp + M_TRAILINGSPACE(mp1);
984263bc
MD
3097
3098 /* Loop through the records and build reply */
3099 while (cpos < cend && ncookies > 0) {
01f31ab3 3100 if (dp->d_ino != 0 && dp->d_type != DT_WHT) {
984263bc
MD
3101 nlen = dp->d_namlen;
3102 rem = nfsm_rndup(nlen) - nlen;
3103 len += (4 * NFSX_UNSIGNED + nlen + rem);
42edf14f 3104 if (info.v3)
984263bc
MD
3105 len += 2 * NFSX_UNSIGNED;
3106 if (len > cnt) {
3107 eofflag = 0;
3108 break;
3109 }
3110 /*
3111 * Build the directory record xdr from
3112 * the dirent entry.
3113 */
42edf14f 3114 tl = nfsm_clget(&info, mp1, mp2, bp, be);
984263bc
MD
3115 *tl = nfs_true;
3116 bp += NFSX_UNSIGNED;
42edf14f
MD
3117 if (info.v3) {
3118 tl = nfsm_clget(&info, mp1, mp2, bp, be);
ebaced37 3119 *tl = txdr_unsigned(dp->d_ino >> 32);
984263bc
MD
3120 bp += NFSX_UNSIGNED;
3121 }
42edf14f 3122 tl = nfsm_clget(&info, mp1, mp2, bp, be);
01f31ab3 3123 *tl = txdr_unsigned(dp->d_ino);
984263bc 3124 bp += NFSX_UNSIGNED;
42edf14f 3125 tl = nfsm_clget(&info, mp1, mp2, bp, be);
984263bc
MD
3126 *tl = txdr_unsigned(nlen);
3127 bp += NFSX_UNSIGNED;
3128
3129 /* And loop around copying the name */
3130 xfer = nlen;
3131 cp = dp->d_name;
3132 while (xfer > 0) {
42edf14f 3133 tl = nfsm_clget(&info, mp1, mp2, bp, be);
984263bc
MD
3134 if ((bp+xfer) > be)
3135 tsiz = be-bp;
3136 else
3137 tsiz = xfer;
3138 bcopy(cp, bp, tsiz);
3139 bp += tsiz;
3140 xfer -= tsiz;
3141 if (xfer > 0)
3142 cp += tsiz;
3143 }
3144 /* And null pad to a int32_t boundary */
3145 for (i = 0; i < rem; i++)
3146 *bp++ = '\0';
42edf14f 3147 tl = nfsm_clget(&info, mp1, mp2, bp, be);
984263bc
MD
3148
3149 /* Finish off the record */
42edf14f 3150 if (info.v3) {
6676af76 3151 *tl = txdr_unsigned(*cookiep >> 32);
984263bc 3152 bp += NFSX_UNSIGNED;
42edf14f 3153 tl = nfsm_clget(&info, mp1, mp2, bp, be);
984263bc
MD
3154 }
3155 *tl = txdr_unsigned(*cookiep);
3156 bp += NFSX_UNSIGNED;
3157 }
01f31ab3
JS
3158 dp = _DIRENT_NEXT(dp);
3159 cpos = (char *)dp;
984263bc
MD
3160 cookiep++;
3161 ncookies--;
3162 }
3163 vrele(vp);
3164 vp = NULL;
42edf14f 3165 tl = nfsm_clget(&info, mp1, mp2, bp, be);
984263bc
MD
3166 *tl = nfs_false;
3167 bp += NFSX_UNSIGNED;
42edf14f 3168 tl = nfsm_clget(&info, mp1, mp2, bp, be);
984263bc
MD
3169 if (eofflag)
3170 *tl = nfs_true;
3171 else
3172 *tl = nfs_false;
3173 bp += NFSX_UNSIGNED;
42edf14f 3174 if (mp1 != info.mb) {
984263bc 3175 if (bp < be)
67863d04 3176 mp1->m_len = bp - mtod(mp1, caddr_t);
984263bc 3177 } else
42edf14f 3178 mp1->m_len += bp - info.bpos;
884717e1
SW
3179 kfree((caddr_t)rbuf, M_TEMP);
3180 kfree((caddr_t)cookies, M_TEMP);
984263bc
MD
3181
3182nfsmout:
42edf14f 3183 *mrq = info.mreq;
984263bc
MD
3184 if (vp)
3185 vrele(vp);
3186 return(error);
3187}
3188
3189int
e851b29e
CP
3190nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3191 struct thread *td, struct mbuf **mrq)
984263bc 3192{
984263bc 3193 struct sockaddr *nam = nfsd->nd_nam;
984263bc 3194 struct ucred *cred = &nfsd->nd_cr;
dadab5e9 3195 char *bp, *be;
dadab5e9
MD
3196 struct dirent *dp;
3197 caddr_t cp;
3198 u_int32_t *tl;
42edf14f
MD
3199 struct mbuf *mp1, *mp2;
3200 char *cpos, *cend, *rbuf;
984263bc 3201 struct vnode *vp = NULL, *nvp;
67863d04 3202 struct mount *mp = NULL;
984263bc
MD
3203 struct flrep fl;
3204 nfsfh_t nfh;
3205 fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
3206 struct uio io;
3207 struct iovec iv;
3208 struct vattr va, at, *vap = &va;
3209 struct nfs_fattr *fp;
3210 int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
e07fef60 3211 int siz, cnt, fullsiz, eofflag, rdonly, dirlen, ncookies;
1d0de3d3
SW
3212 u_quad_t off, toff;
3213#if 0
3214 u_quad_t verf;
3215#endif
6676af76 3216 off_t *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */
42edf14f
MD
3217 struct nfsm_info info;
3218
3219 info.mrep = nfsd->nd_mrep;
3220 info.mreq = NULL;
3221 info.md = nfsd->nd_md;
3222 info.dpos = nfsd->nd_dpos;
ebaced37 3223 info.v3 = (nfsd->nd_flag & ND_NFSV3);
984263bc
MD
3224
3225 nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3226 fhp = &nfh.fh_generic;
42edf14f
MD
3227 NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
3228 NULLOUT(tl = nfsm_dissect(&info, 6 * NFSX_UNSIGNED));
984263bc
MD
3229 toff = fxdr_hyper(tl);
3230 tl += 2;
1d0de3d3 3231#if 0
984263bc 3232 verf = fxdr_hyper(tl);
1d0de3d3 3233#endif
984263bc
MD
3234 tl += 2;
3235 siz = fxdr_unsigned(int, *tl++);
3236 cnt = fxdr_unsigned(int, *tl);
3237 off = toff;
3238 siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
3239 xfer = NFS_SRVMAXDATA(nfsd);
ebaced37 3240 if ((unsigned)cnt > xfer)
984263bc 3241 cnt = xfer;
ebaced37 3242 if ((unsigned)siz > xfer)
984263bc
MD
3243 siz = xfer;
3244 fullsiz = siz;
67863d04 3245 error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
ebaced37 3246 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
984263bc
MD
3247 if (!error && vp->v_type != VDIR) {
3248 error = ENOTDIR;
3249 vput(vp);
3250 vp = NULL;
3251 }
3252 if (error) {
42edf14f
MD
3253 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error));
3254 nfsm_srvpostop_attr(&info, nfsd, getret, &at);
984263bc
MD
3255 error = 0;
3256 goto nfsmout;
3257 }
87de5057 3258 error = getret = VOP_GETATTR(vp, &at);
984263bc
MD
3259#if 0
3260 /*
3261 * XXX This check may be too strict for Solaris 2.5 clients.
3262 */
3263 if (!error && toff && verf && verf != at.va_filerev)
3264 error = NFSERR_BAD_COOKIE;
3265#endif
3266 if (!error) {
67863d04 3267 error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0);
984263bc
MD
3268 }
3269 if (error) {
3270 vput(vp);
3271 vp = NULL;
42edf14f
MD
3272 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3273 NFSX_V3POSTOPATTR, &error));
3274 nfsm_srvpostop_attr(&info, nfsd, getret, &at);
984263bc
MD
3275 error = 0;
3276 goto nfsmout;
3277 }
a11aaa81 3278 vn_unlock(vp);
884717e1 3279 rbuf = kmalloc(siz, M_TEMP, M_WAITOK);
984263bc
MD
3280again:
3281 iv.iov_base = rbuf;
3282 iv.iov_len = fullsiz;
3283 io.uio_iov = &iv;
3284 io.uio_iovcnt = 1;
3285 io.uio_offset = (off_t)off;
3286 io.uio_resid = fullsiz;
3287 io.uio_segflg = UIO_SYSSPACE;
3288 io.uio_rw = UIO_READ;
dadab5e9 3289 io.uio_td = NULL;
984263bc 3290 eofflag = 0;
984263bc 3291 if (cookies) {
efda3bd0 3292 kfree((caddr_t)cookies, M_TEMP);
984263bc
MD
3293 cookies = NULL;
3294 }
3295 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
3296 off = (u_quad_t)io.uio_offset;
87de5057 3297 getret = VOP_GETATTR(vp, &at);
984263bc
MD
3298 if (!cookies && !error)
3299 error = NFSERR_PERM;
3300 if (!error)
3301 error = getret;
3302 if (error) {
3303 vrele(vp);
3304 vp = NULL;
3305 if (cookies)
efda3bd0
MD
3306 kfree((caddr_t)cookies, M_TEMP);
3307 kfree((caddr_t)rbuf, M_TEMP);
42edf14f
MD
3308 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3309 NFSX_V3POSTOPATTR, &error));
3310 nfsm_srvpostop_attr(&info, nfsd, getret, &at);
984263bc
MD
3311 error = 0;
3312 goto nfsmout;
3313 }
3314 if (io.uio_resid) {
3315 siz -= io.uio_resid;
3316
3317 /*
3318 * If nothing read, return eof
3319 * rpc reply
3320 */
3321 if (siz == 0) {
3322 vrele(vp);
3323 vp = NULL;
42edf14f
MD
3324 NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3325 NFSX_V3POSTOPATTR +
3326 NFSX_V3COOKIEVERF +
3327 2 * NFSX_UNSIGNED,