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