Fix a device pager leak for the case where the page already exists in the
authorMatthew Dillon <dillon@dragonflybsd.org>
Wed, 21 Jul 2004 01:25:18 +0000 (01:25 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Wed, 21 Jul 2004 01:25:18 +0000 (01:25 +0000)
VM object (typical case: multiple mappings of the device?).  If the page
already exists we simply update its physical address.  It is unclear whether
the physical address would ever actually be different, however.

This is an untested patch.

Original-patch-written-by: Christian Zander @ NVIDIA
Workaround-suggested-by: Tor Egge <tegge@freebsd.org>
Submitted-by: Emiel Kollof <coolvibe@hackerheaven.org>
sys/vm/device_pager.c
sys/vm/vm_map.c

index d4aaa6d..86ae2e8 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)device_pager.c      8.1 (Berkeley) 6/11/93
  * $FreeBSD: src/sys/vm/device_pager.c,v 1.46.2.1 2000/08/02 21:54:37 peter Exp $
- * $DragonFly: src/sys/vm/device_pager.c,v 1.7 2004/03/23 22:54:32 dillon Exp $
+ * $DragonFly: src/sys/vm/device_pager.c,v 1.8 2004/07/21 01:25:18 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -45,6 +45,7 @@
 #include <sys/conf.h>
 #include <sys/mman.h>
 #include <sys/device.h>
+#include <sys/thread2.h>
 
 #include <vm/vm.h>
 #include <vm/vm_object.h>
@@ -185,8 +186,8 @@ dev_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage)
        vm_paddr_t paddr;
        vm_page_t page;
        dev_t dev;
-       int i, s;
        int prot;
+       int i;
 
        dev = object->handle;
        offset = m[reqpage]->pindex;
@@ -194,19 +195,29 @@ dev_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage)
 
        paddr = pmap_phys_address(dev_dmmap(dev, (vm_offset_t) offset << PAGE_SHIFT, prot));
        KASSERT(paddr != -1,("dev_pager_getpage: map function returns error"));
-       /*
-        * Replace the passed in reqpage page with our own fake page and free up the
-        * all of the original pages.
-        */
-       page = dev_pager_getfake(paddr);
-       TAILQ_INSERT_TAIL(&object->un_pager.devp.devp_pglist, page, pageq);
+
+       if (m[reqpage]->flags & PG_FICTITIOUS) {
+               /*
+                * If the passed in reqpage page is a fake page, update it
+                * with the new physical address.
+                */
+               m[reqpage]->phys_addr = paddr;
+       } else {
+               /*
+                * Replace the passed in reqpage page with our own fake page
+                * and free up all the original pages.
+                */
+               page = dev_pager_getfake(paddr);
+               TAILQ_INSERT_TAIL(&object->un_pager.devp.devp_pglist, page, pageq);
+               crit_enter();
+               vm_page_free(m[reqpage]);
+               vm_page_insert(page, object, offset);
+               crit_exit();
+       }
        for (i = 0; i < count; i++) {
-               vm_page_free(m[i]);
+               if (i != reqpage)
+                       vm_page_free(m[i]);
        }
-       s = splhigh();
-       vm_page_insert(page, object, offset);
-       splx(s);
-
        return (VM_PAGER_OK);
 }
 
index 8f8a761..ac5ec09 100644 (file)
@@ -62,7 +62,7 @@
  * rights to redistribute these changes.
  *
  * $FreeBSD: src/sys/vm/vm_map.c,v 1.187.2.19 2003/05/27 00:47:02 alc Exp $
- * $DragonFly: src/sys/vm/vm_map.c,v 1.28 2004/05/27 00:38:58 dillon Exp $
+ * $DragonFly: src/sys/vm/vm_map.c,v 1.29 2004/07/21 01:25:18 dillon Exp $
  */
 
 /*
@@ -2201,11 +2201,13 @@ vm_map_clean(vm_map_t map, vm_offset_t start, vm_offset_t end, boolean_t syncio,
                if (object && invalidate &&
                   ((object->type == OBJT_VNODE) ||
                    (object->type == OBJT_DEVICE))) {
+                       int clean_only = 
+                               (object->type == OBJT_DEVICE) ? FALSE : TRUE;
                        vm_object_reference(object);
                        vm_object_page_remove(object,
                            OFF_TO_IDX(offset),
                            OFF_TO_IDX(offset + size + PAGE_MASK),
-                           TRUE);
+                           clean_only);
                        vm_object_deallocate(object);
                }
                start += size;