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