Changeset a9e8b39 in mainline


Ignore:
Timestamp:
2006-04-26T17:56:23Z (19 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
ed6c81f1
Parents:
6fa476f7
Message:

Prevent race in as_area_send() by allowing the address space area to be
created with AS_AREA_ATTR_PARTIAL attribute.

Location:
generic
Files:
5 edited

Legend:

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

    r6fa476f7 ra9e8b39  
    6060#define AS_AREA_DEVICE  8
    6161
     62/** Address space area attributes. */
     63#define AS_AREA_ATTR_NONE       0
     64#define AS_AREA_ATTR_PARTIAL    1       /* Not fully initialized area. */
     65
    6266/** Address space area structure.
    6367 *
     
    6771struct as_area {
    6872        SPINLOCK_DECLARE(lock);
    69         int flags;
     73        int flags;              /**< Flags related to the memory represented by the address space area. */
     74        int attributes;         /**< Attributes related to the address space area itself. */
    7075        count_t pages;          /**< Size of this area in multiples of PAGE_SIZE. */
    7176        __address base;         /**< Base address of this area. */
     
    113118extern void as_init(void);
    114119extern as_t *as_create(int flags);
    115 extern as_area_t *as_area_create(as_t *as, int flags, size_t size, __address base);
     120extern as_area_t *as_area_create(as_t *as, int flags, size_t size, __address base, int attrs);
    116121extern __address as_area_resize(as_t *as, __address address, size_t size, int flags);
    117 int as_area_send(task_id_t id, __address base);
     122int as_area_send(task_id_t dst_id, __address base);
    118123extern void as_set_mapping(as_t *as, __address page, __address frame);
    119124extern int as_page_fault(__address page);
  • generic/src/ddi/ddi.c

    r6fa476f7 ra9e8b39  
    9393        if (writable)
    9494                flags |= AS_AREA_WRITE;
    95         if (!as_area_create(t->as, flags, pages * PAGE_SIZE, vp)) {
     95        if (!as_area_create(t->as, flags, pages * PAGE_SIZE, vp, AS_AREA_ATTR_NONE)) {
    9696                /*
    9797                 * The address space area could not have been created.
  • generic/src/lib/elf.c

    r6fa476f7 ra9e8b39  
    187187                segment = ((void *) elf) + entry->p_offset;
    188188
    189         a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr);
     189        a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr, AS_AREA_ATTR_NONE);
    190190        if (!a)
    191191                return EE_MEMORY;
  • generic/src/mm/as.c

    r6fa476f7 ra9e8b39  
    127127 *
    128128 * @param as Target address space.
    129  * @param flags Flags of the area.
     129 * @param flags Flags of the area memory.
    130130 * @param size Size of area.
    131131 * @param base Base address of area.
     132 * @param attrs Attributes of the area.
    132133 *
    133134 * @return Address space area on success or NULL on failure.
    134135 */
    135 as_area_t *as_area_create(as_t *as, int flags, size_t size, __address base)
     136as_area_t *as_area_create(as_t *as, int flags, size_t size, __address base, int attrs)
    136137{
    137138        ipl_t ipl;
     
    162163       
    163164        a->flags = flags;
     165        a->attributes = attrs;
    164166        a->pages = SIZE2FRAMES(size);
    165167        a->base = base;
     
    290292 * space area and any associated mapping is preserved.
    291293 *
    292  * @param id Task ID of the accepting task.
    293  * @param base Base address of the source address space area.
     294 * @param dst_id Task ID of the accepting task.
     295 * @param src_base Base address of the source address space area.
    294296 *
    295297 * @return 0 on success or ENOENT if there is no such task or
     
    299301 *         address space area.
    300302 */
    301 int as_area_send(task_id_t id, __address base)
     303int as_area_send(task_id_t dst_id, __address src_base)
    302304{
    303305        ipl_t ipl;
    304306        task_t *t;
    305307        count_t i;
    306         as_t *as;
     308        as_t *dst_as;
    307309        __address dst_base;
    308         int flags;
    309         size_t size;
    310         as_area_t *area;
     310        int src_flags;
     311        size_t src_size;
     312        as_area_t *src_area, *dst_area;
    311313       
    312314        ipl = interrupts_disable();
    313315        spinlock_lock(&tasks_lock);
    314316       
    315         t = task_find_by_id(id);
     317        t = task_find_by_id(dst_id);
    316318        if (!NULL) {
    317319                spinlock_unlock(&tasks_lock);
     
    323325        spinlock_unlock(&tasks_lock);
    324326
    325         as = t->as;
     327        dst_as = t->as;
    326328        dst_base = (__address) t->accept_arg.base;
    327329       
    328         if (as == AS) {
     330        if (dst_as == AS) {
    329331                /*
    330332                 * The two tasks share the entire address space.
     
    337339       
    338340        spinlock_lock(&AS->lock);
    339         area = find_area_and_lock(AS, base);
    340         if (!area) {
     341        src_area = find_area_and_lock(AS, src_base);
     342        if (!src_area) {
    341343                /*
    342344                 * Could not find the source address space area.
     
    347349                return ENOENT;
    348350        }
    349         size = area->pages * PAGE_SIZE;
    350         flags = area->flags;
    351         spinlock_unlock(&area->lock);
     351        src_size = src_area->pages * PAGE_SIZE;
     352        src_flags = src_area->flags;
     353        spinlock_unlock(&src_area->lock);
    352354        spinlock_unlock(&AS->lock);
    353355
    354         if ((t->accept_arg.task_id != TASK->taskid) || (t->accept_arg.size != size) ||
    355             (t->accept_arg.flags != flags)) {
     356        if ((t->accept_arg.task_id != TASK->taskid) || (t->accept_arg.size != src_size) ||
     357            (t->accept_arg.flags != src_flags)) {
    356358                /*
    357359                 * Discrepancy in either task ID, size or flags.
     
    363365       
    364366        /*
    365          * Create copy of the address space area.
    366          */
    367         if (!as_area_create(as, flags, size, dst_base)) {
     367         * Create copy of the source address space area.
     368         * The destination area is created with AS_AREA_ATTR_PARTIAL
     369         * attribute set which prevents race condition with
     370         * preliminary as_page_fault() calls.
     371         */
     372        dst_area = as_area_create(dst_as, src_flags, src_size, dst_base, AS_AREA_ATTR_PARTIAL);
     373        if (!dst_area) {
    368374                /*
    369375                 * Destination address space area could not be created.
     
    374380        }
    375381       
    376         /*
    377          * NOTE: we have just introduced a race condition.
    378          * The destination task can try to attempt the newly
    379          * created area before its mapping is copied from
    380          * the source address space area. In result, frames
    381          * can get lost.
    382          *
    383          * Currently, this race is not solved, but one of the
    384          * possible solutions would be to sleep in as_page_fault()
    385          * when this situation is detected.
    386          */
    387 
    388382        memsetb((__address) &t->accept_arg, sizeof(as_area_acptsnd_arg_t), 0);
    389383        spinlock_unlock(&t->lock);
     
    392386         * Avoid deadlock by first locking the address space with lower address.
    393387         */
    394         if (as < AS) {
    395                 spinlock_lock(&as->lock);
     388        if (dst_as < AS) {
     389                spinlock_lock(&dst_as->lock);
    396390                spinlock_lock(&AS->lock);
    397391        } else {
    398392                spinlock_lock(&AS->lock);
    399                 spinlock_lock(&as->lock);
    400         }
    401        
    402         for (i = 0; i < SIZE2FRAMES(size); i++) {
     393                spinlock_lock(&dst_as->lock);
     394        }
     395       
     396        for (i = 0; i < SIZE2FRAMES(src_size); i++) {
    403397                pte_t *pte;
    404398                __address frame;
    405399                       
    406400                page_table_lock(AS, false);
    407                 pte = page_mapping_find(AS, base + i*PAGE_SIZE);
     401                pte = page_mapping_find(AS, src_base + i*PAGE_SIZE);
    408402                if (pte && PTE_VALID(pte)) {
    409403                        ASSERT(PTE_PRESENT(pte));
    410404                        frame = PTE_GET_FRAME(pte);
    411                         if (!(flags & AS_AREA_DEVICE))
     405                        if (!(src_flags & AS_AREA_DEVICE))
    412406                                frame_reference_add(ADDR2PFN(frame));
    413407                        page_table_unlock(AS, false);
     
    417411                }
    418412               
    419                 page_table_lock(as, false);
    420                 page_mapping_insert(as, dst_base + i*PAGE_SIZE, frame, area_flags_to_page_flags(flags));
    421                 page_table_unlock(as, false);
    422         }
     413                page_table_lock(dst_as, false);
     414                page_mapping_insert(dst_as, dst_base + i*PAGE_SIZE, frame, area_flags_to_page_flags(src_flags));
     415                page_table_unlock(dst_as, false);
     416        }
     417
     418        /*
     419         * Now the destination address space area has been
     420         * fully initialized. Clear the AS_AREA_ATTR_PARTIAL
     421         * attribute.
     422         */     
     423        spinlock_lock(&dst_area->lock);
     424        dst_area->attributes &= ~AS_AREA_ATTR_PARTIAL;
     425        spinlock_unlock(&dst_area->lock);
    423426       
    424427        spinlock_unlock(&AS->lock);
    425         spinlock_unlock(&as->lock);
     428        spinlock_unlock(&dst_as->lock);
    426429        interrupts_restore(ipl);
    427430       
     
    485488                spinlock_unlock(&AS->lock);
    486489                return 0;
     490        }
     491
     492        if (area->attributes & AS_AREA_ATTR_PARTIAL) {
     493                /*
     494                 * The address space area is not fully initialized.
     495                 * Avoid possible race by returning error.
     496                 */
     497                spinlock_unlock(&area->lock);
     498                spinlock_unlock(&AS->lock);
     499                return 0;               
    487500        }
    488501
     
    840853__native sys_as_area_create(__address address, size_t size, int flags)
    841854{
    842         if (as_area_create(AS, flags, size, address))
     855        if (as_area_create(AS, flags, size, address, AS_AREA_ATTR_NONE))
    843856                return (__native) address;
    844857        else
  • generic/src/proc/task.c

    r6fa476f7 ra9e8b39  
    152152         * Create the data as_area.
    153153         */
    154         a = as_area_create(as, AS_AREA_READ | AS_AREA_WRITE, LOADED_PROG_STACK_PAGES_NO*PAGE_SIZE, USTACK_ADDRESS);
     154        a = as_area_create(as, AS_AREA_READ | AS_AREA_WRITE, LOADED_PROG_STACK_PAGES_NO*PAGE_SIZE,
     155                USTACK_ADDRESS, AS_AREA_ATTR_NONE);
    155156
    156157        t = thread_create(uinit, kernel_uarg, task, 0, "uinit");
Note: See TracChangeset for help on using the changeset viewer.