Mapping precision fixes on l4_unmap and do_munmap()

l4_unmap now returns -1 if given range was only partially unmapped.

do_munmap() now only unmaps address ranges that have correspondence in
the unmapped vmas. Trying to unmap regions with no correspondent vmas
causes problems in corner cases, e.g. mm0 that tries to mmap its own
address space during initialisation would unmap its whole address space
and fail to execute.
This commit is contained in:
Bahadir Balban
2008-11-08 10:18:35 +02:00
parent 0e3f069713
commit 94daebd0c5
7 changed files with 82 additions and 39 deletions

View File

@@ -40,26 +40,30 @@ found:
return 0;
}
/*
* Unmaps given range from given task. If the complete range is unmapped
* sucessfully, returns 0. If part of the range was found to be already
* unmapped, returns -1. This is may or may not be an error.
*/
int sys_unmap(syscall_context_t *regs)
{
unsigned long virt = regs->r0;
unsigned long virtual = regs->r0;
unsigned long npages = regs->r1;
unsigned int tid = regs->r2;
struct ktcb *target;
int ret, retval;
if (tid == current->tid) { /* The easiest case */
if (tid == current->tid)
target = current;
goto found;
} else /* else search the tcb from its hash list */
if ((target = find_task(tid)))
goto found;
BUG();
return -EINVAL;
found:
for (int i = 0; i < npages; i++)
remove_mapping_pgd(virt, target->pgd);
else if (!(target = find_task(tid)))
return -ESRCH;
return 0;
for (int i = 0; i < npages; i++) {
ret = remove_mapping_pgd(virtual + i * PAGE_SIZE, target->pgd);
if (ret)
retval = ret;
}
return retval;
}

View File

@@ -274,31 +274,38 @@ int check_mapping(unsigned long vaddr, unsigned long size,
}
/* FIXME: Empty PMDs should be returned here !!! */
void __remove_mapping(pmd_table_t *pmd, unsigned long vaddr)
int __remove_mapping(pmd_table_t *pmd, unsigned long vaddr)
{
pmd_t pmd_i = PMD_INDEX(vaddr);
int ret;
switch (pmd->entry[pmd_i] & PMD_TYPE_MASK) {
case PMD_TYPE_FAULT:
ret = -1;
break;
case PMD_TYPE_LARGE:
pmd->entry[pmd_i] = 0;
pmd->entry[pmd_i] |= PMD_TYPE_FAULT;
ret = 0;
break;
case PMD_TYPE_SMALL:
pmd->entry[pmd_i] = 0;
pmd->entry[pmd_i] |= PMD_TYPE_FAULT;
ret = 0;
break;
default:
printk("Unknown page mapping in pmd. Assuming bug.\n");
BUG();
}
return;
return ret;
}
void remove_mapping_pgd(unsigned long vaddr, pgd_table_t *pgd)
int remove_mapping_pgd(unsigned long vaddr, pgd_table_t *pgd)
{
pgd_t pgd_i = PGD_INDEX(vaddr);
pmd_table_t *pmd;
pmd_t pmd_i;
int ret;
/*
* Clean the cache to main memory before removing the mapping. Otherwise
@@ -321,20 +328,19 @@ void remove_mapping_pgd(unsigned long vaddr, pgd_table_t *pgd)
phys_to_virt((pgd->entry[pgd_i]
& PGD_COARSE_ALIGN_MASK));
pmd_i = PMD_INDEX(vaddr);
__remove_mapping(pmd, vaddr);
ret = __remove_mapping(pmd, vaddr);
break;
case PGD_TYPE_FAULT:
dprintk("Attempting to remove fault mapping. "
"Assuming bug.\n", vaddr);
BUG();
ret = -1;
break;
case PGD_TYPE_SECTION:
printk("Removing section mapping for 0x%lx",
vaddr);
pgd->entry[pgd_i] = 0;
pgd->entry[pgd_i] |= PGD_TYPE_FAULT;
printk("Removing section mapping for 0x%lx",
vaddr);
pgd->entry[pgd_i] = 0;
pgd->entry[pgd_i] |= PGD_TYPE_FAULT;
ret = 0;
break;
case PGD_TYPE_FINE:
@@ -352,11 +358,13 @@ void remove_mapping_pgd(unsigned long vaddr, pgd_table_t *pgd)
/* The tlb must be invalidated here because it might have cached the
* old translation for this mapping. */
arm_invalidate_tlb();
return ret;
}
void remove_mapping(unsigned long vaddr)
int remove_mapping(unsigned long vaddr)
{
remove_mapping_pgd(vaddr, current->pgd);
return remove_mapping_pgd(vaddr, current->pgd);
}
/*