VMRs that map page_maps are tracked
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 14 Jan 2014 00:52:33 +0000 (16:52 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 17 Jan 2014 22:57:13 +0000 (14:57 -0800)
Needed so we can remove pages or otherwise see which processes are using
which parts of a PM.

kern/include/mm.h
kern/include/pagemap.h
kern/src/mm.c
kern/src/pagemap.c

index cbe5ba6..e0133fe 100644 (file)
@@ -24,6 +24,7 @@ struct proc;                                                          /* preprocessor games */
  * VMRs. */
 struct vm_region {
        TAILQ_ENTRY(vm_region)          vm_link;
+       TAILQ_ENTRY(vm_region)          vm_pm_link;
        struct proc                                     *vm_proc;       /* owning process, for now */
        uintptr_t                                       vm_base;
        uintptr_t                                       vm_end;
@@ -34,8 +35,6 @@ struct vm_region {
 };
 TAILQ_HEAD(vmr_tailq, vm_region);                      /* Declares 'struct vmr_tailq' */
 
-#include <process.h>                                           /* preprocessor games */
-
 /* VM Region Management Functions.  For now, these just maintain themselves -
  * anything related to mapping needs to be done by the caller. */
 void vmr_init(void);
index bbbed5e..0aab4e9 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <radix.h>
 #include <atomic.h>
+#include <mm.h>
 
 /* Need to be careful, due to some ghetto circular references */
 struct page;
@@ -33,6 +34,8 @@ struct page_map {
        struct page_map_operations      *pm_op;
        unsigned int                            pm_flags;
        /*... and private lists, backing block dev info, other mappings, etc. */
+       spinlock_t                                      pm_lock;
+       struct vmr_tailq                        pm_vmrs;
 };
 
 /* Operations performed on a page_map.  These are usually FS specific, which
@@ -57,5 +60,8 @@ struct page_map_operations {
 void pm_init(struct page_map *pm, struct page_map_operations *op, void *host);
 int pm_load_page(struct page_map *pm, unsigned long index, struct page **pp);
 void pm_put_page(struct page *page);
+void pm_add_vmr(struct page_map *pm, struct vm_region *vmr);
+void pm_remove_vmr(struct page_map *pm, struct vm_region *vmr);
+void print_page_map_info(struct page_map *pm);
 
 #endif /* ROS_KERN_PAGEMAP_H */
index 29aedfc..bc231df 100644 (file)
 #include <vfs.h>
 #include <smp.h>
 
-static int __vmr_free_pgs(struct proc *p, pte_t *pte, void *va, void *arg);
-
 struct kmem_cache *vmr_kcache;
 
+static int __vmr_free_pgs(struct proc *p, pte_t *pte, void *va, void *arg);
+/* minor helper, will ease the file->chan transition */
+static struct page_map *file2pm(struct file *file)
+{
+       return file->f_mapping;
+}
+
 void vmr_init(void)
 {
        vmr_kcache = kmem_cache_create("vm_regions", sizeof(struct vm_region),
@@ -118,6 +123,7 @@ struct vm_region *split_vmr(struct vm_region *old_vmr, uintptr_t va)
                new_vmr->vm_file = old_vmr->vm_file;
                new_vmr->vm_foff = old_vmr->vm_foff +
                                      old_vmr->vm_end - old_vmr->vm_base;
+               pm_add_vmr(file2pm(old_vmr->vm_file), new_vmr);
        } else {
                new_vmr->vm_file = 0;
                new_vmr->vm_foff = 0;
@@ -190,8 +196,10 @@ int shrink_vmr(struct vm_region *vmr, uintptr_t va)
  * out the page table entries. */
 void destroy_vmr(struct vm_region *vmr)
 {
-       if (vmr->vm_file)
+       if (vmr->vm_file) {
+               pm_remove_vmr(file2pm(vmr->vm_file), vmr);
                kref_put(&vmr->vm_file->f_kref);
+       }
        TAILQ_REMOVE(&vmr->vm_proc->vm_regions, vmr, vm_link);
        kmem_cache_free(vmr_kcache, vmr);
 }
@@ -322,10 +330,12 @@ int duplicate_vmrs(struct proc *p, struct proc *new_p)
                vmr->vm_end = vm_i->vm_end;
                vmr->vm_prot = vm_i->vm_prot;   
                vmr->vm_flags = vm_i->vm_flags; 
-               if (vm_i->vm_file)
-                       kref_get(&vm_i->vm_file->f_kref, 1);
                vmr->vm_file = vm_i->vm_file;
                vmr->vm_foff = vm_i->vm_foff;
+               if (vm_i->vm_file) {
+                       kref_get(&vm_i->vm_file->f_kref, 1);
+                       pm_add_vmr(file2pm(vm_i->vm_file), vmr);
+               }
                if (!vmr->vm_file || vmr->vm_flags & MAP_PRIVATE) {
                        assert(!(vmr->vm_flags & MAP_SHARED));
                        /* Copy over the memory from one VMR to the other */
@@ -499,6 +509,7 @@ void *__do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
        vmr->vm_flags = flags;
        if (file) {
                if (!check_file_perms(vmr, file, prot)) {
+                       assert(!vmr->vm_file);
                        destroy_vmr(vmr);
                        set_errno(EACCES);
                        return MAP_FAILED;
@@ -514,17 +525,20 @@ void *__do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
                         * immediately mprotect it to PROT_NONE. */
                        flags &= ~MAP_POPULATE;
                }
+               /* Prep the FS to make sure it can mmap the file.  Slightly weird
+                * semantics: if we fail and had munmapped the space, they will have a
+                * hole in their VM now. */
+               if (file->f_op->mmap(file, vmr)) {
+                       assert(!vmr->vm_file);
+                       destroy_vmr(vmr);
+                       set_errno(EACCES);      /* not quite */
+                       return MAP_FAILED;
+               }
                kref_get(&file->f_kref, 1);
+               pm_add_vmr(file2pm(file), vmr);
        }
        vmr->vm_file = file;
        vmr->vm_foff = offset;
-       /* Prep the FS to make sure it can mmap the file.  Slightly weird semantics:
-        * they will have a hole in their VM now. */
-       if (file && file->f_op->mmap(file, vmr)) {
-               destroy_vmr(vmr);
-               set_errno(EACCES);      /* not quite */
-               return MAP_FAILED;
-       }
        addr = vmr->vm_base;            /* so we know which pages to populate later */
        vmr = merge_me(vmr);            /* attempts to merge with neighbors */
        /* Fault in pages now if MAP_POPULATE.  We want to populate the region
index c984911..62e43bf 100644 (file)
 #include <assert.h>
 #include <stdio.h>
 
+void pm_add_vmr(struct page_map *pm, struct vm_region *vmr)
+{
+       /* note that the VMR being reverse-mapped by the PM is protected by the PM's
+        * lock.  so later when removal holds this, it delays munmaps and keeps the
+        * VMR connected. */
+       spin_lock(&pm->pm_lock);
+       TAILQ_INSERT_TAIL(&pm->pm_vmrs, vmr, vm_pm_link);
+       spin_unlock(&pm->pm_lock);
+}
+
+void pm_remove_vmr(struct page_map *pm, struct vm_region *vmr)
+{
+       spin_lock(&pm->pm_lock);
+       TAILQ_REMOVE(&pm->pm_vmrs, vmr, vm_pm_link);
+       spin_unlock(&pm->pm_lock);
+}
+
 /* Initializes a PM.  Host should be an *inode or a *bdev (doesn't matter).  The
  * reference this stores is uncounted. */
 void pm_init(struct page_map *pm, struct page_map_operations *op, void *host)
@@ -22,6 +39,8 @@ void pm_init(struct page_map *pm, struct page_map_operations *op, void *host)
        pm->pm_num_pages = 0;                                   /* no pages in a new pm */
        pm->pm_op = op;
        pm->pm_flags = 0;
+       spinlock_init(&pm->pm_lock);
+       TAILQ_INIT(&pm->pm_vmrs);
 }
 
 /* Looks up the index'th page in the page map, returning an incref'd reference,
@@ -132,3 +151,17 @@ int pm_load_page(struct page_map *pm, unsigned long index, struct page **pp)
        assert(atomic_read(&page->pg_flags) & PG_UPTODATE);
        return 0;
 }
+
+void print_page_map_info(struct page_map *pm)
+{
+       struct vm_region *vmr_i;
+       printk("Page Map %p\n", pm);
+       printk("\tNum pages: %lu\n", pm->pm_num_pages);
+       spin_lock(&pm->pm_lock);
+       TAILQ_FOREACH(vmr_i, &pm->pm_vmrs, vm_pm_link) {
+               printk("\tVMR proc %d: (%p - %p): 0x%08x, 0x%08x, %p, %p\n",
+                      vmr_i->vm_proc->pid, vmr_i->vm_base, vmr_i->vm_end,
+                      vmr_i->vm_prot, vmr_i->vm_flags, vmr_i->vm_file, vmr_i->vm_foff);
+       }
+       spin_unlock(&pm->pm_lock);
+}