nfs_common.c revision 104908
176105Sphantom/*
276105Sphantom * Copyright (c) 1989, 1993
376105Sphantom *	The Regents of the University of California.  All rights reserved.
476105Sphantom *
576105Sphantom * This code is derived from software contributed to Berkeley by
676105Sphantom * Rick Macklem at The University of Guelph.
776105Sphantom *
876105Sphantom * Redistribution and use in source and binary forms, with or without
976105Sphantom * modification, are permitted provided that the following conditions
1076105Sphantom * are met:
1176105Sphantom * 1. Redistributions of source code must retain the above copyright
1276105Sphantom *    notice, this list of conditions and the following disclaimer.
1376105Sphantom * 2. Redistributions in binary form must reproduce the above copyright
1476105Sphantom *    notice, this list of conditions and the following disclaimer in the
1576105Sphantom *    documentation and/or other materials provided with the distribution.
1676105Sphantom * 3. All advertising materials mentioning features or use of this software
1776105Sphantom *    must display the following acknowledgement:
1876105Sphantom *	This product includes software developed by the University of
1976105Sphantom *	California, Berkeley and its contributors.
2076105Sphantom * 4. Neither the name of the University nor the names of its contributors
2176105Sphantom *    may be used to endorse or promote products derived from this software
2276105Sphantom *    without specific prior written permission.
2376105Sphantom *
2476105Sphantom * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2576105Sphantom * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2676105Sphantom * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2776105Sphantom * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2876105Sphantom * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2976105Sphantom * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3076105Sphantom * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3176105Sphantom * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3276105Sphantom * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3376105Sphantom * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3476105Sphantom * SUCH DAMAGE.
3576105Sphantom *
3676105Sphantom *	@(#)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 104908 2002-10-11 14:58:34Z mike $");
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
68#include <nfs/rpcv2.h>
69#include <nfs/nfsproto.h>
70#include <nfsserver/nfs.h>
71#include <nfs/xdr_subs.h>
72#include <nfs/nfs_common.h>
73
74#include <netinet/in.h>
75
76enum vtype nv3tov_type[8]= {
77	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
78};
79nfstype nfsv3_type[9] = {
80	NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON
81};
82
83u_quad_t
84nfs_curusec(void)
85{
86	struct timeval tv;
87
88	getmicrotime(&tv);
89	return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec);
90}
91
92/*
93 * copies mbuf chain to the uio scatter/gather list
94 */
95int
96nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
97{
98	char *mbufcp, *uiocp;
99	int xfer, left, len;
100	struct mbuf *mp;
101	long uiosiz, rem;
102	int error = 0;
103
104	mp = *mrep;
105	mbufcp = *dpos;
106	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
107	rem = nfsm_rndup(siz)-siz;
108	while (siz > 0) {
109		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
110			return (EFBIG);
111		left = uiop->uio_iov->iov_len;
112		uiocp = uiop->uio_iov->iov_base;
113		if (left > siz)
114			left = siz;
115		uiosiz = left;
116		while (left > 0) {
117			while (len == 0) {
118				mp = mp->m_next;
119				if (mp == NULL)
120					return (EBADRPC);
121				mbufcp = mtod(mp, caddr_t);
122				len = mp->m_len;
123			}
124			xfer = (left > len) ? len : left;
125#ifdef notdef
126			/* Not Yet.. */
127			if (uiop->uio_iov->iov_op != NULL)
128				(*(uiop->uio_iov->iov_op))
129				(mbufcp, uiocp, xfer);
130			else
131#endif
132			if (uiop->uio_segflg == UIO_SYSSPACE)
133				bcopy(mbufcp, uiocp, xfer);
134			else
135				copyout(mbufcp, uiocp, xfer);
136			left -= xfer;
137			len -= xfer;
138			mbufcp += xfer;
139			uiocp += xfer;
140			uiop->uio_offset += xfer;
141			uiop->uio_resid -= xfer;
142		}
143		if (uiop->uio_iov->iov_len <= siz) {
144			uiop->uio_iovcnt--;
145			uiop->uio_iov++;
146		} else {
147			uiop->uio_iov->iov_base =
148			    (char *)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 for tough
168 * cases. (The macros use the vars. dpos and dpos2)
169 */
170void *
171nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left)
172{
173	struct mbuf *mp, *mp2;
174	int siz2, xfer;
175	caddr_t ptr;
176	void *ret;
177
178	mp = *mdp;
179	while (left == 0) {
180		*mdp = mp = mp->m_next;
181		if (mp == NULL)
182			return NULL;
183		left = mp->m_len;
184		*dposp = mtod(mp, caddr_t);
185	}
186	if (left >= siz) {
187		ret = *dposp;
188		*dposp += siz;
189	} else if (mp->m_next == NULL) {
190		return NULL;
191	} else if (siz > MHLEN) {
192		panic("nfs S too big");
193	} else {
194		MGET(mp2, M_TRYWAIT, MT_DATA);
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	int t1;
275	char *cp2;
276	void *ret;
277
278	t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos;
279	if (t1 >= s) {
280		ret = *dpos;
281		*dpos += s;
282		return ret;
283	}
284	cp2 = nfsm_disct(md, dpos, s, t1);
285	return cp2;
286}
287
288int
289nfsm_strsiz_xx(int *s, int m, struct mbuf **mb, caddr_t *bpos)
290{
291	u_int32_t *tl;
292
293	tl = nfsm_dissect_xx(NFSX_UNSIGNED, mb, bpos);
294	if (tl == NULL)
295		return EBADRPC;
296	*s = fxdr_unsigned(int32_t, *tl);
297	if (*s > m)
298		return EBADRPC;
299	return 0;
300}
301
302int
303nfsm_adv_xx(int s, struct mbuf **md, caddr_t *dpos)
304{
305	int t1;
306
307	t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos;
308	if (t1 >= s) {
309		*dpos += s;
310		return 0;
311	}
312	t1 = nfs_adv(md, dpos, s, t1);
313	if (t1)
314		return t1;
315	return 0;
316}
317