New KPI for unmap.
authorSimon Gerber <simugerber@student.ethz.ch>
Thu, 22 Nov 2012 14:53:22 +0000 (15:53 +0100)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Tue, 29 Jan 2013 10:31:03 +0000 (11:31 +0100)
errors/errno.fugu
kernel/arch/x86_64/page_mappings_arch.c
kernel/syscall.c
lib/barrelfish/target/x86_64/pmap_target.c

index e6ca1c8..ebc8770 100644 (file)
@@ -72,9 +72,10 @@ errors kernel SYS_ERR_ {
     failure VNODE_SLOT_INUSE        "Destination slot in use: unmap first",
     failure VNODE_TYPE              "Encountered non-VNode capability when manipulating page tables",
     failure VNODE_LOOKUP_NEXT       "Could not find next level page table",
-    failure VM_MAP_START_UNALIGNED  "Mapping offset not aligned to BASE_PAGE_SIZE",
+    failure VM_MAP_ALREADY_MAPPED   "This cap copy is already mapped",
     failure VM_MAP_SIZE             "Mapping size too large",
     failure VM_MAP_OFFSET           "Mapping offset too large",
+    failure VM_RETRY_SINGLE         "Mapping overlaps multiple leaf page tables, retry",
 
     // errors related to IRQ table
     failure IRQ_LOOKUP          "Specified capability was not found while inserting in IRQ table",
@@ -235,7 +236,9 @@ errors libbarrelfish LIB_ERR_ {
     failure PMAP_DETERMINE_ADDR "Failure in pmap_determine_addr()",
     failure PMAP_DO_MAP       "Failure in pmap_do_map()",
     failure PMAP_MAP          "Failure in pmap_map()",
+    failure PMAP_DO_SINGLE_MAP "Failure in pmap_do_single_map()",
     failure PMAP_UNMAP        "Failure in pmap_unmap()",
+    failure PMAP_DO_SINGLE_UNMAP "Failure in pmap_do_single_unmap()",
     failure PMAP_MODIFY_FLAGS "Failure in pmap_modify_flags()",
     failure PMAP_GET_PTABLE   "Failure in get_mapping()",
     failure PMAP_ALLOC_VNODE  "Failure in alloc_vnode()",
index ff37d70..8503cfa 100644 (file)
@@ -327,7 +327,7 @@ static inline errval_t lookup_cap_for_mapping(genpaddr_t paddr, lvaddr_t pte, st
     printf("0x%lx, %zd\n", get_address(&mem->cap), get_size(&mem->cap));
     printf("mem->mapping_info.pte          = 0x%lx\n", mem->mapping_info.pte);
     printf("mem->mapping_info.offset       = %zd\n", mem->mapping_info.offset);
-    printf("mem->mapping_info.mapped_pages = %zd\n", mem->mapping_info.mapped_pages);
+    printf("mem->mapping_info.pte_count    = %zd\n", mem->mapping_info.pte_count);
     printf("mem = %p\n", mem);
 #endif
 
@@ -451,12 +451,14 @@ errval_t page_mappings_unmap(struct capability *pgtable, size_t slot, size_t num
     genvaddr_t vaddr;
     struct cte *leaf_pt = cte_for_cap(pgtable);
     compile_vaddr(leaf_pt, slot, &vaddr);
-    //printf("vaddr = 0x%lx\n", vaddr);
+    // printf("vaddr = 0x%lx\n", vaddr);
+    // printf("num_pages = %zu\n", num_pages);
 
     // get cap for mapping
     struct cte *mem;
     errval_t err = lookup_cap_for_mapping(paddr, pte, &mem);
     if (err_is_fail(err)) {
+        printf("page_mappings_unmap: %ld\n", err);
         return err;
     }
     //printf("state before unmap: mapped_pages = %zd\n", mem->mapping_info.mapped_pages);
index da35930..81ea5a2 100644 (file)
@@ -376,7 +376,7 @@ sys_modify_mapping(struct capability *mem, size_t page_count, uint64_t off)
     size_t map_size = page_count*BASE_PAGE_SIZE;
     if (map_start & BASE_PAGE_MASK) {
         // return modify error if offset not aligned to base page size
-        return SYSRET(SYS_ERR_VM_MAP_START_UNALIGNED);
+        return SYSRET(1000);
     }
     if ((map_start + map_size) > frame_end) {
         // return modify error if offset + map_size after end of memory region
index 592c9cf..10c9c7b 100644 (file)
@@ -86,7 +86,7 @@ static bool has_vnode(struct vnode *root, uint32_t entry, size_t len)
 }
 
 /**
- * \brief Starting at a given root, return the vnode with entry equal to #entry
+ * \brief Starting at a given root, return the vnode with starting entry equal to #entry
  */
 static struct vnode *find_vnode(struct vnode *root, uint32_t entry)
 {
@@ -335,9 +335,9 @@ static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
         }
 
         // map remaining part
+        offset += c * X86_64_BASE_PAGE_SIZE;
         c = X86_64_PTABLE_BASE(vend) - X86_64_PTABLE_BASE(temp_end);
         if (c) {
-            offset += X86_64_PTABLE_SIZE;
             // copy cap
             struct capref next;
             err = slot_alloc(&next);
@@ -495,6 +495,35 @@ static errval_t map(struct pmap *pmap, genvaddr_t vaddr, struct capref frame,
     return err;
 }
 
+static errval_t do_single_unmap(struct pmap_x86 *pmap, genvaddr_t vaddr, size_t pte_count)
+{
+    errval_t err;
+    struct vnode *pt = find_ptable(pmap, vaddr);
+    if (pt) {
+        struct vnode *page = find_vnode(pt, X86_64_PTABLE_BASE(vaddr));
+        if (page && page->u.frame.pte_count == pte_count) {
+            err = vnode_unmap(pt->u.vnode.cap, page->entry, page->u.frame.pte_count);
+            if (err_is_fail(err)) {
+                printf("vnode_unmap returned error: %s (%d)\n", err_getstring(err), err_no(err));
+                return err_push(err, LIB_ERR_VNODE_UNMAP);
+            }
+
+            // Free up the resources
+            err = cap_destroy(page->u.frame.cap);
+            if (err_is_fail(err)) {
+                return err_push(err, LIB_ERR_PMAP_DO_SINGLE_UNMAP);
+            }
+            remove_vnode(pt, page);
+            slab_free(&pmap->slab, page);
+        }
+        else {
+            return LIB_ERR_PMAP_FIND_VNODE;
+        }
+    }
+
+    return SYS_ERR_OK;
+}
+
 /**
  * \brief Remove page mappings
  *
@@ -506,53 +535,52 @@ static errval_t map(struct pmap *pmap, genvaddr_t vaddr, struct capref frame,
 static errval_t unmap(struct pmap *pmap, genvaddr_t vaddr, size_t size,
                       size_t *retsize)
 {
+    //printf("[unmap] 0x%"PRIxGENVADDR", %zu\n", vaddr, size);
     errval_t err, ret = SYS_ERR_OK;
     struct pmap_x86 *x86 = (struct pmap_x86*)pmap;
     size = ROUND_UP(size, X86_64_BASE_PAGE_SIZE);
+    genvaddr_t vend = vaddr + size;
 
+    if (X86_64_PDIR_BASE(vaddr) == X86_64_PDIR_BASE(vend)) {
+        // fast path
+        do_single_unmap(x86, vaddr, size / X86_64_BASE_PAGE_SIZE);
+    }
+    else { // slow path
+        // unmap first leaf
+        uint32_t c = X86_64_PTABLE_SIZE - X86_64_PTABLE_BASE(vaddr);
+        genvaddr_t temp_end = vaddr + c * X86_64_BASE_PAGE_SIZE;
+        err = do_single_unmap(x86, vaddr, c);
+        if (err_is_fail(err)) {
+            return err_push(err, LIB_ERR_PMAP_UNMAP);
+        }
 
-    //printf("size  = %zd\n", size);
-    size_t pages = size / X86_64_BASE_PAGE_SIZE;
-    //printf("pages = %zd\n", pages);
-    // Unmap it in the kernel
-    struct vnode *pt= find_ptable(x86, vaddr);
-    if (pt) {
-        struct vnode *page = find_vnode(pt, X86_64_PTABLE_BASE(vaddr));
-        if (page) {
-            err = vnode_unmap(pt->u.vnode.cap, page->entry, pages);
+        // unmap full leaves
+        while (X86_64_PDIR_BASE(temp_end) < X86_64_PDIR_BASE(vend)) {
+            vaddr += c * X86_64_BASE_PAGE_SIZE;
+            c = X86_64_PTABLE_SIZE;
+            err = do_single_unmap(x86, vaddr, X86_64_PTABLE_SIZE);
             if (err_is_fail(err)) {
-                printf("vnode_unmap returned error: %s (%"PRIuERRV")\n", err_getstring(err), err);
-                ret = err_push(err, LIB_ERR_VNODE_UNMAP);
-                return ret;
+                return err_push(err, LIB_ERR_PMAP_UNMAP);
             }
         }
-    }
 
-    // cleanup user space vnodes
-    for (size_t i = 0; i < size; i+=X86_64_BASE_PAGE_SIZE) {
-        // Find the page table
-        struct vnode *ptable;
-        ptable = find_ptable(x86, vaddr + i);
-        if (ptable == NULL) {
-            printf("no pt for 0x%"PRIxGENVADDR"\n",vaddr +i);
-            continue; // not mapped
-        }
-        // Find the page
-        struct vnode *page = find_vnode(ptable, X86_64_PTABLE_BASE(vaddr + i));
-        if (!page) {
-            printf("no page for 0x%"PRIxGENVADDR"\n", vaddr + i);
-            continue; // not mapped
+        // map remaining part
+        vaddr += c * X86_64_BASE_PAGE_SIZE;
+        c = X86_64_PTABLE_BASE(vend) - X86_64_PTABLE_BASE(vaddr);
+        if (c) {
+            // do mapping
+            err = do_single_unmap(x86, vaddr, c);
+            if (err_is_fail(err)) {
+                return err_push(err, LIB_ERR_PMAP_UNMAP);
+            }
         }
-
-        // Free up the resources
-        remove_vnode(ptable, page);
-        slab_free(&x86->slab, page);
     }
 
     if (retsize) {
         *retsize = size;
     }
 
+    //printf("[unmap] exiting\n");
     return ret;
 }