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_mib.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) 1999 Marcel Moolenaar
    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  *    in this position and unchanged.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/9.2/sys/compat/linux/linux_mib.c 248085 2013-03-09 02:36:32Z marius $");
   31 
   32 #include "opt_compat.h"
   33 #include "opt_kdtrace.h"
   34 
   35 #include <sys/param.h>
   36 #include <sys/kernel.h>
   37 #include <sys/sdt.h>
   38 #include <sys/systm.h>
   39 #include <sys/sysctl.h>
   40 #include <sys/proc.h>
   41 #include <sys/malloc.h>
   42 #include <sys/mount.h>
   43 #include <sys/jail.h>
   44 #include <sys/lock.h>
   45 #include <sys/mutex.h>
   46 #include <sys/sx.h>
   47 
   48 #ifdef COMPAT_LINUX32
   49 #include <machine/../linux32/linux.h>
   50 #else
   51 #include <machine/../linux/linux.h>
   52 #endif
   53 #include <compat/linux/linux_dtrace.h>
   54 #include <compat/linux/linux_mib.h>
   55 
   56 /* DTrace init */
   57 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
   58 
   59 /**
   60  * DTrace probes in this module.
   61  */
   62 LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_osname, entry);
   63 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osname, sysctl_string_error, "int");
   64 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osname, return, "int");
   65 
   66 LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_osrelease, entry);
   67 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osrelease, sysctl_string_error, "int");
   68 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_osrelease, return, "int");
   69 LIN_SDT_PROBE_DEFINE0(mib, linux_sysctl_oss_version, entry);
   70 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_oss_version, sysctl_string_error,
   71     "int");
   72 LIN_SDT_PROBE_DEFINE1(mib, linux_sysctl_oss_version, return, "int");
   73 LIN_SDT_PROBE_DEFINE2(mib, linux_map_osrel, entry, "char *", "int *");
   74 LIN_SDT_PROBE_DEFINE1(mib, linux_map_osrel, return, "int");
   75 LIN_SDT_PROBE_DEFINE2(mib, linux_get_prison, entry, "struct prison *",
   76     "struct prison **");
   77 LIN_SDT_PROBE_DEFINE1(mib, linux_get_prison, return, "struct linux_prison *");
   78 LIN_SDT_PROBE_DEFINE2(mib, linux_alloc_prison, entry, "struct prison *",
   79     "struct linux_prison **");
   80 LIN_SDT_PROBE_DEFINE1(mib, linux_alloc_prison, return, "int");
   81 LIN_SDT_PROBE_DEFINE2(mib, linux_prison_create, entry, "void *", "void *");
   82 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_create, vfs_copyopt_error, "int");
   83 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_create, return, "int");
   84 LIN_SDT_PROBE_DEFINE2(mib, linux_prison_check, entry, "void *", "void *");
   85 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, vfs_copyopt_error, "int");
   86 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, vfs_getopt_error, "int");
   87 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_check, return, "int");
   88 LIN_SDT_PROBE_DEFINE2(mib, linux_prison_set, entry, "void *", "void *");
   89 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, vfs_copyopt_error, "int");
   90 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, vfs_getopt_error, "int");
   91 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_set, return, "int");
   92 LIN_SDT_PROBE_DEFINE2(mib, linux_prison_get, entry, "void *", "void *");
   93 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, vfs_setopt_error, "int");
   94 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, vfs_setopts_error, "int");
   95 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_get, return, "int");
   96 LIN_SDT_PROBE_DEFINE1(mib, linux_prison_destructor, entry, "void *");
   97 LIN_SDT_PROBE_DEFINE0(mib, linux_prison_destructor, return);
   98 LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_register, entry);
   99 LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_register, return);
  100 LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_deregister, entry);
  101 LIN_SDT_PROBE_DEFINE0(mib, linux_osd_jail_deregister, return);
  102 LIN_SDT_PROBE_DEFINE2(mib, linux_get_osname, entry, "struct thread *",
  103     "char *");
  104 LIN_SDT_PROBE_DEFINE0(mib, linux_get_osname, return);
  105 LIN_SDT_PROBE_DEFINE2(mib, linux_set_osname, entry, "struct thread *",
  106     "char *");
  107 LIN_SDT_PROBE_DEFINE1(mib, linux_set_osname, return, "int");
  108 LIN_SDT_PROBE_DEFINE2(mib, linux_get_osrelease, entry, "struct thread *",
  109     "char *");
  110 LIN_SDT_PROBE_DEFINE0(mib, linux_get_osrelease, return);
  111 LIN_SDT_PROBE_DEFINE1(mib, linux_kernver, entry, "struct thread *");
  112 LIN_SDT_PROBE_DEFINE1(mib, linux_kernver, return, "int");
  113 LIN_SDT_PROBE_DEFINE2(mib, linux_set_osrelease, entry, "struct thread *",
  114     "char *");
  115 LIN_SDT_PROBE_DEFINE1(mib, linux_set_osrelease, return, "int");
  116 LIN_SDT_PROBE_DEFINE1(mib, linux_get_oss_version, entry, "struct thread *");
  117 LIN_SDT_PROBE_DEFINE1(mib, linux_get_oss_version, return, "int");
  118 
  119 LIN_SDT_PROBE_DEFINE2(mib, linux_set_oss_version, entry, "struct thread *",
  120     "int");
  121 LIN_SDT_PROBE_DEFINE1(mib, linux_set_oss_version, return, "int");
  122 
  123 struct linux_prison {
  124         char    pr_osname[LINUX_MAX_UTSNAME];
  125         char    pr_osrelease[LINUX_MAX_UTSNAME];
  126         int     pr_oss_version;
  127         int     pr_osrel;
  128 };
  129 
  130 static struct linux_prison lprison0 = {
  131         .pr_osname =            "Linux",
  132         .pr_osrelease =         "2.6.16",
  133         .pr_oss_version =       0x030600,
  134         .pr_osrel =             2006016
  135 };
  136 
  137 static unsigned linux_osd_jail_slot;
  138 
  139 static SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW, 0,
  140             "Linux mode");
  141 
  142 static int      linux_set_osname(struct thread *td, char *osname);
  143 static int      linux_set_osrelease(struct thread *td, char *osrelease);
  144 static int      linux_set_oss_version(struct thread *td, int oss_version);
  145 
  146 static int
  147 linux_sysctl_osname(SYSCTL_HANDLER_ARGS)
  148 {
  149         char osname[LINUX_MAX_UTSNAME];
  150         int error;
  151 
  152         LIN_SDT_PROBE0(mib, linux_sysctl_osname, entry);
  153 
  154         linux_get_osname(req->td, osname);
  155         error = sysctl_handle_string(oidp, osname, LINUX_MAX_UTSNAME, req);
  156         if (error != 0 || req->newptr == NULL) {
  157                 LIN_SDT_PROBE1(mib, linux_sysctl_osname, sysctl_string_error,
  158                     error);
  159                 LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error);
  160                 return (error);
  161         }
  162         error = linux_set_osname(req->td, osname);
  163 
  164         LIN_SDT_PROBE1(mib, linux_sysctl_osname, return, error);
  165         return (error);
  166 }
  167 
  168 SYSCTL_PROC(_compat_linux, OID_AUTO, osname,
  169             CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
  170             0, 0, linux_sysctl_osname, "A",
  171             "Linux kernel OS name");
  172 
  173 static int
  174 linux_sysctl_osrelease(SYSCTL_HANDLER_ARGS)
  175 {
  176         char osrelease[LINUX_MAX_UTSNAME];
  177         int error;
  178 
  179         LIN_SDT_PROBE0(mib, linux_sysctl_osrelease, entry);
  180 
  181         linux_get_osrelease(req->td, osrelease);
  182         error = sysctl_handle_string(oidp, osrelease, LINUX_MAX_UTSNAME, req);
  183         if (error != 0 || req->newptr == NULL) {
  184                 LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, sysctl_string_error,
  185                     error);
  186                 LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error);
  187                 return (error);
  188         }
  189         error = linux_set_osrelease(req->td, osrelease);
  190 
  191         LIN_SDT_PROBE1(mib, linux_sysctl_osrelease, return, error);
  192         return (error);
  193 }
  194 
  195 SYSCTL_PROC(_compat_linux, OID_AUTO, osrelease,
  196             CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
  197             0, 0, linux_sysctl_osrelease, "A",
  198             "Linux kernel OS release");
  199 
  200 static int
  201 linux_sysctl_oss_version(SYSCTL_HANDLER_ARGS)
  202 {
  203         int oss_version;
  204         int error;
  205 
  206         LIN_SDT_PROBE0(mib, linux_sysctl_oss_version, entry);
  207 
  208         oss_version = linux_get_oss_version(req->td);
  209         error = sysctl_handle_int(oidp, &oss_version, 0, req);
  210         if (error != 0 || req->newptr == NULL) {
  211                 LIN_SDT_PROBE1(mib, linux_sysctl_oss_version,
  212                     sysctl_string_error, error);
  213                 LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error);
  214                 return (error);
  215         }
  216         error = linux_set_oss_version(req->td, oss_version);
  217 
  218         LIN_SDT_PROBE1(mib, linux_sysctl_oss_version, return, error);
  219         return (error);
  220 }
  221 
  222 SYSCTL_PROC(_compat_linux, OID_AUTO, oss_version,
  223             CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
  224             0, 0, linux_sysctl_oss_version, "I",
  225             "Linux OSS version");
  226 
  227 /*
  228  * Map the osrelease into integer
  229  */
  230 static int
  231 linux_map_osrel(char *osrelease, int *osrel)
  232 {
  233         char *sep, *eosrelease;
  234         int len, v0, v1, v2, v;
  235 
  236         LIN_SDT_PROBE2(mib, linux_map_osrel, entry, osrelease, osrel);
  237 
  238         len = strlen(osrelease);
  239         eosrelease = osrelease + len;
  240         v0 = strtol(osrelease, &sep, 10);
  241         if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') {
  242                 LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
  243                 return (EINVAL);
  244         }
  245         osrelease = sep + 1;
  246         v1 = strtol(osrelease, &sep, 10);
  247         if (osrelease == sep || sep + 1 >= eosrelease || *sep != '.') {
  248                 LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
  249                 return (EINVAL);
  250         }
  251         osrelease = sep + 1;
  252         v2 = strtol(osrelease, &sep, 10);
  253         if (osrelease == sep || sep != eosrelease) {
  254                 LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
  255                 return (EINVAL);
  256         }
  257 
  258         v = v0 * 1000000 + v1 * 1000 + v2;
  259         if (v < 1000000) {
  260                 LIN_SDT_PROBE1(mib, linux_map_osrel, return, EINVAL);
  261                 return (EINVAL);
  262         }
  263 
  264         *osrel = v;
  265 
  266         LIN_SDT_PROBE1(mib, linux_map_osrel, return, 0);
  267         return (0);
  268 }
  269 
  270 /*
  271  * Find a prison with Linux info.
  272  * Return the Linux info and the (locked) prison.
  273  */
  274 static struct linux_prison *
  275 linux_find_prison(struct prison *spr, struct prison **prp)
  276 {
  277         struct prison *pr;
  278         struct linux_prison *lpr;
  279 
  280         LIN_SDT_PROBE2(mib, linux_get_prison, entry, spr, prp);
  281 
  282         if (!linux_osd_jail_slot)
  283                 /* In case osd_register failed. */
  284                 spr = &prison0;
  285         for (pr = spr;; pr = pr->pr_parent) {
  286                 mtx_lock(&pr->pr_mtx);
  287                 lpr = (pr == &prison0)
  288                     ? &lprison0
  289                     : osd_jail_get(pr, linux_osd_jail_slot);
  290                 if (lpr != NULL)
  291                         break;
  292                 mtx_unlock(&pr->pr_mtx);
  293         }
  294         *prp = pr;
  295 
  296         LIN_SDT_PROBE1(mib, linux_get_prison, return, lpr);
  297         return (lpr);
  298 }
  299 
  300 /*
  301  * Ensure a prison has its own Linux info.  If lprp is non-null, point it to
  302  * the Linux info and lock the prison.
  303  */
  304 static int
  305 linux_alloc_prison(struct prison *pr, struct linux_prison **lprp)
  306 {
  307         struct prison *ppr;
  308         struct linux_prison *lpr, *nlpr;
  309         int error;
  310 
  311         LIN_SDT_PROBE2(mib, linux_alloc_prison, entry, pr, lprp);
  312 
  313         /* If this prison already has Linux info, return that. */
  314         error = 0;
  315         lpr = linux_find_prison(pr, &ppr);
  316         if (ppr == pr)
  317                 goto done;
  318         /*
  319          * Allocate a new info record.  Then check again, in case something
  320          * changed during the allocation.
  321          */
  322         mtx_unlock(&ppr->pr_mtx);
  323         nlpr = malloc(sizeof(struct linux_prison), M_PRISON, M_WAITOK);
  324         lpr = linux_find_prison(pr, &ppr);
  325         if (ppr == pr) {
  326                 free(nlpr, M_PRISON);
  327                 goto done;
  328         }
  329         /* Inherit the initial values from the ancestor. */
  330         mtx_lock(&pr->pr_mtx);
  331         error = osd_jail_set(pr, linux_osd_jail_slot, nlpr);
  332         if (error == 0) {
  333                 bcopy(lpr, nlpr, sizeof(*lpr));
  334                 lpr = nlpr;
  335         } else {
  336                 free(nlpr, M_PRISON);
  337                 lpr = NULL;
  338         }
  339         mtx_unlock(&ppr->pr_mtx);
  340  done:
  341         if (lprp != NULL)
  342                 *lprp = lpr;
  343         else
  344                 mtx_unlock(&pr->pr_mtx);
  345 
  346         LIN_SDT_PROBE1(mib, linux_alloc_prison, return, error);
  347         return (error);
  348 }
  349 
  350 /*
  351  * Jail OSD methods for Linux prison data.
  352  */
  353 static int
  354 linux_prison_create(void *obj, void *data)
  355 {
  356         struct prison *pr = obj;
  357         struct vfsoptlist *opts = data;
  358         int jsys, error;
  359 
  360         LIN_SDT_PROBE2(mib, linux_prison_create, entry, obj, data);
  361 
  362         error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
  363         if (error != 0) {
  364                 LIN_SDT_PROBE1(mib, linux_prison_create, vfs_copyopt_error,
  365                     error);
  366         } else if (jsys == JAIL_SYS_INHERIT) {
  367                 LIN_SDT_PROBE1(mib, linux_prison_create, return, 0);
  368                 return (0);
  369         }
  370         /*
  371          * Inherit a prison's initial values from its parent
  372          * (different from JAIL_SYS_INHERIT which also inherits changes).
  373          */
  374         error = linux_alloc_prison(pr, NULL);
  375 
  376         LIN_SDT_PROBE1(mib, linux_prison_create, return, error);
  377         return (error);
  378 }
  379 
  380 static int
  381 linux_prison_check(void *obj __unused, void *data)
  382 {
  383         struct vfsoptlist *opts = data;
  384         char *osname, *osrelease;
  385         int error, jsys, len, osrel, oss_version;
  386 
  387         LIN_SDT_PROBE2(mib, linux_prison_check, entry, obj, data);
  388 
  389         /* Check that the parameters are correct. */
  390         error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
  391         if (error != 0) {
  392                 LIN_SDT_PROBE1(mib, linux_prison_check, vfs_copyopt_error,
  393                     error);
  394         }
  395         if (error != ENOENT) {
  396                 if (error != 0) {
  397                         LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
  398                         return (error);
  399                 }
  400                 if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) {
  401                         LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL);
  402                         return (EINVAL);
  403                 }
  404         }
  405         error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len);
  406         if (error != 0) {
  407                 LIN_SDT_PROBE1(mib, linux_prison_check, vfs_getopt_error,
  408                     error);
  409         }
  410         if (error != ENOENT) {
  411                 if (error != 0) {
  412                         LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
  413                         return (error);
  414                 }
  415                 if (len == 0 || osname[len - 1] != '\0') {
  416                         LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL);
  417                         return (EINVAL);
  418                 }
  419                 if (len > LINUX_MAX_UTSNAME) {
  420                         vfs_opterror(opts, "linux.osname too long");
  421                         LIN_SDT_PROBE1(mib, linux_prison_check, return,
  422                             ENAMETOOLONG);
  423                         return (ENAMETOOLONG);
  424                 }
  425         }
  426         error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len);
  427         if (error != 0) {
  428                 LIN_SDT_PROBE1(mib, linux_prison_check, vfs_getopt_error,
  429                     error);
  430         }
  431         if (error != ENOENT) {
  432                 if (error != 0) {
  433                         LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
  434                         return (error);
  435                 }
  436                 if (len == 0 || osrelease[len - 1] != '\0') {
  437                         LIN_SDT_PROBE1(mib, linux_prison_check, return, EINVAL);
  438                         return (EINVAL);
  439                 }
  440                 if (len > LINUX_MAX_UTSNAME) {
  441                         vfs_opterror(opts, "linux.osrelease too long");
  442                         LIN_SDT_PROBE1(mib, linux_prison_check, return,
  443                             ENAMETOOLONG);
  444                         return (ENAMETOOLONG);
  445                 }
  446                 error = linux_map_osrel(osrelease, &osrel);
  447                 if (error != 0) {
  448                         vfs_opterror(opts, "linux.osrelease format error");
  449                         LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
  450                         return (error);
  451                 }
  452         }
  453         error = vfs_copyopt(opts, "linux.oss_version", &oss_version,
  454             sizeof(oss_version));
  455         if (error != 0)
  456             LIN_SDT_PROBE1(mib, linux_prison_check, vfs_copyopt_error, error);
  457 
  458         if (error == ENOENT)
  459                 error = 0;
  460         LIN_SDT_PROBE1(mib, linux_prison_check, return, error);
  461         return (error);
  462 }
  463 
  464 static int
  465 linux_prison_set(void *obj, void *data)
  466 {
  467         struct linux_prison *lpr;
  468         struct prison *pr = obj;
  469         struct vfsoptlist *opts = data;
  470         char *osname, *osrelease;
  471         int error, gotversion, jsys, len, oss_version;
  472 
  473         LIN_SDT_PROBE2(mib, linux_prison_set, entry, obj, data);
  474 
  475         /* Set the parameters, which should be correct. */
  476         error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
  477         if (error != 0)
  478                 LIN_SDT_PROBE1(mib, linux_prison_set, vfs_copyopt_error, error);
  479         if (error == ENOENT)
  480                 jsys = -1;
  481         error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len);
  482         if (error != 0)
  483                 LIN_SDT_PROBE1(mib, linux_prison_set, vfs_getopt_error, error);
  484         if (error == ENOENT)
  485                 osname = NULL;
  486         else
  487                 jsys = JAIL_SYS_NEW;
  488         error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len);
  489         if (error != 0)
  490                 LIN_SDT_PROBE1(mib, linux_prison_set, vfs_getopt_error, error);
  491         if (error == ENOENT)
  492                 osrelease = NULL;
  493         else
  494                 jsys = JAIL_SYS_NEW;
  495         error = vfs_copyopt(opts, "linux.oss_version", &oss_version,
  496             sizeof(oss_version));
  497         if (error != 0)
  498                 LIN_SDT_PROBE1(mib, linux_prison_set, vfs_copyopt_error, error);
  499         if (error == ENOENT)
  500                 gotversion = 0;
  501         else {
  502                 gotversion = 1;
  503                 jsys = JAIL_SYS_NEW;
  504         }
  505         switch (jsys) {
  506         case JAIL_SYS_INHERIT:
  507                 /* "linux=inherit": inherit the parent's Linux info. */
  508                 mtx_lock(&pr->pr_mtx);
  509                 osd_jail_del(pr, linux_osd_jail_slot);
  510                 mtx_unlock(&pr->pr_mtx);
  511                 break;
  512         case JAIL_SYS_NEW:
  513                 /*
  514                  * "linux=new" or "linux.*":
  515                  * the prison gets its own Linux info.
  516                  */
  517                 error = linux_alloc_prison(pr, &lpr);
  518                 if (error) {
  519                         mtx_unlock(&pr->pr_mtx);
  520                         LIN_SDT_PROBE1(mib, linux_prison_set, return, error);
  521                         return (error);
  522                 }
  523                 if (osrelease) {
  524                         error = linux_map_osrel(osrelease, &lpr->pr_osrel);
  525                         if (error) {
  526                                 mtx_unlock(&pr->pr_mtx);
  527                                 LIN_SDT_PROBE1(mib, linux_prison_set, return,
  528                                     error);
  529                                 return (error);
  530                         }
  531                         strlcpy(lpr->pr_osrelease, osrelease,
  532                             LINUX_MAX_UTSNAME);
  533                 }
  534                 if (osname)
  535                         strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME);
  536                 if (gotversion)
  537                         lpr->pr_oss_version = oss_version;
  538                 mtx_unlock(&pr->pr_mtx);
  539         }
  540 
  541         LIN_SDT_PROBE1(mib, linux_prison_set, return, 0);
  542         return (0);
  543 }
  544 
  545 SYSCTL_JAIL_PARAM_SYS_NODE(linux, CTLFLAG_RW, "Jail Linux parameters");
  546 SYSCTL_JAIL_PARAM_STRING(_linux, osname, CTLFLAG_RW, LINUX_MAX_UTSNAME,
  547     "Jail Linux kernel OS name");
  548 SYSCTL_JAIL_PARAM_STRING(_linux, osrelease, CTLFLAG_RW, LINUX_MAX_UTSNAME,
  549     "Jail Linux kernel OS release");
  550 SYSCTL_JAIL_PARAM(_linux, oss_version, CTLTYPE_INT | CTLFLAG_RW,
  551     "I", "Jail Linux OSS version");
  552 
  553 static int
  554 linux_prison_get(void *obj, void *data)
  555 {
  556         struct linux_prison *lpr;
  557         struct prison *ppr;
  558         struct prison *pr = obj;
  559         struct vfsoptlist *opts = data;
  560         int error, i;
  561 
  562         static int version0;
  563 
  564         LIN_SDT_PROBE2(mib, linux_prison_get, entry, obj, data);
  565 
  566         /* See if this prison is the one with the Linux info. */
  567         lpr = linux_find_prison(pr, &ppr);
  568         i = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT;
  569         error = vfs_setopt(opts, "linux", &i, sizeof(i));
  570         if (error != 0) {
  571                 LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error, error);
  572                 if (error != ENOENT)
  573                         goto done;
  574         }
  575         if (i) {
  576                 error = vfs_setopts(opts, "linux.osname", lpr->pr_osname);
  577                 if (error != 0) {
  578                         LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
  579                             error);
  580                         if (error != ENOENT)
  581                                 goto done;
  582                 }
  583                 error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease);
  584                 if (error != 0) {
  585                         LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
  586                             error);
  587                         if (error != ENOENT)
  588                                 goto done;
  589                 }
  590                 error = vfs_setopt(opts, "linux.oss_version",
  591                     &lpr->pr_oss_version, sizeof(lpr->pr_oss_version));
  592                 if (error != 0) {
  593                         LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error,
  594                             error);
  595                         if(error != ENOENT)
  596                                 goto done;
  597                 }
  598         } else {
  599                 /*
  600                  * If this prison is inheriting its Linux info, report
  601                  * empty/zero parameters.
  602                  */
  603                 error = vfs_setopts(opts, "linux.osname", "");
  604                 if (error != 0) {
  605                         LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
  606                             error);
  607                         if(error != ENOENT)
  608                                 goto done;
  609                 }
  610                 error = vfs_setopts(opts, "linux.osrelease", "");
  611                 if (error != 0) {
  612                         LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopts_error,
  613                             error);
  614                         if(error != ENOENT)
  615                                 goto done;
  616                 }
  617                 error = vfs_setopt(opts, "linux.oss_version", &version0,
  618                     sizeof(lpr->pr_oss_version));
  619                 if (error != 0) {
  620                         LIN_SDT_PROBE1(mib, linux_prison_get, vfs_setopt_error,
  621                             error);
  622                         if(error != ENOENT)
  623                                 goto done;
  624                 }
  625         }
  626         error = 0;
  627 
  628  done:
  629         mtx_unlock(&ppr->pr_mtx);
  630 
  631         LIN_SDT_PROBE1(mib, linux_prison_get, return, error);
  632         return (error);
  633 }
  634 
  635 static void
  636 linux_prison_destructor(void *data)
  637 {
  638 
  639         LIN_SDT_PROBE1(mib, linux_prison_destructor, entry, data);
  640         free(data, M_PRISON);
  641         LIN_SDT_PROBE0(mib, linux_prison_destructor, return);
  642 }
  643 
  644 void
  645 linux_osd_jail_register(void)
  646 {
  647         struct prison *pr;
  648         osd_method_t methods[PR_MAXMETHOD] = {
  649             [PR_METHOD_CREATE] =        linux_prison_create,
  650             [PR_METHOD_GET] =           linux_prison_get,
  651             [PR_METHOD_SET] =           linux_prison_set,
  652             [PR_METHOD_CHECK] =         linux_prison_check
  653         };
  654 
  655         LIN_SDT_PROBE0(mib, linux_osd_jail_register, entry);
  656 
  657         linux_osd_jail_slot =
  658             osd_jail_register(linux_prison_destructor, methods);
  659         if (linux_osd_jail_slot > 0) {
  660                 /* Copy the system linux info to any current prisons. */
  661                 sx_xlock(&allprison_lock);
  662                 TAILQ_FOREACH(pr, &allprison, pr_list)
  663                         (void)linux_alloc_prison(pr, NULL);
  664                 sx_xunlock(&allprison_lock);
  665         }
  666 
  667         LIN_SDT_PROBE0(mib, linux_osd_jail_register, return);
  668 }
  669 
  670 void
  671 linux_osd_jail_deregister(void)
  672 {
  673 
  674         LIN_SDT_PROBE0(mib, linux_osd_jail_register, entry);
  675 
  676         if (linux_osd_jail_slot)
  677                 osd_jail_deregister(linux_osd_jail_slot);
  678 
  679         LIN_SDT_PROBE0(mib, linux_osd_jail_register, return);
  680 }
  681 
  682 void
  683 linux_get_osname(struct thread *td, char *dst)
  684 {
  685         struct prison *pr;
  686         struct linux_prison *lpr;
  687 
  688         LIN_SDT_PROBE2(mib, linux_get_osname, entry, td, dst);
  689 
  690         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  691         bcopy(lpr->pr_osname, dst, LINUX_MAX_UTSNAME);
  692         mtx_unlock(&pr->pr_mtx);
  693 
  694         LIN_SDT_PROBE0(mib, linux_get_osname, return);
  695 }
  696 
  697 static int
  698 linux_set_osname(struct thread *td, char *osname)
  699 {
  700         struct prison *pr;
  701         struct linux_prison *lpr;
  702 
  703         LIN_SDT_PROBE2(mib, linux_set_osname, entry, td, osname);
  704 
  705         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  706         strlcpy(lpr->pr_osname, osname, LINUX_MAX_UTSNAME);
  707         mtx_unlock(&pr->pr_mtx);
  708 
  709         LIN_SDT_PROBE1(mib, linux_set_osname, return, 0);
  710         return (0);
  711 }
  712 
  713 void
  714 linux_get_osrelease(struct thread *td, char *dst)
  715 {
  716         struct prison *pr;
  717         struct linux_prison *lpr;
  718 
  719         LIN_SDT_PROBE2(mib, linux_get_osrelease, entry, td, dst);
  720 
  721         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  722         bcopy(lpr->pr_osrelease, dst, LINUX_MAX_UTSNAME);
  723         mtx_unlock(&pr->pr_mtx);
  724 
  725         LIN_SDT_PROBE0(mib, linux_get_osrelease, return);
  726 }
  727 
  728 int
  729 linux_kernver(struct thread *td)
  730 {
  731         struct prison *pr;
  732         struct linux_prison *lpr;
  733         int osrel;
  734 
  735         LIN_SDT_PROBE1(mib, linux_kernver, entry, td);
  736 
  737         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  738         osrel = lpr->pr_osrel;
  739         mtx_unlock(&pr->pr_mtx);
  740 
  741         LIN_SDT_PROBE1(mib, linux_kernver, return, osrel);
  742         return (osrel);
  743 }
  744 
  745 static int
  746 linux_set_osrelease(struct thread *td, char *osrelease)
  747 {
  748         struct prison *pr;
  749         struct linux_prison *lpr;
  750         int error;
  751 
  752         LIN_SDT_PROBE2(mib, linux_set_osrelease, entry, td, osrelease);
  753 
  754         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  755         error = linux_map_osrel(osrelease, &lpr->pr_osrel);
  756         if (error == 0)
  757                 strlcpy(lpr->pr_osrelease, osrelease, LINUX_MAX_UTSNAME);
  758         mtx_unlock(&pr->pr_mtx);
  759 
  760         LIN_SDT_PROBE1(mib, linux_set_osrelease, return, error);
  761         return (error);
  762 }
  763 
  764 int
  765 linux_get_oss_version(struct thread *td)
  766 {
  767         struct prison *pr;
  768         struct linux_prison *lpr;
  769         int version;
  770 
  771         LIN_SDT_PROBE1(mib, linux_get_oss_version, entry, td);
  772 
  773         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  774         version = lpr->pr_oss_version;
  775         mtx_unlock(&pr->pr_mtx);
  776 
  777         LIN_SDT_PROBE1(mib, linux_get_oss_version, return, version);
  778         return (version);
  779 }
  780 
  781 static int
  782 linux_set_oss_version(struct thread *td, int oss_version)
  783 {
  784         struct prison *pr;
  785         struct linux_prison *lpr;
  786 
  787         LIN_SDT_PROBE2(mib, linux_set_oss_version, entry, td, oss_version);
  788 
  789         lpr = linux_find_prison(td->td_ucred->cr_prison, &pr);
  790         lpr->pr_oss_version = oss_version;
  791         mtx_unlock(&pr->pr_mtx);
  792 
  793         LIN_SDT_PROBE1(mib, linux_set_oss_version, return, 0);
  794         return (0);
  795 }
  796 
  797 #if defined(DEBUG) || defined(KTR)
  798 /* XXX: can be removed when every ldebug(...) and KTR stuff are removed. */
  799 
  800 u_char linux_debug_map[howmany(LINUX_SYS_MAXSYSCALL, sizeof(u_char))];
  801 
  802 static int
  803 linux_debug(int syscall, int toggle, int global)
  804 {
  805 
  806         if (global) {
  807                 char c = toggle ? 0 : 0xff;
  808 
  809                 memset(linux_debug_map, c, sizeof(linux_debug_map));
  810                 return (0);
  811         }
  812         if (syscall < 0 || syscall >= LINUX_SYS_MAXSYSCALL)
  813                 return (EINVAL);
  814         if (toggle)
  815                 clrbit(linux_debug_map, syscall);
  816         else
  817                 setbit(linux_debug_map, syscall);
  818         return (0);
  819 }
  820 
  821 /*
  822  * Usage: sysctl linux.debug=<syscall_nr>.<0/1>
  823  *
  824  *    E.g.: sysctl linux.debug=21.0
  825  *
  826  * As a special case, syscall "all" will apply to all syscalls globally.
  827  */
  828 #define LINUX_MAX_DEBUGSTR      16
  829 static int
  830 linux_sysctl_debug(SYSCTL_HANDLER_ARGS)
  831 {
  832         char value[LINUX_MAX_DEBUGSTR], *p;
  833         int error, sysc, toggle;
  834         int global = 0;
  835 
  836         value[0] = '\0';
  837         error = sysctl_handle_string(oidp, value, LINUX_MAX_DEBUGSTR, req);
  838         if (error || req->newptr == NULL)
  839                 return (error);
  840         for (p = value; *p != '\0' && *p != '.'; p++);
  841         if (*p == '\0')
  842                 return (EINVAL);
  843         *p++ = '\0';
  844         sysc = strtol(value, NULL, 0);
  845         toggle = strtol(p, NULL, 0);
  846         if (strcmp(value, "all") == 0)
  847                 global = 1;
  848         error = linux_debug(sysc, toggle, global);
  849         return (error);
  850 }
  851 
  852 SYSCTL_PROC(_compat_linux, OID_AUTO, debug,
  853             CTLTYPE_STRING | CTLFLAG_RW,
  854             0, 0, linux_sysctl_debug, "A",
  855             "Linux debugging control");
  856 
  857 #endif /* DEBUG || KTR */

Cache object: 70393618f181b34b2bc0efc3bac59210


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