The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs/nfs_common.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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/10.0/sys/nfs/nfs_common.c 248318 2013-03-15 10:21:18Z glebius $");
   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/module.h>
   58 #include <sys/sysent.h>
   59 #include <sys/syscall.h>
   60 #include <sys/sysctl.h>
   61 
   62 #include <vm/vm.h>
   63 #include <vm/vm_object.h>
   64 #include <vm/vm_extern.h>
   65 
   66 #include <nfs/nfsproto.h>
   67 #include <nfsserver/nfs.h>
   68 #include <nfs/xdr_subs.h>
   69 #include <nfs/nfs_common.h>
   70 
   71 #include <netinet/in.h>
   72 
   73 enum vtype nv3tov_type[8]= {
   74         VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
   75 };
   76 nfstype nfsv3_type[9] = {
   77         NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON
   78 };
   79 
   80 static void *nfsm_dissect_xx_sub(int s, struct mbuf **md, caddr_t *dpos,
   81     int how);
   82 
   83 SYSCTL_NODE(_vfs, OID_AUTO, nfs_common, CTLFLAG_RD, 0, "NFS common support");
   84 
   85 static int nfs_realign_test;
   86 SYSCTL_INT(_vfs_nfs_common, OID_AUTO, realign_test, CTLFLAG_RD,
   87     &nfs_realign_test, 0, "Number of realign tests done");
   88 
   89 static int nfs_realign_count;
   90 SYSCTL_INT(_vfs_nfs_common, OID_AUTO, realign_count, CTLFLAG_RD,
   91     &nfs_realign_count, 0, "Number of mbuf realignments done");
   92 
   93 /*
   94  * copies mbuf chain to the uio scatter/gather list
   95  */
   96 int
   97 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
   98 {
   99         char *mbufcp, *uiocp;
  100         int xfer, left, len;
  101         struct mbuf *mp;
  102         long uiosiz, rem;
  103         int error = 0;
  104 
  105         mp = *mrep;
  106         mbufcp = *dpos;
  107         len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
  108         rem = nfsm_rndup(siz)-siz;
  109         while (siz > 0) {
  110                 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
  111                         return (EFBIG);
  112                 left = uiop->uio_iov->iov_len;
  113                 uiocp = uiop->uio_iov->iov_base;
  114                 if (left > siz)
  115                         left = siz;
  116                 uiosiz = left;
  117                 while (left > 0) {
  118                         while (len == 0) {
  119                                 mp = mp->m_next;
  120                                 if (mp == NULL)
  121                                         return (EBADRPC);
  122                                 mbufcp = mtod(mp, caddr_t);
  123                                 len = mp->m_len;
  124                         }
  125                         xfer = (left > len) ? len : left;
  126 #ifdef notdef
  127                         /* Not Yet.. */
  128                         if (uiop->uio_iov->iov_op != NULL)
  129                                 (*(uiop->uio_iov->iov_op))
  130                                 (mbufcp, uiocp, xfer);
  131                         else
  132 #endif
  133                         if (uiop->uio_segflg == UIO_SYSSPACE)
  134                                 bcopy(mbufcp, uiocp, xfer);
  135                         else
  136                                 copyout(mbufcp, uiocp, xfer);
  137                         left -= xfer;
  138                         len -= xfer;
  139                         mbufcp += xfer;
  140                         uiocp += xfer;
  141                         uiop->uio_offset += xfer;
  142                         uiop->uio_resid -= xfer;
  143                 }
  144                 if (uiop->uio_iov->iov_len <= siz) {
  145                         uiop->uio_iovcnt--;
  146                         uiop->uio_iov++;
  147                 } else {
  148                         uiop->uio_iov->iov_base =
  149                             (char *)uiop->uio_iov->iov_base + uiosiz;
  150                         uiop->uio_iov->iov_len -= uiosiz;
  151                 }
  152                 siz -= uiosiz;
  153         }
  154         *dpos = mbufcp;
  155         *mrep = mp;
  156         if (rem > 0) {
  157                 if (len < rem)
  158                         error = nfs_adv(mrep, dpos, rem, len);
  159                 else
  160                         *dpos += rem;
  161         }
  162         return (error);
  163 }
  164 
  165 /*
  166  * Help break down an mbuf chain by setting the first siz bytes contiguous
  167  * pointed to by returned val.
  168  * This is used by the macros nfsm_dissect for tough
  169  * cases. (The macros use the vars. dpos and dpos2)
  170  */
  171 void *
  172 nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, int how)
  173 {
  174         struct mbuf *mp, *mp2;
  175         int siz2, xfer;
  176         caddr_t ptr, npos = NULL;
  177         void *ret;
  178 
  179         mp = *mdp;
  180         while (left == 0) {
  181                 *mdp = mp = mp->m_next;
  182                 if (mp == NULL)
  183                         return (NULL);
  184                 left = mp->m_len;
  185                 *dposp = mtod(mp, caddr_t);
  186         }
  187         if (left >= siz) {
  188                 ret = *dposp;
  189                 *dposp += siz;
  190         } else if (mp->m_next == NULL) {
  191                 return (NULL);
  192         } else if (siz > MHLEN) {
  193                 panic("nfs S too big");
  194         } else {
  195                 mp2 = m_get(how, MT_DATA);
  196                 if (mp2 == NULL)
  197                         return (NULL);
  198                 mp2->m_len = siz;
  199                 mp2->m_next = mp->m_next;
  200                 mp->m_next = mp2;
  201                 mp->m_len -= left;
  202                 mp = mp2;
  203                 ptr = mtod(mp, caddr_t);
  204                 ret = ptr;
  205                 bcopy(*dposp, ptr, left);               /* Copy what was left */
  206                 siz2 = siz-left;
  207                 ptr += left;
  208                 mp2 = mp->m_next;
  209                 npos = mtod(mp2, caddr_t);
  210                 /* Loop around copying up the siz2 bytes */
  211                 while (siz2 > 0) {
  212                         if (mp2 == NULL)
  213                                 return (NULL);
  214                         xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
  215                         if (xfer > 0) {
  216                                 bcopy(mtod(mp2, caddr_t), ptr, xfer);
  217                                 mp2->m_data += xfer;
  218                                 mp2->m_len -= xfer;
  219                                 ptr += xfer;
  220                                 siz2 -= xfer;
  221                         }
  222                         if (siz2 > 0) {
  223                                 mp2 = mp2->m_next;
  224                                 if (mp2 != NULL)
  225                                         npos = mtod(mp2, caddr_t);
  226                         }
  227                 }
  228                 *mdp = mp2;
  229                 *dposp = mtod(mp2, caddr_t);
  230                 if (!nfsm_aligned(*dposp, u_int32_t)) {
  231                         bcopy(*dposp, npos, mp2->m_len);
  232                         mp2->m_data = npos;
  233                         *dposp = npos;
  234                 }
  235         }
  236         return (ret);
  237 }
  238 
  239 /*
  240  * Advance the position in the mbuf chain.
  241  */
  242 int
  243 nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
  244 {
  245         struct mbuf *m;
  246         int s;
  247 
  248         m = *mdp;
  249         s = left;
  250         while (s < offs) {
  251                 offs -= s;
  252                 m = m->m_next;
  253                 if (m == NULL)
  254                         return (EBADRPC);
  255                 s = m->m_len;
  256         }
  257         *mdp = m;
  258         *dposp = mtod(m, caddr_t)+offs;
  259         return (0);
  260 }
  261 
  262 void *
  263 nfsm_build_xx(int s, struct mbuf **mb, caddr_t *bpos)
  264 {
  265         struct mbuf *mb2;
  266         void *ret;
  267 
  268         if (s > M_TRAILINGSPACE(*mb)) {
  269                 mb2 = m_get(M_WAITOK, MT_DATA);
  270                 if (s > MLEN)
  271                         panic("build > MLEN");
  272                 (*mb)->m_next = mb2;
  273                 *mb = mb2;
  274                 (*mb)->m_len = 0;
  275                 *bpos = mtod(*mb, caddr_t);
  276         }
  277         ret = *bpos;
  278         (*mb)->m_len += s;
  279         *bpos += s;
  280         return (ret);
  281 }
  282 
  283 void *
  284 nfsm_dissect_xx(int s, struct mbuf **md, caddr_t *dpos)
  285 {
  286 
  287         return (nfsm_dissect_xx_sub(s, md, dpos, M_WAITOK));
  288 }
  289 
  290 void *
  291 nfsm_dissect_xx_nonblock(int s, struct mbuf **md, caddr_t *dpos)
  292 {
  293 
  294         return (nfsm_dissect_xx_sub(s, md, dpos, M_NOWAIT));
  295 }
  296 
  297 static void *
  298 nfsm_dissect_xx_sub(int s, struct mbuf **md, caddr_t *dpos, int how)
  299 {
  300         int t1;
  301         char *cp2;
  302         void *ret;
  303 
  304         t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos;
  305         if (t1 >= s) {
  306                 ret = *dpos;
  307                 *dpos += s;
  308                 return (ret);
  309         }
  310         cp2 = nfsm_disct(md, dpos, s, t1, how);
  311         return (cp2);
  312 }
  313 
  314 int
  315 nfsm_strsiz_xx(int *s, int m, struct mbuf **mb, caddr_t *bpos)
  316 {
  317         u_int32_t *tl;
  318 
  319         tl = nfsm_dissect_xx(NFSX_UNSIGNED, mb, bpos);
  320         if (tl == NULL)
  321                 return (EBADRPC);
  322         *s = fxdr_unsigned(int32_t, *tl);
  323         if (*s > m)
  324                 return (EBADRPC);
  325         return (0);
  326 }
  327 
  328 int
  329 nfsm_adv_xx(int s, struct mbuf **md, caddr_t *dpos)
  330 {
  331         int t1;
  332 
  333         t1 = mtod(*md, caddr_t) + (*md)->m_len - *dpos;
  334         if (t1 >= s) {
  335                 *dpos += s;
  336                 return (0);
  337         }
  338         t1 = nfs_adv(md, dpos, s, t1);
  339         if (t1)
  340                 return (t1);
  341         return (0);
  342 }
  343 
  344 /*
  345  * Check for badly aligned mbuf data and realign by copying the unaligned
  346  * portion of the data into a new mbuf chain and freeing the portions of the
  347  * old chain that were replaced.
  348  *
  349  * We cannot simply realign the data within the existing mbuf chain because
  350  * the underlying buffers may contain other rpc commands and we cannot afford
  351  * to overwrite them.
  352  *
  353  * We would prefer to avoid this situation entirely.  The situation does not
  354  * occur with NFS/UDP and is supposed to only occassionally occur with TCP.
  355  * Use vfs.nfs_common.realign_count and realign_test to check this.
  356  */
  357 int
  358 nfs_realign(struct mbuf **pm, int how)
  359 {
  360         struct mbuf *m, *n;
  361         int off;
  362 
  363         ++nfs_realign_test;
  364         while ((m = *pm) != NULL) {
  365                 if (!nfsm_aligned(m->m_len, u_int32_t) ||
  366                     !nfsm_aligned(mtod(m, intptr_t), u_int32_t)) {
  367                         /*
  368                          * NB: we can't depend on m_pkthdr.len to help us
  369                          * decide what to do here.  May not be worth doing
  370                          * the m_length calculation as m_copyback will
  371                          * expand the mbuf chain below as needed.
  372                          */
  373                         if (m_length(m, NULL) >= MINCLSIZE) {
  374                                 /* NB: m_copyback handles space > MCLBYTES */
  375                                 n = m_getcl(how, MT_DATA, 0);
  376                         } else
  377                                 n = m_get(how, MT_DATA);
  378                         if (n == NULL)
  379                                 return (ENOMEM);
  380                         /*
  381                          * Align the remainder of the mbuf chain.
  382                          */
  383                         n->m_len = 0;
  384                         off = 0;
  385                         while (m != NULL) {
  386                                 m_copyback(n, off, m->m_len, mtod(m, caddr_t));
  387                                 off += m->m_len;
  388                                 m = m->m_next;
  389                         }
  390                         m_freem(*pm);
  391                         *pm = n;
  392                         ++nfs_realign_count;
  393                         break;
  394                 }
  395                 pm = &m->m_next;
  396         }
  397         return (0);
  398 }
  399 
  400 static moduledata_t nfs_common_mod = {
  401         "nfs_common",
  402         NULL,
  403         NULL
  404 };
  405 
  406 DECLARE_MODULE(nfs_common, nfs_common_mod, SI_SUB_VFS, SI_ORDER_ANY);
  407 MODULE_VERSION(nfs_common, 1);

Cache object: d58dd17dab2b7857c47d59dee52283ff


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.