FreeBSD/Linux Kernel Cross Reference
sys/nfs/nfs_common.c
1 /*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 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: releng/7.4/sys/nfs/nfs_common.c 205917 2010-03-30 19:52:45Z marius $");
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
72 enum vtype nv3tov_type[8]= {
73 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
74 };
75 nfstype nfsv3_type[9] = {
76 NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON
77 };
78
79 static void *nfsm_dissect_xx_sub(int s, struct mbuf **md, caddr_t *dpos,
80 int how);
81
82 u_quad_t
83 nfs_curusec(void)
84 {
85 struct timeval tv;
86
87 getmicrotime(&tv);
88 return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec);
89 }
90
91 /*
92 * copies mbuf chain to the uio scatter/gather list
93 */
94 int
95 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
96 {
97 char *mbufcp, *uiocp;
98 int xfer, left, len;
99 struct mbuf *mp;
100 long uiosiz, rem;
101 int error = 0;
102
103 mp = *mrep;
104 mbufcp = *dpos;
105 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
106 rem = nfsm_rndup(siz)-siz;
107 while (siz > 0) {
108 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
109 return (EFBIG);
110 left = uiop->uio_iov->iov_len;
111 uiocp = uiop->uio_iov->iov_base;
112 if (left > siz)
113 left = siz;
114 uiosiz = left;
115 while (left > 0) {
116 while (len == 0) {
117 mp = mp->m_next;
118 if (mp == NULL)
119 return (EBADRPC);
120 mbufcp = mtod(mp, caddr_t);
121 len = mp->m_len;
122 }
123 xfer = (left > len) ? len : left;
124 #ifdef notdef
125 /* Not Yet.. */
126 if (uiop->uio_iov->iov_op != NULL)
127 (*(uiop->uio_iov->iov_op))
128 (mbufcp, uiocp, xfer);
129 else
130 #endif
131 if (uiop->uio_segflg == UIO_SYSSPACE)
132 bcopy(mbufcp, uiocp, xfer);
133 else
134 copyout(mbufcp, uiocp, xfer);
135 left -= xfer;
136 len -= xfer;
137 mbufcp += xfer;
138 uiocp += xfer;
139 uiop->uio_offset += xfer;
140 uiop->uio_resid -= xfer;
141 }
142 if (uiop->uio_iov->iov_len <= siz) {
143 uiop->uio_iovcnt--;
144 uiop->uio_iov++;
145 } else {
146 uiop->uio_iov->iov_base =
147 (char *)uiop->uio_iov->iov_base + uiosiz;
148 uiop->uio_iov->iov_len -= uiosiz;
149 }
150 siz -= uiosiz;
151 }
152 *dpos = mbufcp;
153 *mrep = mp;
154 if (rem > 0) {
155 if (len < rem)
156 error = nfs_adv(mrep, dpos, rem, len);
157 else
158 *dpos += rem;
159 }
160 return (error);
161 }
162
163 /*
164 * Help break down an mbuf chain by setting the first siz bytes contiguous
165 * pointed to by returned val.
166 * This is used by the macros nfsm_dissect for tough
167 * cases. (The macros use the vars. dpos and dpos2)
168 */
169 void *
170 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, int how)
171 {
172 struct mbuf *mp, *mp2;
173 int siz2, xfer;
174 caddr_t ptr, npos = NULL;
175 void *ret;
176
177 mp = *mdp;
178 while (left == 0) {
179 *mdp = mp = mp->m_next;
180 if (mp == NULL)
181 return (NULL);
182 left = mp->m_len;
183 *dposp = mtod(mp, caddr_t);
184 }
185 if (left >= siz) {
186 ret = *dposp;
187 *dposp += siz;
188 } else if (mp->m_next == NULL) {
189 return (NULL);
190 } else if (siz > MHLEN) {
191 panic("nfs S too big");
192 } else {
193 MGET(mp2, how, MT_DATA);
194 if (mp2 == NULL)
195 return (NULL);
196 mp2->m_len = siz;
197 mp2->m_next = mp->m_next;
198 mp->m_next = mp2;
199 mp->m_len -= left;
200 mp = mp2;
201 ptr = mtod(mp, caddr_t);
202 ret = ptr;
203 bcopy(*dposp, ptr, left); /* Copy what was left */
204 siz2 = siz-left;
205 ptr += left;
206 mp2 = mp->m_next;
207 npos = mtod(mp2, caddr_t);
208 /* Loop around copying up the siz2 bytes */
209 while (siz2 > 0) {
210 if (mp2 == NULL)
211 return (NULL);
212 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
213 if (xfer > 0) {
214 bcopy(mtod(mp2, caddr_t), ptr, xfer);
215 mp2->m_data += xfer;
216 mp2->m_len -= xfer;
217 ptr += xfer;
218 siz2 -= xfer;
219 }
220 if (siz2 > 0) {
221 mp2 = mp2->m_next;
222 if (mp2 != NULL)
223 npos = mtod(mp2, caddr_t);
224 }
225 }
226 *mdp = mp2;
227 *dposp = mtod(mp2, caddr_t);
228 if (!nfsm_aligned(*dposp, u_int32_t)) {
229 bcopy(*dposp, npos, mp2->m_len);
230 mp2->m_data = npos;
231 *dposp = npos;
232 }
233 }
234 return (ret);
235 }
236
237 /*
238 * Advance the position in the mbuf chain.
239 */
240 int
241 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
242 {
243 struct mbuf *m;
244 int s;
245
246 m = *mdp;
247 s = left;
248 while (s < offs) {
249 offs -= s;
250 m = m->m_next;
251 if (m == NULL)
252 return (EBADRPC);
253 s = m->m_len;
254 }
255 *mdp = m;
256 *dposp = mtod(m, caddr_t)+offs;
257 return (0);
258 }
259
260 void *
261 nfsm_build_xx(int s, struct mbuf **mb, caddr_t *bpos)
262 {
263 struct mbuf *mb2;
264 void *ret;
265
266 if (s > M_TRAILINGSPACE(*mb)) {
267 MGET(mb2, M_TRYWAIT, MT_DATA);
268 if (s > MLEN)
269 panic("build > MLEN");
270 (*mb)->m_next = mb2;
271 *mb = mb2;
272 (*mb)->m_len = 0;
273 *bpos = mtod(*mb, caddr_t);
274 }
275 ret = *bpos;
276 (*mb)->m_len += s;
277 *bpos += s;
278 return (ret);
279 }
280
281 void *
282 nfsm_dissect_xx(int s, struct mbuf **md, caddr_t *dpos)
283 {
284
285 return (nfsm_dissect_xx_sub(s, md, dpos, M_TRYWAIT));
286 }
287
288 void *
289 nfsm_dissect_xx_nonblock(int s, struct mbuf **md, caddr_t *dpos)
290 {
291
292 return (nfsm_dissect_xx_sub(s, md, dpos, M_DONTWAIT));
293 }
294
295 static void *
296 nfsm_dissect_xx_sub(int s, struct mbuf **md, caddr_t *dpos, int how)
297 {
298 int t1;
299 char *cp2;
300 void *ret;
301
302 t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos;
303 if (t1 >= s) {
304 ret = *dpos;
305 *dpos += s;
306 return (ret);
307 }
308 cp2 = nfsm_disct(md, dpos, s, t1, how);
309 return (cp2);
310 }
311
312 int
313 nfsm_strsiz_xx(int *s, int m, struct mbuf **mb, caddr_t *bpos)
314 {
315 u_int32_t *tl;
316
317 tl = nfsm_dissect_xx(NFSX_UNSIGNED, mb, bpos);
318 if (tl == NULL)
319 return (EBADRPC);
320 *s = fxdr_unsigned(int32_t, *tl);
321 if (*s > m)
322 return (EBADRPC);
323 return (0);
324 }
325
326 int
327 nfsm_adv_xx(int s, struct mbuf **md, caddr_t *dpos)
328 {
329 int t1;
330
331 t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos;
332 if (t1 >= s) {
333 *dpos += s;
334 return (0);
335 }
336 t1 = nfs_adv(md, dpos, s, t1);
337 if (t1)
338 return (t1);
339 return (0);
340 }
Cache object: 160517c12d5bac509dab6fa89b47b1f0
|