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/dev/vmware/vmci/vmci_resource.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) 2018 VMware, Inc.
    3  *
    4  * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)
    5  */
    6 
    7 /* Implementation of the VMCI Resource Access Control API. */
    8 
    9 #include <sys/cdefs.h>
   10 __FBSDID("$FreeBSD$");
   11 
   12 #include "vmci_driver.h"
   13 #include "vmci_kernel_defs.h"
   14 #include "vmci_resource.h"
   15 
   16 #define LGPFX   "vmci_resource: "
   17 
   18 /* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */
   19 static uint32_t resource_id = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
   20 static vmci_lock resource_id_lock;
   21 
   22 static void     vmci_resource_do_remove(struct vmci_resource *resource);
   23 
   24 static struct vmci_hashtable *resource_table = NULL;
   25 
   26 /* Public Resource Access Control API. */
   27 
   28 /*
   29  *------------------------------------------------------------------------------
   30  *
   31  * vmci_resource_init --
   32  *
   33  *     Initializes the VMCI Resource Access Control API. Creates a hashtable to
   34  *     hold all resources, and registers vectors and callbacks for hypercalls.
   35  *
   36  * Results:
   37  *     None.
   38  *
   39  * Side effects:
   40  *     None.
   41  *
   42  *------------------------------------------------------------------------------
   43  */
   44 
   45 int
   46 vmci_resource_init(void)
   47 {
   48         int err;
   49 
   50         err = vmci_init_lock(&resource_id_lock, "VMCI RID lock");
   51         if (err < VMCI_SUCCESS)
   52                 return (err);
   53 
   54         resource_table = vmci_hashtable_create(128);
   55         if (resource_table == NULL) {
   56                 VMCI_LOG_WARNING((LGPFX"Failed creating a resource hash table "
   57                     "for VMCI.\n"));
   58                 vmci_cleanup_lock(&resource_id_lock);
   59                 return (VMCI_ERROR_NO_MEM);
   60         }
   61 
   62         return (VMCI_SUCCESS);
   63 }
   64 
   65 /*
   66  *------------------------------------------------------------------------------
   67  *
   68  * vmci_resource_exit --
   69  *
   70  *      Cleans up resources.
   71  *
   72  * Results:
   73  *      None.
   74  *
   75  * Side effects:
   76  *      None.
   77  *
   78  *------------------------------------------------------------------------------
   79  */
   80 
   81 void
   82 vmci_resource_exit(void)
   83 {
   84 
   85         /* Cleanup resources.*/
   86         vmci_cleanup_lock(&resource_id_lock);
   87 
   88         if (resource_table)
   89                 vmci_hashtable_destroy(resource_table);
   90 }
   91 
   92 /*
   93  *------------------------------------------------------------------------------
   94  *
   95  *  vmci_resource_get_id --
   96  *
   97  *      Return resource ID. The first VMCI_RESERVED_RESOURCE_ID_MAX are reserved
   98  *      so we start from its value + 1.
   99  *
  100  *  Result:
  101  *      VMCI resource id on success, VMCI_INVALID_ID on failure.
  102  *
  103  *  Side effects:
  104  *      None.
  105  *
  106  *
  107  *------------------------------------------------------------------------------
  108  */
  109 
  110 vmci_id
  111 vmci_resource_get_id(vmci_id context_id)
  112 {
  113         vmci_id current_rid;
  114         vmci_id old_rid;
  115         bool found_rid;
  116 
  117         old_rid = resource_id;
  118         found_rid = false;
  119 
  120         /*
  121          * Generate a unique resource ID. Keep on trying until we wrap around
  122          * in the RID space.
  123          */
  124         ASSERT(old_rid > VMCI_RESERVED_RESOURCE_ID_MAX);
  125 
  126         do {
  127                 struct vmci_handle handle;
  128 
  129                 vmci_grab_lock(&resource_id_lock);
  130                 current_rid = resource_id;
  131                 handle = VMCI_MAKE_HANDLE(context_id, current_rid);
  132                 resource_id++;
  133                 if (UNLIKELY(resource_id == VMCI_INVALID_ID)) {
  134                         /* Skip the reserved rids. */
  135                         resource_id = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
  136                 }
  137                 vmci_release_lock(&resource_id_lock);
  138                 found_rid = !vmci_hashtable_entry_exists(resource_table,
  139                     handle);
  140         } while (!found_rid && resource_id != old_rid);
  141 
  142         if (UNLIKELY(!found_rid))
  143                 return (VMCI_INVALID_ID);
  144         else
  145                 return (current_rid);
  146 }
  147 
  148 /*
  149  *------------------------------------------------------------------------------
  150  *
  151  * vmci_resource_add --
  152  *
  153  *     Add resource to hashtable.
  154  *
  155  * Results:
  156  *     VMCI_SUCCESS if successful, error code if not.
  157  *
  158  * Side effects:
  159  *     None.
  160  *
  161  *------------------------------------------------------------------------------
  162  */
  163 
  164 int
  165 vmci_resource_add(struct vmci_resource *resource,
  166     vmci_resource_type resource_type, struct vmci_handle resource_handle,
  167     vmci_resource_free_cb container_free_cb, void *container_object)
  168 {
  169         int result;
  170 
  171         ASSERT(resource);
  172 
  173         if (VMCI_HANDLE_EQUAL(resource_handle, VMCI_INVALID_HANDLE)) {
  174                 VMCI_LOG_DEBUG(LGPFX"Invalid argument resource "
  175                     "(handle=0x%x:0x%x).\n", resource_handle.context,
  176                     resource_handle.resource);
  177                 return (VMCI_ERROR_INVALID_ARGS);
  178         }
  179 
  180         vmci_hashtable_init_entry(&resource->hash_entry, resource_handle);
  181         resource->type = resource_type;
  182         resource->container_free_cb = container_free_cb;
  183         resource->container_object = container_object;
  184 
  185         /* Add resource to hashtable. */
  186         result = vmci_hashtable_add_entry(resource_table,
  187             &resource->hash_entry);
  188         if (result != VMCI_SUCCESS) {
  189                 VMCI_LOG_DEBUG(LGPFX"Failed to add entry to hash table "
  190                     "(result=%d).\n", result);
  191                 return (result);
  192         }
  193 
  194         return (result);
  195 }
  196 
  197 /*
  198  *------------------------------------------------------------------------------
  199  *
  200  * vmci_resource_remove --
  201  *
  202  *     Remove resource from hashtable.
  203  *
  204  * Results:
  205  *     None.
  206  *
  207  * Side effects:
  208  *     None.
  209  *
  210  *------------------------------------------------------------------------------
  211  */
  212 
  213 void
  214 vmci_resource_remove(struct vmci_handle resource_handle,
  215     vmci_resource_type resource_type)
  216 {
  217         struct vmci_resource *resource;
  218 
  219         resource = vmci_resource_get(resource_handle, resource_type);
  220         if (resource == NULL)
  221                 return;
  222 
  223         /* Remove resource from hashtable. */
  224         vmci_hashtable_remove_entry(resource_table, &resource->hash_entry);
  225 
  226         vmci_resource_release(resource);
  227         /* resource could be freed by now. */
  228 }
  229 
  230 /*
  231  *------------------------------------------------------------------------------
  232  *
  233  * vmci_resource_get --
  234  *
  235  *     Get resource from hashtable.
  236  *
  237  * Results:
  238  *     Resource if successful. Otherwise NULL.
  239  *
  240  * Side effects:
  241  *     None.
  242  *
  243  *------------------------------------------------------------------------------
  244  */
  245 
  246 struct vmci_resource *
  247 vmci_resource_get(struct vmci_handle resource_handle,
  248     vmci_resource_type resource_type)
  249 {
  250         struct vmci_hash_entry *entry;
  251         struct vmci_resource *resource;
  252 
  253         entry = vmci_hashtable_get_entry(resource_table, resource_handle);
  254         if (entry == NULL)
  255                 return (NULL);
  256         resource = RESOURCE_CONTAINER(entry, struct vmci_resource, hash_entry);
  257         if (resource_type == VMCI_RESOURCE_TYPE_ANY ||
  258                 resource->type == resource_type) {
  259                 return (resource);
  260         }
  261         vmci_hashtable_release_entry(resource_table, entry);
  262         return (NULL);
  263 }
  264 
  265 /*
  266  *------------------------------------------------------------------------------
  267  *
  268  * vmci_resource_hold --
  269  *
  270  *     Hold the given resource. This will hold the hashtable entry. This is like
  271  *     doing a Get() but without having to lookup the resource by handle.
  272  *
  273  * Results:
  274  *     None.
  275  *
  276  * Side effects:
  277  *     None.
  278  *
  279  *------------------------------------------------------------------------------
  280  */
  281 
  282 void
  283 vmci_resource_hold(struct vmci_resource *resource)
  284 {
  285 
  286         ASSERT(resource);
  287         vmci_hashtable_hold_entry(resource_table, &resource->hash_entry);
  288 }
  289 
  290 /*
  291  *------------------------------------------------------------------------------
  292  *
  293  * vmci_resource_do_remove --
  294  *
  295  *     Deallocates data structures associated with the given resource and
  296  *     invoke any call back registered for the resource.
  297  *
  298  * Results:
  299  *     None.
  300  *
  301  * Side effects:
  302  *     May deallocate memory and invoke a callback for the removed resource.
  303  *
  304  *------------------------------------------------------------------------------
  305  */
  306 
  307 static void inline
  308 vmci_resource_do_remove(struct vmci_resource *resource)
  309 {
  310 
  311         ASSERT(resource);
  312 
  313         if (resource->container_free_cb) {
  314                 resource->container_free_cb(resource->container_object);
  315                 /* Resource has been freed don't dereference it. */
  316         }
  317 }
  318 
  319 /*
  320  *------------------------------------------------------------------------------
  321  *
  322  * vmci_resource_release --
  323  *
  324  * Results:
  325  *     None.
  326  *
  327  * Side effects:
  328  *     Resource's containerFreeCB will get called if last reference.
  329  *
  330  *------------------------------------------------------------------------------
  331  */
  332 
  333 int
  334 vmci_resource_release(struct vmci_resource *resource)
  335 {
  336         int result;
  337 
  338         ASSERT(resource);
  339 
  340         result = vmci_hashtable_release_entry(resource_table,
  341             &resource->hash_entry);
  342         if (result == VMCI_SUCCESS_ENTRY_DEAD)
  343                 vmci_resource_do_remove(resource);
  344 
  345         /*
  346          * We propagate the information back to caller in case it wants to know
  347          * whether entry was freed.
  348          */
  349         return (result);
  350 }
  351 
  352 /*
  353  *------------------------------------------------------------------------------
  354  *
  355  * vmci_resource_handle --
  356  *
  357  *     Get the handle for the given resource.
  358  *
  359  * Results:
  360  *     The resource's associated handle.
  361  *
  362  * Side effects:
  363  *     None.
  364  *
  365  *------------------------------------------------------------------------------
  366  */
  367 
  368 struct vmci_handle
  369 vmci_resource_handle(struct vmci_resource *resource)
  370 {
  371 
  372         ASSERT(resource);
  373         return (resource->hash_entry.handle);
  374 }
  375 
  376 /*
  377  *------------------------------------------------------------------------------
  378  *
  379  * vmci_resource_sync --
  380  *
  381  *     Use this as a synchronization point when setting globals, for example,
  382  *     during device shutdown.
  383  *
  384  * Results:
  385  *     None.
  386  *
  387  * Side effects:
  388  *     None.
  389  *
  390  *------------------------------------------------------------------------------
  391  */
  392 
  393 void
  394 vmci_resource_sync(void)
  395 {
  396 
  397         vmci_hashtable_sync(resource_table);
  398 }

Cache object: ebd490384a40881594df3cb2f265a188


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