Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 05913fe7 in mainline


Ignore:
Timestamp:
2017-10-09T22:18:09Z (4 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master
Children:
2bdf92a5
Parents:
e02bfb4
Message:

Allow virtually unlimited number of capabilities per task

Location:
kernel/generic
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/include/cap/cap.h

    re02bfb4 r05913fe7  
    3838#include <typedefs.h>
    3939#include <adt/list.h>
     40#include <adt/hash.h>
     41#include <adt/hash_table.h>
     42#include <lib/ra.h>
    4043#include <synch/mutex.h>
    4144#include <atomic.h>
    42 
    43 #define MAX_CAPS  64
    4445
    4546typedef int cap_handle_t;
     
    8990        cap_state_t state;
    9091
     92        struct task *task;
    9193        cap_handle_t handle;
    9294
    9395        /* Link to the task's capabilities of the same kobject type. */
    94         link_t link;
     96        link_t type_link;
     97
     98        ht_link_t caps_link;
    9599
    96100        /* The underlying kernel object. */
     
    103107        list_t type_list[KOBJECT_TYPE_MAX];
    104108
    105         cap_t *caps;
     109        hash_table_t caps;
     110        ra_arena_t *handles;
    106111} cap_info_t;
    107112
     
    112117    bool (*)(cap_t *, void *), void *);
    113118
    114 extern void cap_initialize(cap_t *, cap_handle_t);
    115119extern cap_handle_t cap_alloc(struct task *);
    116120extern void cap_publish(struct task *, cap_handle_t, kobject_t *);
  • kernel/generic/src/cap/cap.c

    re02bfb4 r05913fe7  
    7979#include <adt/list.h>
    8080
     81#include <stdint.h>
     82
     83#define MAX_CAPS        INT_MAX
     84
    8185static kobject_t *cap_unpublish_locked(task_t *, cap_handle_t, kobject_type_t);
    8286
    83 /** Initialize capability and associate it with its handle
    84  *
    85  * @param cap     Address of the capability.
    86  * @param handle  Capability handle.
    87  */
    88 void cap_initialize(cap_t *cap, cap_handle_t handle)
    89 {
    90         cap->state = CAP_STATE_FREE;
    91         cap->handle = handle;
    92         link_initialize(&cap->link);
    93 }
     87static size_t caps_hash(const ht_link_t *item)
     88{
     89        cap_t *cap = hash_table_get_inst(item, cap_t, caps_link);
     90        return hash_mix(cap->handle);
     91}
     92
     93static size_t caps_key_hash(void *key)
     94{
     95        cap_handle_t *handle = (cap_handle_t *) key;
     96        return hash_mix(*handle);
     97}
     98
     99static bool caps_key_equal(void *key, const ht_link_t *item)
     100{
     101        cap_handle_t *handle = (cap_handle_t *) key;
     102        cap_t *cap = hash_table_get_inst(item, cap_t, caps_link);
     103        return *handle == cap->handle;
     104}
     105
     106static hash_table_ops_t caps_ops = {
     107        .hash = caps_hash,
     108        .key_hash = caps_key_hash,
     109        .key_equal = caps_key_equal
     110};
    94111
    95112/** Allocate the capability info structure
     
    100117{
    101118        task->cap_info = (cap_info_t *) malloc(sizeof(cap_info_t), 0);
    102         task->cap_info->caps = malloc(sizeof(cap_t) * MAX_CAPS, 0);
     119        task->cap_info->handles = ra_arena_create();
     120        // FIXME: allow caps_task_alloc() to fail
     121        assert(task->cap_info->handles);
     122        bool success = ra_span_add(task->cap_info->handles, 0, MAX_CAPS);
     123        // FIXME: allow caps_task_alloc() to fail
     124        assert(success);
     125        success = hash_table_create(&task->cap_info->caps, 0, 0, &caps_ops);
     126        // FIXME: allow caps_task_alloc() to fail
     127        assert(success);
    103128}
    104129
     
    113138        for (kobject_type_t t = 0; t < KOBJECT_TYPE_MAX; t++)
    114139                list_initialize(&task->cap_info->type_list[t]);
    115 
    116         for (cap_handle_t h = 0; h < MAX_CAPS; h++)
    117                 cap_initialize(&task->cap_info->caps[h], h);
    118140}
    119141
     
    124146void caps_task_free(task_t *task)
    125147{
    126         free(task->cap_info->caps);
     148        hash_table_destroy(&task->cap_info->caps);
     149        ra_arena_destroy(task->cap_info->handles);
    127150        free(task->cap_info);
    128151}
     
    146169        mutex_lock(&task->cap_info->lock);
    147170        list_foreach_safe(task->cap_info->type_list[type], cur, next) {
    148                 cap_t *cap = list_get_instance(cur, cap_t, link);
     171                cap_t *cap = list_get_instance(cur, cap_t, type_link);
    149172                done = cb(cap, arg);
    150173                if (!done)
     
    156179}
    157180
     181/** Initialize capability and associate it with its handle
     182 *
     183 * @param cap     Address of the capability.
     184 * @param task    Backling to the owning task.
     185 * @param handle  Capability handle.
     186 */
     187static void cap_initialize(cap_t *cap, task_t *task, cap_handle_t handle)
     188{
     189        cap->state = CAP_STATE_FREE;
     190        cap->task = task;
     191        cap->handle = handle;
     192        link_initialize(&cap->type_link);
     193}
     194
    158195/** Get capability using capability handle
    159196 *
     
    171208        if ((handle < 0) || (handle >= MAX_CAPS))
    172209                return NULL;
    173         if (task->cap_info->caps[handle].state != state)
     210        ht_link_t *link = hash_table_find(&task->cap_info->caps, &handle);
     211        if (!link)
    174212                return NULL;
    175         return &task->cap_info->caps[handle];
     213        cap_t *cap = hash_table_get_inst(link, cap_t, caps_link);
     214        if (cap->state != state)
     215                return NULL;
     216        return cap;
     217}
     218
     219static bool cap_reclaimer(ht_link_t *link, void *arg)
     220{
     221        cap_t **result = (cap_t **) arg;
     222        cap_t *cap = hash_table_get_inst(link, cap_t, caps_link);
     223
     224        if (cap->state == CAP_STATE_PUBLISHED && cap->kobject->ops->reclaim &&
     225            cap->kobject->ops->reclaim(cap->kobject)) {
     226                kobject_t *kobj = cap_unpublish_locked(cap->task, cap->handle,
     227                    cap->kobject->type);
     228                kobject_put(kobj);
     229                cap_initialize(cap, cap->task, cap->handle);
     230                *result = cap;
     231                return false;
     232        }
     233
     234        return true;
    176235}
    177236
     
    185244cap_handle_t cap_alloc(task_t *task)
    186245{
    187         mutex_lock(&task->cap_info->lock);
    188         for (cap_handle_t handle = 0; handle < MAX_CAPS; handle++) {
    189                 cap_t *cap = &task->cap_info->caps[handle];
    190                 /* See if the capability should be garbage-collected */
    191                 if (cap->state == CAP_STATE_PUBLISHED &&
    192                     cap->kobject->ops->reclaim &&
    193                     cap->kobject->ops->reclaim(cap->kobject)) {
    194                         kobject_t *kobj = cap_unpublish_locked(task, handle,
    195                             cap->kobject->type);
    196                         kobject_put(kobj);
    197                         cap_initialize(&task->cap_info->caps[handle], handle);
     246        cap_t *cap = NULL;
     247        cap_handle_t handle;
     248
     249        /*
     250         * First of all, see if we can reclaim a capability. Note that this
     251         * feature is only temporary and capability reclamaition will eventually
     252         * be phased out.
     253         */
     254        mutex_lock(&task->cap_info->lock);
     255        hash_table_apply(&task->cap_info->caps, cap_reclaimer, &cap);
     256
     257        /*
     258         * If we don't have a capability by now, try to allocate a new one.
     259         */
     260        if (!cap) {
     261                cap = malloc(sizeof(cap_t), 0);
     262                if (!cap) {
     263                        mutex_unlock(&task->cap_info->lock);
     264                        return ENOMEM;
    198265                }
    199                 if (cap->state == CAP_STATE_FREE) {
    200                         cap->state = CAP_STATE_ALLOCATED;
     266                uintptr_t hbase;
     267                if (!ra_alloc(task->cap_info->handles, 1, 1, &hbase)) {
     268                        free(cap);
    201269                        mutex_unlock(&task->cap_info->lock);
    202                         return handle;
     270                        return ENOMEM;
    203271                }
    204         }
    205         mutex_unlock(&task->cap_info->lock);
    206 
    207         return ELIMIT;
     272                cap_initialize(cap, task, (cap_handle_t) hbase);
     273                hash_table_insert(&task->cap_info->caps, &cap->caps_link);
     274        }
     275
     276        cap->state = CAP_STATE_ALLOCATED;
     277        handle = cap->handle;
     278        mutex_unlock(&task->cap_info->lock);
     279
     280        return handle;
    208281}
    209282
     
    227300        /* Hand over kobj's reference to cap */
    228301        cap->kobject = kobj;
    229         list_append(&cap->link, &task->cap_info->type_list[kobj->type]);
     302        list_append(&cap->type_link, &task->cap_info->type_list[kobj->type]);
    230303        mutex_unlock(&task->cap_info->lock);
    231304}
     
    242315                        kobj = cap->kobject;
    243316                        cap->kobject = NULL;
    244                         list_remove(&cap->link);
     317                        list_remove(&cap->type_link);
    245318                        cap->state = CAP_STATE_ALLOCATED;
    246319                }
     
    281354        assert(handle >= 0);
    282355        assert(handle < MAX_CAPS);
    283         assert(task->cap_info->caps[handle].state == CAP_STATE_ALLOCATED);
    284 
    285         mutex_lock(&task->cap_info->lock);
    286         cap_initialize(&task->cap_info->caps[handle], handle);
     356
     357        mutex_lock(&task->cap_info->lock);
     358        cap_t *cap = cap_get(task, handle, CAP_STATE_ALLOCATED);
     359
     360        assert(cap);
     361
     362        hash_table_remove_item(&task->cap_info->caps, &cap->caps_link);
     363        ra_free(task->cap_info->handles, handle, 1);
     364        free(cap);
    287365        mutex_unlock(&task->cap_info->lock);
    288366}
Note: See TracChangeset for help on using the changeset viewer.