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