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