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

Changeset 83b6ba9f in mainline


Ignore:
Timestamp:
2014-02-18T00:18:48Z (8 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master
Children:
8aaf9dc
Parents:
89dcf93
Message:

Support for AS area backend shared data.

  • share_info_t is now created for every new address space area.
  • share_info_t was extended to point to AS area backend shared data.
  • AS area backend may decide to define create/destroy_shared_data() methods.
  • Anonymous backend_phys frames are now freed from phys_destroy_shared_data().
  • Fixed one case of forgotten locked mutex.
Location:
kernel/generic
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/include/mm/as.h

    r89dcf93 r83b6ba9f  
    140140        /** This structure can be deallocated if refcount drops to 0. */
    141141        size_t refcount;
    142        
     142        /** True if the area has been ever shared. */
     143        bool shared;
     144
    143145        /**
    144146         * B+tree containing complete map of anonymous pages of the shared area.
    145147         */
    146148        btree_t pagemap;
     149
     150        /** Address space area backend. */
     151        struct mem_backend *backend;
     152        /** Address space area shared data. */
     153        void *backend_shared_data;
    147154} share_info_t;
    148155
     
    227234        int (* page_fault)(as_area_t *, uintptr_t, pf_access_t);
    228235        void (* frame_free)(as_area_t *, uintptr_t, uintptr_t);
     236
     237        bool (* create_shared_data)(as_area_t *);
     238        void (* destroy_shared_data)(void *);
    229239} mem_backend_t;
    230240
  • kernel/generic/src/mm/as.c

    r89dcf93 r83b6ba9f  
    520520}
    521521
     522/** Remove reference to address space area share info.
     523 *
     524 * If the reference count drops to 0, the sh_info is deallocated.
     525 *
     526 * @param sh_info Pointer to address space area share info.
     527 *
     528 */
     529NO_TRACE static void sh_info_remove_reference(share_info_t *sh_info)
     530{
     531        bool dealloc = false;
     532       
     533        mutex_lock(&sh_info->lock);
     534        ASSERT(sh_info->refcount);
     535       
     536        if (--sh_info->refcount == 0) {
     537                dealloc = true;
     538               
     539                /*
     540                 * Now walk carefully the pagemap B+tree and free/remove
     541                 * reference from all frames found there.
     542                 */
     543                list_foreach(sh_info->pagemap.leaf_list, leaf_link,
     544                    btree_node_t, node) {
     545                        btree_key_t i;
     546                       
     547                        for (i = 0; i < node->keys; i++)
     548                                frame_free((uintptr_t) node->value[i], 1);
     549                }
     550               
     551        }
     552        mutex_unlock(&sh_info->lock);
     553       
     554        if (dealloc) {
     555                if (sh_info->backend && sh_info->backend->destroy_shared_data) {
     556                        sh_info->backend->destroy_shared_data(
     557                            sh_info->backend_shared_data);
     558                }
     559                btree_destroy(&sh_info->pagemap);
     560                free(sh_info);
     561        }
     562}
     563
     564
    522565/** Create address space area of common attributes.
    523566 *
     
    566609        }
    567610
    568         if (overflows_into_positive(*base, size))
     611        if (overflows_into_positive(*base, size)) {
     612                mutex_unlock(&as->lock);
    569613                return NULL;
     614        }
    570615
    571616        if (!check_area_conflicts(as, *base, pages, guarded, NULL)) {
     
    584629        area->resident = 0;
    585630        area->base = *base;
     631        area->backend = backend;
    586632        area->sh_info = NULL;
    587         area->backend = backend;
    588633       
    589634        if (backend_data)
     
    591636        else
    592637                memsetb(&area->backend_data, sizeof(area->backend_data), 0);
    593        
     638
     639        share_info_t *si = NULL;
     640
     641        /*
     642         * Create the sharing info structure.
     643         * We do this in advance for every new area, even if it is not going
     644         * to be shared.
     645         */
     646        if (!(attrs & AS_AREA_ATTR_PARTIAL)) {
     647                si = (share_info_t *) malloc(sizeof(share_info_t), 0);
     648                mutex_initialize(&si->lock, MUTEX_PASSIVE);
     649                si->refcount = 1;
     650                si->shared = false;
     651                si->backend_shared_data = NULL;
     652                si->backend = backend;
     653                btree_create(&si->pagemap);
     654
     655                area->sh_info = si;
     656       
     657                if (area->backend && area->backend->create_shared_data) {
     658                        if (!area->backend->create_shared_data(area)) {
     659                                free(area);
     660                                mutex_unlock(&as->lock);
     661                                sh_info_remove_reference(si);
     662                                return NULL;
     663                        }
     664                }
     665        }
     666
    594667        if (area->backend && area->backend->create) {
    595668                if (!area->backend->create(area)) {
    596669                        free(area);
    597670                        mutex_unlock(&as->lock);
     671                        if (!(attrs & AS_AREA_ATTR_PARTIAL))
     672                                sh_info_remove_reference(si);
    598673                        return NULL;
    599674                }
    600675        }
    601        
     676
    602677        btree_create(&area->used_space);
    603678        btree_insert(&as->as_area_btree, *base, (void *) area,
     
    709784        }
    710785       
    711         if (area->sh_info) {
     786        mutex_lock(&area->sh_info->lock);
     787        if (area->sh_info->shared) {
    712788                /*
    713789                 * Remapping of shared address space areas
    714790                 * is not supported.
    715791                 */
     792                mutex_unlock(&area->sh_info->lock);
    716793                mutex_unlock(&area->lock);
    717794                mutex_unlock(&as->lock);
    718795                return ENOTSUP;
    719796        }
     797        mutex_unlock(&area->sh_info->lock);
    720798       
    721799        size_t pages = SIZE2FRAMES((address - area->base) + size);
     
    881959}
    882960
    883 /** Remove reference to address space area share info.
    884  *
    885  * If the reference count drops to 0, the sh_info is deallocated.
    886  *
    887  * @param sh_info Pointer to address space area share info.
    888  *
    889  */
    890 NO_TRACE static void sh_info_remove_reference(share_info_t *sh_info)
    891 {
    892         bool dealloc = false;
    893        
    894         mutex_lock(&sh_info->lock);
    895         ASSERT(sh_info->refcount);
    896        
    897         if (--sh_info->refcount == 0) {
    898                 dealloc = true;
    899                
    900                 /*
    901                  * Now walk carefully the pagemap B+tree and free/remove
    902                  * reference from all frames found there.
    903                  */
    904                 list_foreach(sh_info->pagemap.leaf_list, leaf_link,
    905                     btree_node_t, node) {
    906                         btree_key_t i;
    907                        
    908                         for (i = 0; i < node->keys; i++)
    909                                 frame_free((uintptr_t) node->value[i], 1);
    910                 }
    911                
    912         }
    913         mutex_unlock(&sh_info->lock);
    914        
    915         if (dealloc) {
    916                 btree_destroy(&sh_info->pagemap);
    917                 free(sh_info);
    918         }
    919 }
    920 
    921961/** Destroy address space area.
    922962 *
     
    10001040        area->attributes |= AS_AREA_ATTR_PARTIAL;
    10011041       
    1002         if (area->sh_info)
    1003                 sh_info_remove_reference(area->sh_info);
     1042        sh_info_remove_reference(area->sh_info);
    10041043       
    10051044        mutex_unlock(&area->lock);
     
    10881127         */
    10891128        share_info_t *sh_info = src_area->sh_info;
    1090         if (!sh_info) {
    1091                 sh_info = (share_info_t *) malloc(sizeof(share_info_t), 0);
    1092                 mutex_initialize(&sh_info->lock, MUTEX_PASSIVE);
    1093                 sh_info->refcount = 2;
    1094                 btree_create(&sh_info->pagemap);
    1095                 src_area->sh_info = sh_info;
    1096                
     1129       
     1130        mutex_lock(&sh_info->lock);
     1131        sh_info->refcount++;
     1132        bool shared = sh_info->shared;
     1133        sh_info->shared = true;
     1134        mutex_unlock(&sh_info->lock);
     1135
     1136        if (!shared) {
    10971137                /*
    10981138                 * Call the backend to setup sharing.
     1139                 * This only happens once for each sh_info.
    10991140                 */
    11001141                src_area->backend->share(src_area);
    1101         } else {
    1102                 mutex_lock(&sh_info->lock);
    1103                 sh_info->refcount++;
    1104                 mutex_unlock(&sh_info->lock);
    11051142        }
    11061143       
     
    12211258        }
    12221259       
    1223         if ((area->sh_info) || (area->backend != &anon_backend)) {
    1224                 /* Copying shared areas not supported yet */
     1260        if (area->backend != &anon_backend) {
    12251261                /* Copying non-anonymous memory not supported yet */
    12261262                mutex_unlock(&area->lock);
     
    12281264                return ENOTSUP;
    12291265        }
     1266
     1267        mutex_lock(&area->sh_info->lock);
     1268        if (area->sh_info->shared) {
     1269                /* Copying shared areas not supported yet */
     1270                mutex_unlock(&area->sh_info->lock);
     1271                mutex_unlock(&area->lock);
     1272                mutex_unlock(&as->lock);
     1273                return ENOTSUP;
     1274        }
     1275        mutex_unlock(&area->sh_info->lock);
    12301276       
    12311277        /*
  • kernel/generic/src/mm/backend_anon.c

    r89dcf93 r83b6ba9f  
    7676        .page_fault = anon_page_fault,
    7777        .frame_free = anon_frame_free,
     78
     79        .create_shared_data = NULL,
     80        .destroy_shared_data = NULL
    7881};
    7982
     
    190193                return AS_PF_FAULT;
    191194
    192         if (area->sh_info) {
     195        mutex_lock(&area->sh_info->lock);
     196        if (area->sh_info->shared) {
    193197                btree_node_t *leaf;
    194198               
     
    200204                 * mapping, a new frame is allocated and the mapping is created.
    201205                 */
    202                 mutex_lock(&area->sh_info->lock);
    203206                frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
    204207                    upage - area->base, &leaf);
     
    232235                }
    233236                frame_reference_add(ADDR2PFN(frame));
    234                 mutex_unlock(&area->sh_info->lock);
    235237        } else {
    236238
     
    254256                         * Reserve the memory for this page now.
    255257                         */
    256                         if (!reserve_try_alloc(1))
     258                        if (!reserve_try_alloc(1)) {
     259                                mutex_unlock(&area->sh_info->lock);
    257260                                return AS_PF_SILENT;
     261                        }
    258262                }
    259263
     
    262266                km_temporary_page_put(kpage);
    263267        }
     268        mutex_unlock(&area->sh_info->lock);
    264269       
    265270        /*
  • kernel/generic/src/mm/backend_elf.c

    r89dcf93 r83b6ba9f  
    7575        .page_fault = elf_page_fault,
    7676        .frame_free = elf_frame_free,
     77
     78        .create_shared_data = NULL,
     79        .destroy_shared_data = NULL
    7780};
    7881
     
    274277        start_anon = entry->p_vaddr + entry->p_filesz;
    275278
    276         if (area->sh_info) {
     279        mutex_lock(&area->sh_info->lock);
     280        if (area->sh_info->shared) {
    277281                bool found = false;
    278282
     
    281285                 */
    282286               
    283                 mutex_lock(&area->sh_info->lock);
    284287                frame = (uintptr_t) btree_search(&area->sh_info->pagemap,
    285288                    upage - area->base, &leaf);
     
    384387        }
    385388
    386         if (dirty && area->sh_info) {
     389        if (dirty && area->sh_info->shared) {
    387390                frame_reference_add(ADDR2PFN(frame));
    388391                btree_insert(&area->sh_info->pagemap, upage - area->base,
     
    390393        }
    391394
    392         if (area->sh_info)
    393                 mutex_unlock(&area->sh_info->lock);
     395        mutex_unlock(&area->sh_info->lock);
    394396
    395397        page_mapping_insert(AS, upage, frame, as_area_get_flags(area));
  • kernel/generic/src/mm/backend_phys.c

    r89dcf93 r83b6ba9f  
    5555static bool phys_is_shareable(as_area_t *);
    5656
     57static int phys_page_fault(as_area_t *, uintptr_t, pf_access_t);
    5758
    58 static int phys_page_fault(as_area_t *, uintptr_t, pf_access_t);
     59static bool phys_create_shared_data(as_area_t *);
     60static void phys_destroy_shared_data(void *);
     61
     62typedef struct {
     63        uintptr_t base;
     64        size_t frames; 
     65} phys_shared_data_t;
    5966
    6067mem_backend_t phys_backend = {
     
    6976        .page_fault = phys_page_fault,
    7077        .frame_free = NULL,
     78       
     79        .create_shared_data = phys_create_shared_data,
     80        .destroy_shared_data = phys_destroy_shared_data
    7181};
     82
    7283
    7384bool phys_create(as_area_t *area)
     
    92103void phys_destroy(as_area_t *area)
    93104{
    94         mem_backend_data_t *data = &area->backend_data;
    95         bool last = true;
    96 
    97         if (area->sh_info) {
    98                 mutex_lock(&area->sh_info->lock);
    99                 if (area->sh_info->refcount != 1)
    100                         last = false;
    101                 mutex_unlock(&area->sh_info->lock);
    102         }
    103        
    104         if (last && data->anonymous)
    105                 frame_free(data->base, data->frames);
     105        /*
     106         * Nothing to do.
     107         * The anonymous frames, if any, are released in
     108         * phys_destroy_shared_data().
     109         */
    106110}
    107111
     
    149153}
    150154
     155bool phys_create_shared_data(as_area_t *area)
     156{
     157        /*
     158         * For anonymous phys areas, create the shared data.
     159         */
     160        if (area->backend_data.anonymous) {
     161                phys_shared_data_t *data;
     162
     163                data = (phys_shared_data_t *) malloc(sizeof(*data), 0);
     164
     165                data->base = area->backend_data.base;
     166                data->frames = area->backend_data.frames;
     167                area->sh_info->backend_shared_data = data;
     168        }
     169
     170        return true;
     171}
     172
     173void phys_destroy_shared_data(void *opaque_data)
     174{
     175        phys_shared_data_t *data = (phys_shared_data_t *) opaque_data;
     176
     177        if (data) {
     178                frame_free(data->base, data->frames);
     179                free(data);
     180        }
     181}
     182
    151183/** @}
    152184 */
Note: See TracChangeset for help on using the changeset viewer.