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/contrib/openzfs/module/os/freebsd/spl/spl_zone.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) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
    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 AUTHORS 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 AUTHORS 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 <sys/types.h>
   31 #include <sys/param.h>
   32 #include <sys/kernel.h>
   33 #include <sys/systm.h>
   34 #include <sys/proc.h>
   35 #include <sys/lock.h>
   36 #include <sys/mutex.h>
   37 #include <sys/sx.h>
   38 #include <sys/malloc.h>
   39 #include <sys/queue.h>
   40 #include <sys/jail.h>
   41 #include <sys/osd.h>
   42 #include <sys/priv.h>
   43 #include <sys/zone.h>
   44 
   45 #include <sys/policy.h>
   46 
   47 static MALLOC_DEFINE(M_ZONES, "zones_data", "Zones data");
   48 
   49 /*
   50  * Structure to record list of ZFS datasets exported to a zone.
   51  */
   52 typedef struct zone_dataset {
   53         LIST_ENTRY(zone_dataset) zd_next;
   54         char    zd_dataset[0];
   55 } zone_dataset_t;
   56 
   57 LIST_HEAD(zone_dataset_head, zone_dataset);
   58 
   59 static int zone_slot;
   60 
   61 int
   62 zone_dataset_attach(struct ucred *cred, const char *dataset, int jailid)
   63 {
   64         struct zone_dataset_head *head;
   65         zone_dataset_t *zd, *zd2;
   66         struct prison *pr;
   67         int dofree, error;
   68 
   69         if ((error = spl_priv_check_cred(cred, PRIV_ZFS_JAIL)) != 0)
   70                 return (error);
   71 
   72         /* Allocate memory before we grab prison's mutex. */
   73         zd = malloc(sizeof (*zd) + strlen(dataset) + 1, M_ZONES, M_WAITOK);
   74 
   75         sx_slock(&allprison_lock);
   76         pr = prison_find(jailid);       /* Locks &pr->pr_mtx. */
   77         sx_sunlock(&allprison_lock);
   78         if (pr == NULL) {
   79                 free(zd, M_ZONES);
   80                 return (ENOENT);
   81         }
   82 
   83         head = osd_jail_get(pr, zone_slot);
   84         if (head != NULL) {
   85                 dofree = 0;
   86                 LIST_FOREACH(zd2, head, zd_next) {
   87                         if (strcmp(dataset, zd2->zd_dataset) == 0) {
   88                                 free(zd, M_ZONES);
   89                                 error = EEXIST;
   90                                 goto end;
   91                         }
   92                 }
   93         } else {
   94                 dofree = 1;
   95                 prison_hold_locked(pr);
   96                 mtx_unlock(&pr->pr_mtx);
   97                 head = malloc(sizeof (*head), M_ZONES, M_WAITOK);
   98                 LIST_INIT(head);
   99                 mtx_lock(&pr->pr_mtx);
  100                 error = osd_jail_set(pr, zone_slot, head);
  101                 KASSERT(error == 0, ("osd_jail_set() failed (error=%d)",
  102                     error));
  103         }
  104         strcpy(zd->zd_dataset, dataset);
  105         LIST_INSERT_HEAD(head, zd, zd_next);
  106 end:
  107         if (dofree)
  108                 prison_free_locked(pr);
  109         else
  110                 mtx_unlock(&pr->pr_mtx);
  111         return (error);
  112 }
  113 
  114 int
  115 zone_dataset_detach(struct ucred *cred, const char *dataset, int jailid)
  116 {
  117         struct zone_dataset_head *head;
  118         zone_dataset_t *zd;
  119         struct prison *pr;
  120         int error;
  121 
  122         if ((error = spl_priv_check_cred(cred, PRIV_ZFS_JAIL)) != 0)
  123                 return (error);
  124 
  125         sx_slock(&allprison_lock);
  126         pr = prison_find(jailid);
  127         sx_sunlock(&allprison_lock);
  128         if (pr == NULL)
  129                 return (ENOENT);
  130         head = osd_jail_get(pr, zone_slot);
  131         if (head == NULL) {
  132                 error = ENOENT;
  133                 goto end;
  134         }
  135         LIST_FOREACH(zd, head, zd_next) {
  136                 if (strcmp(dataset, zd->zd_dataset) == 0)
  137                         break;
  138         }
  139         if (zd == NULL)
  140                 error = ENOENT;
  141         else {
  142                 LIST_REMOVE(zd, zd_next);
  143                 free(zd, M_ZONES);
  144                 if (LIST_EMPTY(head))
  145                         osd_jail_del(pr, zone_slot);
  146                 error = 0;
  147         }
  148 end:
  149         mtx_unlock(&pr->pr_mtx);
  150         return (error);
  151 }
  152 
  153 /*
  154  * Returns true if the named dataset is visible in the current zone.
  155  * The 'write' parameter is set to 1 if the dataset is also writable.
  156  */
  157 int
  158 zone_dataset_visible(const char *dataset, int *write)
  159 {
  160         struct zone_dataset_head *head;
  161         zone_dataset_t *zd;
  162         struct prison *pr;
  163         size_t len;
  164         int ret = 0;
  165 
  166         if (dataset[0] == '\0')
  167                 return (0);
  168         if (INGLOBALZONE(curproc)) {
  169                 if (write != NULL)
  170                         *write = 1;
  171                 return (1);
  172         }
  173         pr = curthread->td_ucred->cr_prison;
  174         mtx_lock(&pr->pr_mtx);
  175         head = osd_jail_get(pr, zone_slot);
  176         if (head == NULL)
  177                 goto end;
  178 
  179         /*
  180          * Walk the list once, looking for datasets which match exactly, or
  181          * specify a dataset underneath an exported dataset.  If found, return
  182          * true and note that it is writable.
  183          */
  184         LIST_FOREACH(zd, head, zd_next) {
  185                 len = strlen(zd->zd_dataset);
  186                 if (strlen(dataset) >= len &&
  187                     memcmp(dataset, zd->zd_dataset, len) == 0 &&
  188                     (dataset[len] == '\0' || dataset[len] == '/' ||
  189                     dataset[len] == '@')) {
  190                         if (write)
  191                                 *write = 1;
  192                         ret = 1;
  193                         goto end;
  194                 }
  195         }
  196 
  197         /*
  198          * Walk the list a second time, searching for datasets which are parents
  199          * of exported datasets.  These should be visible, but read-only.
  200          *
  201          * Note that we also have to support forms such as 'pool/dataset/', with
  202          * a trailing slash.
  203          */
  204         LIST_FOREACH(zd, head, zd_next) {
  205                 len = strlen(dataset);
  206                 if (dataset[len - 1] == '/')
  207                         len--;  /* Ignore trailing slash */
  208                 if (len < strlen(zd->zd_dataset) &&
  209                     memcmp(dataset, zd->zd_dataset, len) == 0 &&
  210                     zd->zd_dataset[len] == '/') {
  211                         if (write)
  212                                 *write = 0;
  213                         ret = 1;
  214                         goto end;
  215                 }
  216         }
  217 end:
  218         mtx_unlock(&pr->pr_mtx);
  219         return (ret);
  220 }
  221 
  222 static void
  223 zone_destroy(void *arg)
  224 {
  225         struct zone_dataset_head *head;
  226         zone_dataset_t *zd;
  227 
  228         head = arg;
  229         while ((zd = LIST_FIRST(head)) != NULL) {
  230                 LIST_REMOVE(zd, zd_next);
  231                 free(zd, M_ZONES);
  232         }
  233         free(head, M_ZONES);
  234 }
  235 
  236 uint32_t
  237 zone_get_hostid(void *ptr)
  238 {
  239 
  240         KASSERT(ptr == NULL, ("only NULL pointer supported in %s", __func__));
  241 
  242         return ((uint32_t)curthread->td_ucred->cr_prison->pr_hostid);
  243 }
  244 
  245 static void
  246 zone_sysinit(void *arg __unused)
  247 {
  248 
  249         zone_slot = osd_jail_register(zone_destroy, NULL);
  250 }
  251 
  252 static void
  253 zone_sysuninit(void *arg __unused)
  254 {
  255 
  256         osd_jail_deregister(zone_slot);
  257 }
  258 
  259 SYSINIT(zone_sysinit, SI_SUB_DRIVERS, SI_ORDER_ANY, zone_sysinit, NULL);
  260 SYSUNINIT(zone_sysuninit, SI_SUB_DRIVERS, SI_ORDER_ANY, zone_sysuninit, NULL);

Cache object: 91a61f85f903bdc5f5338bd5ec23d5ba


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