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$");
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, int how);
80
81 u_quad_t
82 nfs_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 */
93 int
94 nfsm_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 */
168 void *
169 nfsm_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, npos = NULL;
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_len = siz;
196 mp2->m_next = mp->m_next;
197 mp->m_next = mp2;
198 mp->m_len -= left;
199 mp = mp2;
200 ptr = mtod(mp, caddr_t);
201 ret = ptr;
202 bcopy(*dposp, ptr, left); /* Copy what was left */
203 siz2 = siz-left;
204 ptr += left;
205 mp2 = mp->m_next;
206 npos = mtod(mp2, caddr_t);
207 /* Loop around copying up the siz2 bytes */
208 while (siz2 > 0) {
209 if (mp2 == NULL)
210 return NULL;
211 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
212 if (xfer > 0) {
213 bcopy(mtod(mp2, caddr_t), ptr, xfer);
214 mp2->m_data += xfer;
215 mp2->m_len -= xfer;
216 ptr += xfer;
217 siz2 -= xfer;
218 }
219 if (siz2 > 0) {
220 mp2 = mp2->m_next;
221 if (mp2 != NULL)
222 npos = mtod(mp2, caddr_t);
223 }
224 }
225 *mdp = mp2;
226 *dposp = mtod(mp2, caddr_t);
227 if (!nfsm_aligned(*dposp, u_int32_t)) {
228 bcopy(*dposp, npos, mp2->m_len);
229 mp2->m_data = npos;
230 *dposp = npos;
231 }
232 }
233 return ret;
234 }
235
236 /*
237 * Advance the position in the mbuf chain.
238 */
239 int
240 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
241 {
242 struct mbuf *m;
243 int s;
244
245 m = *mdp;
246 s = left;
247 while (s < offs) {
248 offs -= s;
249 m = m->m_next;
250 if (m == NULL)
251 return (EBADRPC);
252 s = m->m_len;
253 }
254 *mdp = m;
255 *dposp = mtod(m, caddr_t)+offs;
256 return (0);
257 }
258
259 void *
260 nfsm_build_xx(int s, struct mbuf **mb, caddr_t *bpos)
261 {
262 struct mbuf *mb2;
263 void *ret;
264
265 if (s > M_TRAILINGSPACE(*mb)) {
266 MGET(mb2, M_TRYWAIT, MT_DATA);
267 if (s > MLEN)
268 panic("build > MLEN");
269 (*mb)->m_next = mb2;
270 *mb = mb2;
271 (*mb)->m_len = 0;
272 *bpos = mtod(*mb, caddr_t);
273 }
274 ret = *bpos;
275 (*mb)->m_len += s;
276 *bpos += s;
277 return ret;
278 }
279
280 void *
281 nfsm_dissect_xx(int s, struct mbuf **md, caddr_t *dpos)
282 {
283 return nfsm_dissect_xx_sub(s, md, dpos, M_TRYWAIT);
284 }
285
286 void *
287 nfsm_dissect_xx_nonblock(int s, struct mbuf **md, caddr_t *dpos)
288 {
289 return nfsm_dissect_xx_sub(s, md, dpos, M_DONTWAIT);
290 }
291
292 static void *
293 nfsm_dissect_xx_sub(int s, struct mbuf **md, caddr_t *dpos, int how)
294 {
295 int t1;
296 char *cp2;
297 void *ret;
298
299 t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos;
300 if (t1 >= s) {
301 ret = *dpos;
302 *dpos += s;
303 return ret;
304 }
305 cp2 = nfsm_disct(md, dpos, s, t1, how);
306 return cp2;
307 }
308
309 int
310 nfsm_strsiz_xx(int *s, int m, struct mbuf **mb, caddr_t *bpos)
311 {
312 u_int32_t *tl;
313
314 tl = nfsm_dissect_xx(NFSX_UNSIGNED, mb, bpos);
315 if (tl == NULL)
316 return EBADRPC;
317 *s = fxdr_unsigned(int32_t, *tl);
318 if (*s > m)
319 return EBADRPC;
320 return 0;
321 }
322
323 int
324 nfsm_adv_xx(int s, struct mbuf **md, caddr_t *dpos)
325 {
326 int t1;
327
328 t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos;
329 if (t1 >= s) {
330 *dpos += s;
331 return 0;
332 }
333 t1 = nfs_adv(md, dpos, s, t1);
334 if (t1)
335 return t1;
336 return 0;
337 }
Cache object: 8bd053d6f0dc1c90a30b6b1a3e38f173
|