nfs_common.c revision 83651
1/*
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	@(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/sys/nfs/nfs_common.c 83651 2001-09-18 23:32:09Z peter $");
41
42/*
43 * These functions support the macros and help fiddle mbuf chains for
44 * the nfs op functions. They do things like create the rpc header and
45 * copy data between mbuf chains and uio lists.
46 */
47
48#include <sys/param.h>
49#include <sys/systm.h>
50#include <sys/kernel.h>
51#include <sys/bio.h>
52#include <sys/buf.h>
53#include <sys/proc.h>
54#include <sys/mount.h>
55#include <sys/vnode.h>
56#include <sys/namei.h>
57#include <sys/mbuf.h>
58#include <sys/socket.h>
59#include <sys/stat.h>
60#include <sys/malloc.h>
61#include <sys/sysent.h>
62#include <sys/syscall.h>
63
64#include <vm/vm.h>
65#include <vm/vm_object.h>
66#include <vm/vm_extern.h>
67#include <vm/vm_zone.h>
68
69#include <nfs/rpcv2.h>
70#include <nfs/nfsproto.h>
71#include <nfsserver/nfs.h>
72#include <nfs/xdr_subs.h>
73#include <nfs/nfs_common.h>
74
75#include <netinet/in.h>
76
77enum vtype nv3tov_type[8]= {
78	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
79};
80nfstype nfsv3_type[9] = {
81	NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON
82};
83
84u_quad_t
85nfs_curusec(void)
86{
87	struct timeval tv;
88
89	getmicrotime(&tv);
90	return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec);
91}
92
93/*
94 * copies mbuf chain to the uio scatter/gather list
95 */
96int
97nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
98{
99	char *mbufcp, *uiocp;
100	int xfer, left, len;
101	struct mbuf *mp;
102	long uiosiz, rem;
103	int error = 0;
104
105	mp = *mrep;
106	mbufcp = *dpos;
107	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
108	rem = nfsm_rndup(siz)-siz;
109	while (siz > 0) {
110		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
111			return (EFBIG);
112		left = uiop->uio_iov->iov_len;
113		uiocp = uiop->uio_iov->iov_base;
114		if (left > siz)
115			left = siz;
116		uiosiz = left;
117		while (left > 0) {
118			while (len == 0) {
119				mp = mp->m_next;
120				if (mp == NULL)
121					return (EBADRPC);
122				mbufcp = mtod(mp, caddr_t);
123				len = mp->m_len;
124			}
125			xfer = (left > len) ? len : left;
126#ifdef notdef
127			/* Not Yet.. */
128			if (uiop->uio_iov->iov_op != NULL)
129				(*(uiop->uio_iov->iov_op))
130				(mbufcp, uiocp, xfer);
131			else
132#endif
133			if (uiop->uio_segflg == UIO_SYSSPACE)
134				bcopy(mbufcp, uiocp, xfer);
135			else
136				copyout(mbufcp, uiocp, xfer);
137			left -= xfer;
138			len -= xfer;
139			mbufcp += xfer;
140			uiocp += xfer;
141			uiop->uio_offset += xfer;
142			uiop->uio_resid -= xfer;
143		}
144		if (uiop->uio_iov->iov_len <= siz) {
145			uiop->uio_iovcnt--;
146			uiop->uio_iov++;
147		} else {
148			uiop->uio_iov->iov_base += uiosiz;
149			uiop->uio_iov->iov_len -= uiosiz;
150		}
151		siz -= uiosiz;
152	}
153	*dpos = mbufcp;
154	*mrep = mp;
155	if (rem > 0) {
156		if (len < rem)
157			error = nfs_adv(mrep, dpos, rem, len);
158		else
159			*dpos += rem;
160	}
161	return (error);
162}
163
164/*
165 * Help break down an mbuf chain by setting the first siz bytes contiguous
166 * pointed to by returned val.
167 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
168 * cases. (The macros use the vars. dpos and dpos2)
169 */
170int
171nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
172{
173	struct mbuf *mp, *mp2;
174	int siz2, xfer;
175	caddr_t ptr;
176
177	mp = *mdp;
178	while (left == 0) {
179		*mdp = mp = mp->m_next;
180		if (mp == NULL)
181			return (EBADRPC);
182		left = mp->m_len;
183		*dposp = mtod(mp, caddr_t);
184	}
185	if (left >= siz) {
186		*cp2 = *dposp;
187		*dposp += siz;
188	} else if (mp->m_next == NULL) {
189		return (EBADRPC);
190	} else if (siz > MHLEN) {
191		panic("nfs S too big");
192	} else {
193		MGET(mp2, M_TRYWAIT, MT_DATA);
194		mp2->m_next = mp->m_next;
195		mp->m_next = mp2;
196		mp->m_len -= left;
197		mp = mp2;
198		*cp2 = ptr = mtod(mp, caddr_t);
199		bcopy(*dposp, ptr, left);		/* Copy what was left */
200		siz2 = siz-left;
201		ptr += left;
202		mp2 = mp->m_next;
203		/* Loop around copying up the siz2 bytes */
204		while (siz2 > 0) {
205			if (mp2 == NULL)
206				return (EBADRPC);
207			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
208			if (xfer > 0) {
209				bcopy(mtod(mp2, caddr_t), ptr, xfer);
210				NFSMADV(mp2, xfer);
211				mp2->m_len -= xfer;
212				ptr += xfer;
213				siz2 -= xfer;
214			}
215			if (siz2 > 0)
216				mp2 = mp2->m_next;
217		}
218		mp->m_len = siz;
219		*mdp = mp2;
220		*dposp = mtod(mp2, caddr_t);
221	}
222	return (0);
223}
224
225/*
226 * Advance the position in the mbuf chain.
227 */
228int
229nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
230{
231	struct mbuf *m;
232	int s;
233
234	m = *mdp;
235	s = left;
236	while (s < offs) {
237		offs -= s;
238		m = m->m_next;
239		if (m == NULL)
240			return (EBADRPC);
241		s = m->m_len;
242	}
243	*mdp = m;
244	*dposp = mtod(m, caddr_t)+offs;
245	return (0);
246}
247
248void
249nfsm_build_xx(void **a, int s, struct mbuf **mb, caddr_t *bpos)
250{
251	struct mbuf *mb2;
252
253	if (s > M_TRAILINGSPACE(*mb)) {
254		MGET(mb2, M_TRYWAIT, MT_DATA);
255		if (s > MLEN)
256			panic("build > MLEN");
257		(*mb)->m_next = mb2;
258		*mb = mb2;
259		(*mb)->m_len = 0;
260		*bpos = mtod(*mb, caddr_t);
261	}
262	*a = *bpos;
263	(*mb)->m_len += s;
264	*bpos += s;
265}
266
267int
268nfsm_dissect_xx(void **a, int s, struct mbuf **md, caddr_t *dpos)
269{
270	int t1;
271	char *cp2;
272
273	t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos;
274	if (t1 >= s) {
275		*a = *dpos;
276		*dpos += s;
277		return 0;
278	}
279	t1 = nfsm_disct(md, dpos, s, t1, &cp2);
280	if (t1 != 0)
281		return t1;
282	*a = cp2;
283	return 0;
284}
285
286int
287nfsm_strsiz_xx(int *s, int m, u_int32_t **tl, struct mbuf **mb, caddr_t *bpos)
288{
289	int ret;
290
291	ret = nfsm_dissect_xx((void **)tl, NFSX_UNSIGNED, mb, bpos);
292	if (ret)
293		return ret;
294	*s = fxdr_unsigned(int32_t, **tl);
295	if (*s > m)
296		return EBADRPC;
297	return 0;
298}
299
300int
301nfsm_adv_xx(int s, u_int32_t **tl, struct mbuf **md, caddr_t *dpos)
302{
303	int t1;
304
305	t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos;
306	if (t1 > s) {
307		*dpos += s;
308		return 0;
309	}
310	t1 = nfs_adv(md, dpos, s, t1);
311	if (t1)
312		return t1;
313	return 0;
314}
315