Catch negative FDs
[akaros.git] / kern / src / mm.c
index c0dac97..90a53c4 100644 (file)
@@ -104,8 +104,8 @@ struct vm_region *split_vmr(struct vm_region *old_vmr, uintptr_t va)
        new_vmr->vm_prot = old_vmr->vm_prot;
        new_vmr->vm_flags = old_vmr->vm_flags;
        if (old_vmr->vm_file) {
+               kref_get(&old_vmr->vm_file->f_kref, 1);
                new_vmr->vm_file = old_vmr->vm_file;
-               atomic_inc(&new_vmr->vm_file->f_refcnt);
                new_vmr->vm_foff = old_vmr->vm_foff +
                                      old_vmr->vm_end - old_vmr->vm_base;
        } else {
@@ -181,7 +181,7 @@ int shrink_vmr(struct vm_region *vmr, uintptr_t va)
 void destroy_vmr(struct vm_region *vmr)
 {
        if (vmr->vm_file)
-               atomic_dec(&vmr->vm_file->f_refcnt);
+               kref_put(&vmr->vm_file->f_kref);
        TAILQ_REMOVE(&vmr->vm_proc->vm_regions, vmr, vm_link);
        kmem_cache_free(vmr_kcache, vmr);
 }
@@ -226,6 +226,15 @@ void isolate_vmrs(struct proc *p, uintptr_t va, size_t len)
                split_vmr(vmr, va + len);
 }
 
+/* Destroys all vmrs of a process - important for when files are mmap()d and
+ * probably later when we share memory regions */
+void destroy_vmrs(struct proc *p)
+{
+       struct vm_region *vm_i;
+       TAILQ_FOREACH(vm_i, &p->vm_regions, vm_link)
+               destroy_vmr(vm_i);
+}
+
 /* This will make new_p have the same VMRs as p, though it does nothing to
  * ensure the physical pages or whatever are shared/mapped/copied/whatever.
  * This is used by fork().
@@ -244,9 +253,9 @@ void 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;
-               if (vmr->vm_file)
-                       atomic_inc(&vmr->vm_file->f_refcnt);
                vmr->vm_foff = vm_i->vm_foff;
                TAILQ_INSERT_TAIL(&new_p->vm_regions, vmr, vm_link);
        }
@@ -258,9 +267,9 @@ void print_vmrs(struct proc *p)
        struct vm_region *vmr;
        printk("VM Regions for proc %d\n", p->pid);
        TAILQ_FOREACH(vmr, &p->vm_regions, vm_link)
-               printk("%02d: (0x%08x - 0x%08x): %08p, %08p, %08p\n", count++,
+               printk("%02d: (0x%08x - 0x%08x): %08p, %08p, %08p, %08p\n", count++,
                       vmr->vm_base, vmr->vm_end, vmr->vm_prot, vmr->vm_flags,
-                      vmr->vm_file);
+                      vmr->vm_file, vmr->vm_foff);
 }
 
 
@@ -272,11 +281,6 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
        struct file *file = NULL;
        printd("mmap(addr %x, len %x, prot %x, flags %x, fd %x, off %x)\n", addr,
               len, prot, flags, fd, offset);
-       if (fd >= 0 && (flags & MAP_SHARED)) {
-               printk("[kernel] mmap() for files requires !MAP_SHARED.\n");
-               set_errno(current_tf, EACCES);
-               return MAP_FAILED;
-       }
        if (fd >= 0 && (flags & MAP_ANON)) {
                set_errno(current_tf, EBADF);
                return MAP_FAILED;
@@ -290,7 +294,7 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
                return MAP_FAILED;
        }
        if (fd != -1) {
-               file = file_open_from_fd(p, fd);
+               file = get_file_from_fd(&p->open_files, fd);
                if (!file) {
                        set_errno(current_tf, EBADF);
                        return MAP_FAILED;
@@ -299,7 +303,7 @@ void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
        addr = MAX(addr, MMAP_LOWEST_VA);
        void *result = do_mmap(p, addr, len, prot, flags, file, offset);
        if (file)
-               file_decref(file);
+               kref_put(&file->f_kref);
        return result;
 }
 
@@ -337,6 +341,8 @@ void *__do_mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
        }
        vmr->vm_prot = prot;
        vmr->vm_flags = flags;
+       if (file)
+               kref_get(&file->f_kref, 1);
        vmr->vm_file = file;
        vmr->vm_foff = offset;
        /* Prep the FS to make sure it can mmap the file.  Slightly weird semantics:
@@ -547,6 +553,15 @@ int __handle_page_fault(struct proc* p, uintptr_t va, int prot)
                retval = file_load_page(vmr->vm_file, f_idx, &a_page);
                if (retval)
                        return retval;
+               /* If we want a private map that is writable, we'll preemptively give
+                * you a new page.  In the future, we want to CoW this, but the kernel
+                * needs to be able to handle its own page faults first. */
+               if ((vmr->vm_flags |= MAP_PRIVATE) && (vmr->vm_prot |= PROT_WRITE)) {
+                       struct page *cache_page = a_page;
+                       if (upage_alloc(p, &a_page, FALSE))
+                               return -ENOMEM;
+                       memcpy(page2kva(a_page), page2kva(cache_page), PGSIZE);
+               }
                /* if this is an executable page, we might have to flush the instruction
                 * cache if our HW requires it. */
                if (vmr->vm_prot & PROT_EXEC)