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/compat/linux/linux.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) 2015 Dmitry Chagin
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <opt_inet6.h>
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/conf.h>
   35 #include <sys/ctype.h>
   36 #include <sys/jail.h>
   37 #include <sys/lock.h>
   38 #include <sys/malloc.h>
   39 #include <sys/signalvar.h>
   40 #include <sys/socket.h>
   41 #include <sys/socketvar.h>
   42 
   43 #include <net/if.h>
   44 #include <net/if_var.h>
   45 #include <net/if_dl.h>
   46 #include <net/if_types.h>
   47 
   48 #include <sys/un.h>
   49 #include <netinet/in.h>
   50 
   51 #include <compat/linux/linux.h>
   52 #include <compat/linux/linux_common.h>
   53 #include <compat/linux/linux_util.h>
   54 
   55 struct futex_list futex_list;
   56 struct mtx futex_mtx;                   /* protects the futex list */
   57 
   58 CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
   59 
   60 static int bsd_to_linux_sigtbl[LINUX_SIGTBLSZ] = {
   61         LINUX_SIGHUP,   /* SIGHUP */
   62         LINUX_SIGINT,   /* SIGINT */
   63         LINUX_SIGQUIT,  /* SIGQUIT */
   64         LINUX_SIGILL,   /* SIGILL */
   65         LINUX_SIGTRAP,  /* SIGTRAP */
   66         LINUX_SIGABRT,  /* SIGABRT */
   67         0,              /* SIGEMT */
   68         LINUX_SIGFPE,   /* SIGFPE */
   69         LINUX_SIGKILL,  /* SIGKILL */
   70         LINUX_SIGBUS,   /* SIGBUS */
   71         LINUX_SIGSEGV,  /* SIGSEGV */
   72         LINUX_SIGSYS,   /* SIGSYS */
   73         LINUX_SIGPIPE,  /* SIGPIPE */
   74         LINUX_SIGALRM,  /* SIGALRM */
   75         LINUX_SIGTERM,  /* SIGTERM */
   76         LINUX_SIGURG,   /* SIGURG */
   77         LINUX_SIGSTOP,  /* SIGSTOP */
   78         LINUX_SIGTSTP,  /* SIGTSTP */
   79         LINUX_SIGCONT,  /* SIGCONT */
   80         LINUX_SIGCHLD,  /* SIGCHLD */
   81         LINUX_SIGTTIN,  /* SIGTTIN */
   82         LINUX_SIGTTOU,  /* SIGTTOU */
   83         LINUX_SIGIO,    /* SIGIO */
   84         LINUX_SIGXCPU,  /* SIGXCPU */
   85         LINUX_SIGXFSZ,  /* SIGXFSZ */
   86         LINUX_SIGVTALRM,/* SIGVTALRM */
   87         LINUX_SIGPROF,  /* SIGPROF */
   88         LINUX_SIGWINCH, /* SIGWINCH */
   89         0,              /* SIGINFO */
   90         LINUX_SIGUSR1,  /* SIGUSR1 */
   91         LINUX_SIGUSR2   /* SIGUSR2 */
   92 };
   93 
   94 static int linux_to_bsd_sigtbl[LINUX_SIGTBLSZ] = {
   95         SIGHUP,         /* LINUX_SIGHUP */
   96         SIGINT,         /* LINUX_SIGINT */
   97         SIGQUIT,        /* LINUX_SIGQUIT */
   98         SIGILL,         /* LINUX_SIGILL */
   99         SIGTRAP,        /* LINUX_SIGTRAP */
  100         SIGABRT,        /* LINUX_SIGABRT */
  101         SIGBUS,         /* LINUX_SIGBUS */
  102         SIGFPE,         /* LINUX_SIGFPE */
  103         SIGKILL,        /* LINUX_SIGKILL */
  104         SIGUSR1,        /* LINUX_SIGUSR1 */
  105         SIGSEGV,        /* LINUX_SIGSEGV */
  106         SIGUSR2,        /* LINUX_SIGUSR2 */
  107         SIGPIPE,        /* LINUX_SIGPIPE */
  108         SIGALRM,        /* LINUX_SIGALRM */
  109         SIGTERM,        /* LINUX_SIGTERM */
  110         SIGBUS,         /* LINUX_SIGSTKFLT */
  111         SIGCHLD,        /* LINUX_SIGCHLD */
  112         SIGCONT,        /* LINUX_SIGCONT */
  113         SIGSTOP,        /* LINUX_SIGSTOP */
  114         SIGTSTP,        /* LINUX_SIGTSTP */
  115         SIGTTIN,        /* LINUX_SIGTTIN */
  116         SIGTTOU,        /* LINUX_SIGTTOU */
  117         SIGURG,         /* LINUX_SIGURG */
  118         SIGXCPU,        /* LINUX_SIGXCPU */
  119         SIGXFSZ,        /* LINUX_SIGXFSZ */
  120         SIGVTALRM,      /* LINUX_SIGVTALARM */
  121         SIGPROF,        /* LINUX_SIGPROF */
  122         SIGWINCH,       /* LINUX_SIGWINCH */
  123         SIGIO,          /* LINUX_SIGIO */
  124         /*
  125          * FreeBSD does not have SIGPWR signal, map Linux SIGPWR signal
  126          * to the first unused FreeBSD signal number. Since Linux supports
  127          * signals from 1 to 64 we are ok here as our SIGRTMIN = 65.
  128          */
  129         SIGRTMIN,       /* LINUX_SIGPWR */
  130         SIGSYS          /* LINUX_SIGSYS */
  131 };
  132 
  133 static struct cdev *dev_shm_cdev;
  134 static struct cdevsw dev_shm_cdevsw = {
  135      .d_version = D_VERSION,
  136      .d_name    = "dev_shm",
  137 };
  138 
  139 /*
  140  * Map Linux RT signals to the FreeBSD RT signals.
  141  */
  142 static inline int
  143 linux_to_bsd_rt_signal(int sig)
  144 {
  145 
  146         return (SIGRTMIN + 1 + sig - LINUX_SIGRTMIN);
  147 }
  148 
  149 static inline int
  150 bsd_to_linux_rt_signal(int sig)
  151 {
  152 
  153         return (sig - SIGRTMIN - 1 + LINUX_SIGRTMIN);
  154 }
  155 
  156 int
  157 linux_to_bsd_signal(int sig)
  158 {
  159 
  160         KASSERT(sig > 0 && sig <= LINUX_SIGRTMAX, ("invalid Linux signal %d\n", sig));
  161 
  162         if (sig < LINUX_SIGRTMIN)
  163                 return (linux_to_bsd_sigtbl[_SIG_IDX(sig)]);
  164 
  165         return (linux_to_bsd_rt_signal(sig));
  166 }
  167 
  168 int
  169 bsd_to_linux_signal(int sig)
  170 {
  171 
  172         if (sig <= LINUX_SIGTBLSZ)
  173                 return (bsd_to_linux_sigtbl[_SIG_IDX(sig)]);
  174         if (sig == SIGRTMIN)
  175                 return (LINUX_SIGPWR);
  176 
  177         return (bsd_to_linux_rt_signal(sig));
  178 }
  179 
  180 int
  181 linux_to_bsd_sigaltstack(int lsa)
  182 {
  183         int bsa = 0;
  184 
  185         if (lsa & LINUX_SS_DISABLE)
  186                 bsa |= SS_DISABLE;
  187         /*
  188          * Linux ignores SS_ONSTACK flag for ss
  189          * parameter while FreeBSD prohibits it.
  190          */
  191         return (bsa);
  192 }
  193 
  194 int
  195 bsd_to_linux_sigaltstack(int bsa)
  196 {
  197         int lsa = 0;
  198 
  199         if (bsa & SS_DISABLE)
  200                 lsa |= LINUX_SS_DISABLE;
  201         if (bsa & SS_ONSTACK)
  202                 lsa |= LINUX_SS_ONSTACK;
  203         return (lsa);
  204 }
  205 
  206 void
  207 linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss)
  208 {
  209         int b, l;
  210 
  211         SIGEMPTYSET(*bss);
  212         for (l = 1; l <= LINUX_SIGRTMAX; l++) {
  213                 if (LINUX_SIGISMEMBER(*lss, l)) {
  214                         b = linux_to_bsd_signal(l);
  215                         if (b)
  216                                 SIGADDSET(*bss, b);
  217                 }
  218         }
  219 }
  220 
  221 void
  222 bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
  223 {
  224         int b, l;
  225 
  226         LINUX_SIGEMPTYSET(*lss);
  227         for (b = 1; b <= SIGRTMAX; b++) {
  228                 if (SIGISMEMBER(*bss, b)) {
  229                         l = bsd_to_linux_signal(b);
  230                         if (l)
  231                                 LINUX_SIGADDSET(*lss, l);
  232                 }
  233         }
  234 }
  235 
  236 /*
  237  * Translate a Linux interface name to a FreeBSD interface name,
  238  * and return the associated ifnet structure
  239  * bsdname and lxname need to be least IFNAMSIZ bytes long, but
  240  * can point to the same buffer.
  241  */
  242 struct ifnet *
  243 ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
  244 {
  245         struct ifnet *ifp;
  246         int len, unit;
  247         char *ep;
  248         int index;
  249         bool is_eth, is_lo;
  250 
  251         for (len = 0; len < LINUX_IFNAMSIZ; ++len)
  252                 if (!isalpha(lxname[len]) || lxname[len] == '\0')
  253                         break;
  254         if (len == 0 || len == LINUX_IFNAMSIZ)
  255                 return (NULL);
  256         /* Linux loopback interface name is lo (not lo0) */
  257         is_lo = (len == 2 && strncmp(lxname, "lo", len) == 0);
  258         unit = (int)strtoul(lxname + len, &ep, 10);
  259         if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) &&
  260             is_lo == 0)
  261                 return (NULL);
  262         index = 0;
  263         is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0);
  264 
  265         CURVNET_SET(TD_TO_VNET(td));
  266         IFNET_RLOCK();
  267         CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
  268                 /*
  269                  * Allow Linux programs to use FreeBSD names. Don't presume
  270                  * we never have an interface named "eth", so don't make
  271                  * the test optional based on is_eth.
  272                  */
  273                 if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
  274                         break;
  275                 if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
  276                         break;
  277                 if (is_lo && IFP_IS_LOOP(ifp))
  278                         break;
  279         }
  280         IFNET_RUNLOCK();
  281         CURVNET_RESTORE();
  282         if (ifp != NULL && bsdname != NULL)
  283                 strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
  284         return (ifp);
  285 }
  286 
  287 void
  288 linux_ifflags(struct ifnet *ifp, short *flags)
  289 {
  290         unsigned short fl;
  291 
  292         fl = (ifp->if_flags | ifp->if_drv_flags) & 0xffff;
  293         *flags = 0;
  294         if (fl & IFF_UP)
  295                 *flags |= LINUX_IFF_UP;
  296         if (fl & IFF_BROADCAST)
  297                 *flags |= LINUX_IFF_BROADCAST;
  298         if (fl & IFF_DEBUG)
  299                 *flags |= LINUX_IFF_DEBUG;
  300         if (fl & IFF_LOOPBACK)
  301                 *flags |= LINUX_IFF_LOOPBACK;
  302         if (fl & IFF_POINTOPOINT)
  303                 *flags |= LINUX_IFF_POINTOPOINT;
  304         if (fl & IFF_DRV_RUNNING)
  305                 *flags |= LINUX_IFF_RUNNING;
  306         if (fl & IFF_NOARP)
  307                 *flags |= LINUX_IFF_NOARP;
  308         if (fl & IFF_PROMISC)
  309                 *flags |= LINUX_IFF_PROMISC;
  310         if (fl & IFF_ALLMULTI)
  311                 *flags |= LINUX_IFF_ALLMULTI;
  312         if (fl & IFF_MULTICAST)
  313                 *flags |= LINUX_IFF_MULTICAST;
  314 }
  315 
  316 int
  317 linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa)
  318 {
  319         struct ifaddr *ifa;
  320         struct sockaddr_dl *sdl;
  321 
  322         if (IFP_IS_LOOP(ifp)) {
  323                 bzero(lsa, sizeof(*lsa));
  324                 lsa->sa_family = LINUX_ARPHRD_LOOPBACK;
  325                 return (0);
  326         }
  327 
  328         if (!IFP_IS_ETH(ifp))
  329                 return (ENOENT);
  330 
  331         CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
  332                 sdl = (struct sockaddr_dl*)ifa->ifa_addr;
  333                 if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
  334                     (sdl->sdl_type == IFT_ETHER)) {
  335                         bzero(lsa, sizeof(*lsa));
  336                         lsa->sa_family = LINUX_ARPHRD_ETHER;
  337                         bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN);
  338                         return (0);
  339                 }
  340         }
  341 
  342         return (ENOENT);
  343 }
  344 
  345 int
  346 linux_to_bsd_domain(int domain)
  347 {
  348 
  349         switch (domain) {
  350         case LINUX_AF_UNSPEC:
  351                 return (AF_UNSPEC);
  352         case LINUX_AF_UNIX:
  353                 return (AF_LOCAL);
  354         case LINUX_AF_INET:
  355                 return (AF_INET);
  356         case LINUX_AF_INET6:
  357                 return (AF_INET6);
  358         case LINUX_AF_AX25:
  359                 return (AF_CCITT);
  360         case LINUX_AF_IPX:
  361                 return (AF_IPX);
  362         case LINUX_AF_APPLETALK:
  363                 return (AF_APPLETALK);
  364         }
  365         return (-1);
  366 }
  367 
  368 int
  369 bsd_to_linux_domain(int domain)
  370 {
  371 
  372         switch (domain) {
  373         case AF_UNSPEC:
  374                 return (LINUX_AF_UNSPEC);
  375         case AF_LOCAL:
  376                 return (LINUX_AF_UNIX);
  377         case AF_INET:
  378                 return (LINUX_AF_INET);
  379         case AF_INET6:
  380                 return (LINUX_AF_INET6);
  381         case AF_CCITT:
  382                 return (LINUX_AF_AX25);
  383         case AF_IPX:
  384                 return (LINUX_AF_IPX);
  385         case AF_APPLETALK:
  386                 return (LINUX_AF_APPLETALK);
  387         }
  388         return (-1);
  389 }
  390 
  391 /*
  392  * Based on the fact that:
  393  * 1. Native and Linux storage of struct sockaddr
  394  * and struct sockaddr_in6 are equal.
  395  * 2. On Linux sa_family is the first member of all struct sockaddr.
  396  */
  397 int
  398 bsd_to_linux_sockaddr(const struct sockaddr *sa, struct l_sockaddr **lsa,
  399     socklen_t len)
  400 {
  401         struct l_sockaddr *kosa;
  402         int error, bdom;
  403 
  404         *lsa = NULL;
  405         if (len < 2 || len > UCHAR_MAX)
  406                 return (EINVAL);
  407 
  408         kosa = malloc(len, M_SONAME, M_WAITOK);
  409         bcopy(sa, kosa, len);
  410 
  411         bdom = bsd_to_linux_domain(sa->sa_family);
  412         if (bdom == -1) {
  413                 error = EAFNOSUPPORT;
  414                 goto out;
  415         }
  416 
  417         kosa->sa_family = bdom;
  418         *lsa = kosa;
  419         return (0);
  420 
  421 out:
  422         free(kosa, M_SONAME);
  423         return (error);
  424 }
  425 
  426 int
  427 linux_to_bsd_sockaddr(const struct l_sockaddr *osa, struct sockaddr **sap,
  428     socklen_t *len)
  429 {
  430         struct sockaddr *sa;
  431         struct l_sockaddr *kosa;
  432 #ifdef INET6
  433         struct sockaddr_in6 *sin6;
  434         bool  oldv6size;
  435 #endif
  436         char *name;
  437         int salen, bdom, error, hdrlen, namelen;
  438 
  439         if (*len < 2 || *len > UCHAR_MAX)
  440                 return (EINVAL);
  441 
  442         salen = *len;
  443 
  444 #ifdef INET6
  445         oldv6size = false;
  446         /*
  447          * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
  448          * if it's a v4-mapped address, so reserve the proper space
  449          * for it.
  450          */
  451         if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
  452                 salen += sizeof(uint32_t);
  453                 oldv6size = true;
  454         }
  455 #endif
  456 
  457         kosa = malloc(salen, M_SONAME, M_WAITOK);
  458 
  459         if ((error = copyin(osa, kosa, *len)))
  460                 goto out;
  461 
  462         bdom = linux_to_bsd_domain(kosa->sa_family);
  463         if (bdom == -1) {
  464                 error = EAFNOSUPPORT;
  465                 goto out;
  466         }
  467 
  468 #ifdef INET6
  469         /*
  470          * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
  471          * which lacks the scope id compared with RFC2553 one. If we detect
  472          * the situation, reject the address and write a message to system log.
  473          *
  474          * Still accept addresses for which the scope id is not used.
  475          */
  476         if (oldv6size) {
  477                 if (bdom == AF_INET6) {
  478                         sin6 = (struct sockaddr_in6 *)kosa;
  479                         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
  480                             (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
  481                              !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
  482                              !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
  483                              !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
  484                              !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
  485                                 sin6->sin6_scope_id = 0;
  486                         } else {
  487                                 linux_msg(curthread,
  488                                     "obsolete pre-RFC2553 sockaddr_in6 rejected");
  489                                 error = EINVAL;
  490                                 goto out;
  491                         }
  492                 } else
  493                         salen -= sizeof(uint32_t);
  494         }
  495 #endif
  496         if (bdom == AF_INET) {
  497                 if (salen < sizeof(struct sockaddr_in)) {
  498                         error = EINVAL;
  499                         goto out;
  500                 }
  501                 salen = sizeof(struct sockaddr_in);
  502         }
  503 
  504         if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
  505                 hdrlen = offsetof(struct sockaddr_un, sun_path);
  506                 name = ((struct sockaddr_un *)kosa)->sun_path;
  507                 if (*name == '\0') {
  508                         /*
  509                          * Linux abstract namespace starts with a NULL byte.
  510                          * XXX We do not support abstract namespace yet.
  511                          */
  512                         namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
  513                 } else
  514                         namelen = strnlen(name, salen - hdrlen);
  515                 salen = hdrlen + namelen;
  516                 if (salen > sizeof(struct sockaddr_un)) {
  517                         error = ENAMETOOLONG;
  518                         goto out;
  519                 }
  520         }
  521 
  522         sa = (struct sockaddr *)kosa;
  523         sa->sa_family = bdom;
  524         sa->sa_len = salen;
  525 
  526         *sap = sa;
  527         *len = salen;
  528         return (0);
  529 
  530 out:
  531         free(kosa, M_SONAME);
  532         return (error);
  533 }
  534 
  535 void
  536 linux_dev_shm_create(void)
  537 {
  538         int error;
  539 
  540         error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &dev_shm_cdev,
  541             &dev_shm_cdevsw, NULL, UID_ROOT, GID_WHEEL, 0, "shm/.mountpoint");
  542         if (error != 0) {
  543                 printf("%s: failed to create device node, error %d\n",
  544                     __func__, error);
  545         }
  546 }
  547 
  548 void
  549 linux_dev_shm_destroy(void)
  550 {
  551 
  552         destroy_dev(dev_shm_cdev);
  553 }
  554 
  555 int
  556 bsd_to_linux_bits_(int value, struct bsd_to_linux_bitmap *bitmap,
  557     size_t mapcnt, int no_value)
  558 {
  559         int bsd_mask, bsd_value, linux_mask, linux_value;
  560         int linux_ret;
  561         size_t i;
  562         bool applied;
  563 
  564         applied = false;
  565         linux_ret = 0;
  566         for (i = 0; i < mapcnt; ++i) {
  567                 bsd_mask = bitmap[i].bsd_mask;
  568                 bsd_value = bitmap[i].bsd_value;
  569                 if (bsd_mask == 0)
  570                         bsd_mask = bsd_value;
  571 
  572                 linux_mask = bitmap[i].linux_mask;
  573                 linux_value = bitmap[i].linux_value;
  574                 if (linux_mask == 0)
  575                         linux_mask = linux_value;
  576 
  577                 /*
  578                  * If a mask larger than just the value is set, we explicitly
  579                  * want to make sure that only this bit we mapped within that
  580                  * mask is set.
  581                  */
  582                 if ((value & bsd_mask) == bsd_value) {
  583                         linux_ret = (linux_ret & ~linux_mask) | linux_value;
  584                         applied = true;
  585                 }
  586         }
  587 
  588         if (!applied)
  589                 return (no_value);
  590         return (linux_ret);
  591 }
  592 
  593 int
  594 linux_to_bsd_bits_(int value, struct bsd_to_linux_bitmap *bitmap,
  595     size_t mapcnt, int no_value)
  596 {
  597         int bsd_mask, bsd_value, linux_mask, linux_value;
  598         int bsd_ret;
  599         size_t i;
  600         bool applied;
  601 
  602         applied = false;
  603         bsd_ret = 0;
  604         for (i = 0; i < mapcnt; ++i) {
  605                 bsd_mask = bitmap[i].bsd_mask;
  606                 bsd_value = bitmap[i].bsd_value;
  607                 if (bsd_mask == 0)
  608                         bsd_mask = bsd_value;
  609 
  610                 linux_mask = bitmap[i].linux_mask;
  611                 linux_value = bitmap[i].linux_value;
  612                 if (linux_mask == 0)
  613                         linux_mask = linux_value;
  614 
  615                 /*
  616                  * If a mask larger than just the value is set, we explicitly
  617                  * want to make sure that only this bit we mapped within that
  618                  * mask is set.
  619                  */
  620                 if ((value & linux_mask) == linux_value) {
  621                         bsd_ret = (bsd_ret & ~bsd_mask) | bsd_value;
  622                         applied = true;
  623                 }
  624         }
  625 
  626         if (!applied)
  627                 return (no_value);
  628         return (bsd_ret);
  629 }

Cache object: 1514995f43c9b564dfd999168687ac27


[ 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.