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