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