1108441Ssimokawa/*- 2108441Ssimokawa * Copyright (c) 1989, 1993 3108441Ssimokawa * The Regents of the University of California. All rights reserved. 4108441Ssimokawa * 5108441Ssimokawa * This code is derived from software contributed to Berkeley by 6108441Ssimokawa * Rick Macklem at The University of Guelph. 7108441Ssimokawa * 8108441Ssimokawa * Redistribution and use in source and binary forms, with or without 9108441Ssimokawa * modification, are permitted provided that the following conditions 10108441Ssimokawa * are met: 11108441Ssimokawa * 1. Redistributions of source code must retain the above copyright 12108441Ssimokawa * notice, this list of conditions and the following disclaimer. 13108441Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright 14108441Ssimokawa * notice, this list of conditions and the following disclaimer in the 15108441Ssimokawa * documentation and/or other materials provided with the distribution. 16108441Ssimokawa * 4. Neither the name of the University nor the names of its contributors 17108441Ssimokawa * may be used to endorse or promote products derived from this software 18108441Ssimokawa * without specific prior written permission. 19108441Ssimokawa * 20108441Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21108441Ssimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22108441Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23108441Ssimokawa * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24108441Ssimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25108441Ssimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26108441Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27108441Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28108441Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29108441Ssimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30108441Ssimokawa * SUCH DAMAGE. 31108441Ssimokawa * 32108441Ssimokawa * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 33108441Ssimokawa */ 34108441Ssimokawa 35185996Ssbruno#include <sys/cdefs.h> 36146442Scharnier__FBSDID("$FreeBSD$"); 37146442Scharnier 38185996Ssbruno/* 39146442Scharnier * These functions support the macros and help fiddle mbuf chains for 40108441Ssimokawa * the nfs op functions. They do things like create the rpc header and 41108441Ssimokawa * copy data between mbuf chains and uio lists. 42146442Scharnier */ 43146442Scharnier 44108441Ssimokawa#include <sys/param.h> 45108441Ssimokawa#include <sys/systm.h> 46108441Ssimokawa#include <sys/kernel.h> 47185996Ssbruno#include <sys/bio.h> 48129760Sbrooks#include <sys/buf.h> 49108441Ssimokawa#include <sys/proc.h> 50108441Ssimokawa#include <sys/mount.h> 51120432Ssimokawa#include <sys/vnode.h> 52163712Simp#include <sys/namei.h> 53185996Ssbruno#include <sys/mbuf.h> 54185996Ssbruno#include <sys/socket.h> 55185996Ssbruno#include <sys/stat.h> 56185996Ssbruno#include <sys/malloc.h> 57185996Ssbruno#include <sys/module.h> 58185996Ssbruno#include <sys/sysent.h> 59185996Ssbruno#include <sys/syscall.h> 60185996Ssbruno#include <sys/sysctl.h> 61185996Ssbruno 62108441Ssimokawa#include <vm/vm.h> 63185996Ssbruno#include <vm/vm_object.h> 64108441Ssimokawa#include <vm/vm_extern.h> 65108441Ssimokawa 66108441Ssimokawa#include <nfs/nfsproto.h> 67108441Ssimokawa#include <nfsserver/nfs.h> 68108441Ssimokawa#include <nfs/xdr_subs.h> 69108441Ssimokawa#include <nfs/nfs_common.h> 70163712Simp 71108441Ssimokawa#include <netinet/in.h> 72182911Ssbruno 73182911Ssbrunoenum vtype nv3tov_type[8]= { 74163712Simp VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO 75108441Ssimokawa}; 76163712Simpnfstype nfsv3_type[9] = { 77109737Ssimokawa NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON 78108657Ssimokawa}; 79108441Ssimokawa 80108441Ssimokawastatic void *nfsm_dissect_xx_sub(int s, struct mbuf **md, caddr_t *dpos, 81109787Ssimokawa int how); 82185996Ssbruno 83182911SsbrunoSYSCTL_NODE(_vfs, OID_AUTO, nfs_common, CTLFLAG_RD, 0, "NFS common support"); 84182911Ssbruno 85118457Ssimokawastatic int nfs_realign_test; 86182911SsbrunoSYSCTL_INT(_vfs_nfs_common, OID_AUTO, realign_test, CTLFLAG_RD, 87114217Ssimokawa &nfs_realign_test, 0, "Number of realign tests done"); 88114217Ssimokawa 89182911Ssbrunostatic int nfs_realign_count; 90114217SsimokawaSYSCTL_INT(_vfs_nfs_common, OID_AUTO, realign_count, CTLFLAG_RD, 91182911Ssbruno &nfs_realign_count, 0, "Number of mbuf realignments done"); 92182911Ssbruno 93114217Ssimokawa/* 94185996Ssbruno * copies mbuf chain to the uio scatter/gather list 95185996Ssbruno */ 96182911Ssbrunoint 97182911Ssbrunonfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos) 98163712Simp{ 99137028Ssimokawa char *mbufcp, *uiocp; 100185996Ssbruno int xfer, left, len; 101185996Ssbruno struct mbuf *mp; 102185996Ssbruno long uiosiz, rem; 103108441Ssimokawa int error = 0; 104108441Ssimokawa 105129760Sbrooks mp = *mrep; 106129760Sbrooks mbufcp = *dpos; 107129760Sbrooks len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 108129760Sbrooks rem = nfsm_rndup(siz)-siz; 109129760Sbrooks while (siz > 0) { 110129760Sbrooks if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 111129760Sbrooks return (EFBIG); 112182911Ssbruno left = uiop->uio_iov->iov_len; 113182911Ssbruno uiocp = uiop->uio_iov->iov_base; 114108441Ssimokawa if (left > siz) 115109814Ssimokawa left = siz; 116182911Ssbruno uiosiz = left; 117108441Ssimokawa while (left > 0) { 118182911Ssbruno while (len == 0) { 119108441Ssimokawa mp = mp->m_next; 120108441Ssimokawa if (mp == NULL) 121108441Ssimokawa return (EBADRPC); 122129760Sbrooks mbufcp = mtod(mp, caddr_t); 123129760Sbrooks len = mp->m_len; 124129760Sbrooks } 125129760Sbrooks xfer = (left > len) ? len : left; 126129760Sbrooks#ifdef notdef 127129760Sbrooks /* Not Yet.. */ 128129760Sbrooks if (uiop->uio_iov->iov_op != NULL) 129129760Sbrooks (*(uiop->uio_iov->iov_op)) 130129760Sbrooks (mbufcp, uiocp, xfer); 131129760Sbrooks else 132129760Sbrooks#endif 133129760Sbrooks if (uiop->uio_segflg == UIO_SYSSPACE) 134129760Sbrooks bcopy(mbufcp, uiocp, xfer); 135129760Sbrooks else 136129760Sbrooks copyout(mbufcp, uiocp, xfer); 137129760Sbrooks left -= xfer; 138129760Sbrooks len -= xfer; 139129760Sbrooks mbufcp += xfer; 140129760Sbrooks uiocp += xfer; 141129760Sbrooks uiop->uio_offset += xfer; 142129760Sbrooks uiop->uio_resid -= xfer; 143129760Sbrooks } 144129760Sbrooks if (uiop->uio_iov->iov_len <= siz) { 145129760Sbrooks uiop->uio_iovcnt--; 146182911Ssbruno uiop->uio_iov++; 147182911Ssbruno } else { 148182911Ssbruno uiop->uio_iov->iov_base = 149182911Ssbruno (char *)uiop->uio_iov->iov_base + uiosiz; 150129760Sbrooks uiop->uio_iov->iov_len -= uiosiz; 151129760Sbrooks } 152129760Sbrooks siz -= uiosiz; 153129760Sbrooks } 154129760Sbrooks *dpos = mbufcp; 155228790Seadler *mrep = mp; 156129760Sbrooks if (rem > 0) { 157129760Sbrooks if (len < rem) 158129760Sbrooks error = nfs_adv(mrep, dpos, rem, len); 159182911Ssbruno else 160182911Ssbruno *dpos += rem; 161182911Ssbruno } 162129760Sbrooks return (error); 163182911Ssbruno} 164129760Sbrooks 165129760Sbrooks/* 166129760Sbrooks * Help break down an mbuf chain by setting the first siz bytes contiguous 167129760Sbrooks * pointed to by returned val. 168129760Sbrooks * This is used by the macros nfsm_dissect for tough 169129760Sbrooks * cases. (The macros use the vars. dpos and dpos2) 170129760Sbrooks */ 171129760Sbrooksvoid * 172108657Ssimokawanfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, int how) 173108441Ssimokawa{ 174108441Ssimokawa struct mbuf *mp, *mp2; 175109814Ssimokawa int siz2, xfer; 176109814Ssimokawa caddr_t ptr, npos = NULL; 177129760Sbrooks void *ret; 178176810Ssimokawa 179108441Ssimokawa mp = *mdp; 180108441Ssimokawa while (left == 0) { 181182911Ssbruno *mdp = mp = mp->m_next; 182182911Ssbruno if (mp == NULL) 183182911Ssbruno return (NULL); 184182911Ssbruno left = mp->m_len; 185109814Ssimokawa *dposp = mtod(mp, caddr_t); 186176810Ssimokawa } 187109814Ssimokawa if (left >= siz) { 188109814Ssimokawa ret = *dposp; 189129760Sbrooks *dposp += siz; 190129760Sbrooks } else if (mp->m_next == NULL) { 191176810Ssimokawa return (NULL); 192176810Ssimokawa } else if (siz > MHLEN) { 193176810Ssimokawa panic("nfs S too big"); 194110578Ssimokawa } else { 195129760Sbrooks mp2 = m_get(how, MT_DATA); 196176810Ssimokawa if (mp2 == NULL) 197176810Ssimokawa return (NULL); 198108441Ssimokawa mp2->m_len = siz; 199108441Ssimokawa mp2->m_next = mp->m_next; 200109814Ssimokawa mp->m_next = mp2; 201108441Ssimokawa mp->m_len -= left; 202108441Ssimokawa mp = mp2; 203108657Ssimokawa ptr = mtod(mp, caddr_t); 204146442Scharnier ret = ptr; 205108441Ssimokawa bcopy(*dposp, ptr, left); /* Copy what was left */ 206108441Ssimokawa siz2 = siz-left; 207108441Ssimokawa ptr += left; 208108441Ssimokawa mp2 = mp->m_next; 209108441Ssimokawa npos = mtod(mp2, caddr_t); 210182911Ssbruno /* Loop around copying up the siz2 bytes */ 211182911Ssbruno while (siz2 > 0) { 212108441Ssimokawa if (mp2 == NULL) 213114217Ssimokawa return (NULL); 214114217Ssimokawa xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 215114217Ssimokawa if (xfer > 0) { 216114217Ssimokawa bcopy(mtod(mp2, caddr_t), ptr, xfer); 217108441Ssimokawa mp2->m_data += xfer; 218108441Ssimokawa mp2->m_len -= xfer; 219108441Ssimokawa ptr += xfer; 220108441Ssimokawa siz2 -= xfer; 221146442Scharnier } 222108441Ssimokawa if (siz2 > 0) { 223108441Ssimokawa mp2 = mp2->m_next; 224108441Ssimokawa if (mp2 != NULL) 225108441Ssimokawa npos = mtod(mp2, caddr_t); 226113584Ssimokawa } 227113584Ssimokawa } 228108441Ssimokawa *mdp = mp2; 229108441Ssimokawa *dposp = mtod(mp2, caddr_t); 230146442Scharnier if (!nfsm_aligned(*dposp, u_int32_t)) { 231176810Ssimokawa bcopy(*dposp, npos, mp2->m_len); 232108441Ssimokawa mp2->m_data = npos; 233108441Ssimokawa *dposp = npos; 234182911Ssbruno } 235108441Ssimokawa } 236108441Ssimokawa return (ret); 237108441Ssimokawa} 238146442Scharnier 239108441Ssimokawa/* 240108441Ssimokawa * Advance the position in the mbuf chain. 241108441Ssimokawa */ 242108441Ssimokawaint 243108657Ssimokawanfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left) 244182911Ssbruno{ 245182911Ssbruno struct mbuf *m; 246182911Ssbruno int s; 247182911Ssbruno 248182911Ssbruno m = *mdp; 249182911Ssbruno s = left; 250182911Ssbruno while (s < offs) { 251182911Ssbruno offs -= s; 252182911Ssbruno m = m->m_next; 253182911Ssbruno if (m == NULL) 254182911Ssbruno return (EBADRPC); 255182911Ssbruno s = m->m_len; 256182911Ssbruno } 257182911Ssbruno *mdp = m; 258182911Ssbruno *dposp = mtod(m, caddr_t)+offs; 259108657Ssimokawa return (0); 260108441Ssimokawa} 261108441Ssimokawa 262108441Ssimokawavoid * 263108441Ssimokawanfsm_build_xx(int s, struct mbuf **mb, caddr_t *bpos) 264108441Ssimokawa{ 265182911Ssbruno struct mbuf *mb2; 266182911Ssbruno void *ret; 267108441Ssimokawa 268108441Ssimokawa if (s > M_TRAILINGSPACE(*mb)) { 269108441Ssimokawa mb2 = m_get(M_WAITOK, MT_DATA); 270108441Ssimokawa if (s > MLEN) 271108441Ssimokawa panic("build > MLEN"); 272108441Ssimokawa (*mb)->m_next = mb2; 273182911Ssbruno *mb = mb2; 274108441Ssimokawa (*mb)->m_len = 0; 275182911Ssbruno *bpos = mtod(*mb, caddr_t); 276108441Ssimokawa } 277108441Ssimokawa ret = *bpos; 278108441Ssimokawa (*mb)->m_len += s; 279108441Ssimokawa *bpos += s; 280108441Ssimokawa return (ret); 281114274Ssimokawa} 282182911Ssbruno 283114274Ssimokawavoid * 284108441Ssimokawanfsm_dissect_xx(int s, struct mbuf **md, caddr_t *dpos) 285108441Ssimokawa{ 286108657Ssimokawa 287182911Ssbruno return (nfsm_dissect_xx_sub(s, md, dpos, M_WAITOK)); 288114217Ssimokawa} 289114217Ssimokawa 290114217Ssimokawavoid * 291114217Ssimokawanfsm_dissect_xx_nonblock(int s, struct mbuf **md, caddr_t *dpos) 292182911Ssbruno{ 293182911Ssbruno 294114217Ssimokawa return (nfsm_dissect_xx_sub(s, md, dpos, M_NOWAIT)); 295114217Ssimokawa} 296114217Ssimokawa 297114217Ssimokawastatic void * 298114217Ssimokawanfsm_dissect_xx_sub(int s, struct mbuf **md, caddr_t *dpos, int how) 299114217Ssimokawa{ 300114274Ssimokawa int t1; 301182911Ssbruno char *cp2; 302114274Ssimokawa void *ret; 303114217Ssimokawa 304114217Ssimokawa t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos; 305114217Ssimokawa if (t1 >= s) { 306114217Ssimokawa ret = *dpos; 307114217Ssimokawa *dpos += s; 308114217Ssimokawa return (ret); 309114217Ssimokawa } 310114217Ssimokawa cp2 = nfsm_disct(md, dpos, s, t1, how); 311182911Ssbruno return (cp2); 312182911Ssbruno} 313114217Ssimokawa 314114217Ssimokawaint 315114217Ssimokawanfsm_strsiz_xx(int *s, int m, struct mbuf **mb, caddr_t *bpos) 316114217Ssimokawa{ 317114217Ssimokawa u_int32_t *tl; 318114217Ssimokawa 319114217Ssimokawa tl = nfsm_dissect_xx(NFSX_UNSIGNED, mb, bpos); 320114217Ssimokawa if (tl == NULL) 321114217Ssimokawa return (EBADRPC); 322114217Ssimokawa *s = fxdr_unsigned(int32_t, *tl); 323114217Ssimokawa if (*s > m) 324114274Ssimokawa return (EBADRPC); 325182911Ssbruno return (0); 326114274Ssimokawa} 327114217Ssimokawa 328114217Ssimokawaint 329114217Ssimokawanfsm_adv_xx(int s, struct mbuf **md, caddr_t *dpos) 330163712Simp{ 331108441Ssimokawa int t1; 332109814Ssimokawa 333109814Ssimokawa t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos; 334129760Sbrooks if (t1 >= s) { 335129760Sbrooks *dpos += s; 336108441Ssimokawa return (0); 337108441Ssimokawa } 338108441Ssimokawa t1 = nfs_adv(md, dpos, s, t1); 339182911Ssbruno if (t1) 340182911Ssbruno return (t1); 341182911Ssbruno return (0); 342182911Ssbruno} 343108441Ssimokawa 344109814Ssimokawa/* 345109814Ssimokawa * Check for badly aligned mbuf data and realign by copying the unaligned 346109814Ssimokawa * portion of the data into a new mbuf chain and freeing the portions of the 347108441Ssimokawa * old chain that were replaced. 348109814Ssimokawa * 349129760Sbrooks * We cannot simply realign the data within the existing mbuf chain because 350129760Sbrooks * the underlying buffers may contain other rpc commands and we cannot afford 351129760Sbrooks * to overwrite them. 352129760Sbrooks * 353163712Simp * We would prefer to avoid this situation entirely. The situation does not 354108441Ssimokawa * occur with NFS/UDP and is supposed to only occassionally occur with TCP. 355108441Ssimokawa * Use vfs.nfs_common.realign_count and realign_test to check this. 356108441Ssimokawa */ 357108441Ssimokawaint 358108441Ssimokawanfs_realign(struct mbuf **pm, int how) 359109814Ssimokawa{ 360108441Ssimokawa struct mbuf *m, *n; 361108441Ssimokawa int off; 362108441Ssimokawa 363108441Ssimokawa ++nfs_realign_test; 364109814Ssimokawa while ((m = *pm) != NULL) { 365108441Ssimokawa if (!nfsm_aligned(m->m_len, u_int32_t) || 366108441Ssimokawa !nfsm_aligned(mtod(m, intptr_t), u_int32_t)) { 367108657Ssimokawa /* 368163712Simp * NB: we can't depend on m_pkthdr.len to help us 369108441Ssimokawa * decide what to do here. May not be worth doing 370129760Sbrooks * the m_length calculation as m_copyback will 371116141Ssimokawa * expand the mbuf chain below as needed. 372129760Sbrooks */ 373108441Ssimokawa if (m_length(m, NULL) >= MINCLSIZE) { 374116141Ssimokawa /* NB: m_copyback handles space > MCLBYTES */ 375129760Sbrooks n = m_getcl(how, MT_DATA, 0); 376129760Sbrooks } else 377116141Ssimokawa n = m_get(how, MT_DATA); 378116141Ssimokawa if (n == NULL) 379116141Ssimokawa return (ENOMEM); 380116141Ssimokawa /* 381129760Sbrooks * Align the remainder of the mbuf chain. 382116141Ssimokawa */ 383116141Ssimokawa n->m_len = 0; 384116141Ssimokawa off = 0; 385116141Ssimokawa while (m != NULL) { 386129760Sbrooks m_copyback(n, off, m->m_len, mtod(m, caddr_t)); 387108441Ssimokawa off += m->m_len; 388108441Ssimokawa m = m->m_next; 389108657Ssimokawa } 390108441Ssimokawa m_freem(*pm); 391108441Ssimokawa *pm = n; 392108441Ssimokawa ++nfs_realign_count; 393109991Ssimokawa break; 394109814Ssimokawa } 395108441Ssimokawa pm = &m->m_next; 396182911Ssbruno } 397182911Ssbruno return (0); 398182911Ssbruno} 399182911Ssbruno 400108441Ssimokawastatic moduledata_t nfs_common_mod = { 401109814Ssimokawa "nfs_common", 402109814Ssimokawa NULL, 403108441Ssimokawa NULL 404108441Ssimokawa}; 405109814Ssimokawa 406109814SsimokawaDECLARE_MODULE(nfs_common, nfs_common_mod, SI_SUB_VFS, SI_ORDER_ANY); 407109814SsimokawaMODULE_VERSION(nfs_common, 1); 408109814Ssimokawa