summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordfr <dfr@FreeBSD.org>2004-07-30 11:09:18 +0000
committerdfr <dfr@FreeBSD.org>2004-07-30 11:09:18 +0000
commit74842d80bcca2a7ea9e14f5d213684bc5f48488f (patch)
tree6277336ef1c49333a5d3730fd13621838b197bc2
parentf4b42f3d573ea564ecabf010a70af14a692d5834 (diff)
downloadFreeBSD-src-74842d80bcca2a7ea9e14f5d213684bc5f48488f.zip
FreeBSD-src-74842d80bcca2a7ea9e14f5d213684bc5f48488f.tar.gz
Fix a memory leak in the device pager which is exposed by the NVIDIA
OpenGL driver. Submitted by: nvidia (possibly also tegge)
-rw-r--r--sys/vm/device_pager.c54
1 files changed, 41 insertions, 13 deletions
diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c
index e52d416..e7a256d 100644
--- a/sys/vm/device_pager.c
+++ b/sys/vm/device_pager.c
@@ -74,6 +74,7 @@ static uma_zone_t fakepg_zone;
static vm_page_t dev_pager_getfake(vm_paddr_t);
static void dev_pager_putfake(vm_page_t);
+static void dev_pager_updatefake(vm_page_t, vm_paddr_t);
struct pagerops devicepagerops = {
.pgo_init = dev_pager_init,
@@ -224,19 +225,36 @@ dev_pager_getpages(object, m, count, reqpage)
KASSERT(ret == 0, ("dev_pager_getpage: map function returns error"));
mtx_unlock(&Giant);
- /*
- * 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);
- VM_OBJECT_LOCK(object);
- TAILQ_INSERT_TAIL(&object->un_pager.devp.devp_pglist, page, pageq);
- vm_page_lock_queues();
- for (i = 0; i < count; i++)
- vm_page_free(m[i]);
- vm_page_unlock_queues();
- vm_page_insert(page, object, offset);
- m[reqpage] = page;
+ if ((m[reqpage]->flags & PG_FICTITIOUS) != 0) {
+ /*
+ * If the passed in reqpage page is a fake page, update it with
+ * the new physical address.
+ */
+ dev_pager_updatefake(m[reqpage], paddr);
+ VM_OBJECT_LOCK(object);
+ if (count > 1) {
+ vm_page_lock_queues();
+ for (i = 0; i < count; i++) {
+ if (i != reqpage)
+ vm_page_free(m[i]);
+ }
+ vm_page_unlock_queues();
+ }
+ } else {
+ /*
+ * 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);
+ VM_OBJECT_LOCK(object);
+ TAILQ_INSERT_TAIL(&object->un_pager.devp.devp_pglist, page, pageq);
+ vm_page_lock_queues();
+ for (i = 0; i < count; i++)
+ vm_page_free(m[i]);
+ vm_page_unlock_queues();
+ vm_page_insert(page, object, offset);
+ m[reqpage] = page;
+ }
return (VM_PAGER_OK);
}
@@ -296,3 +314,13 @@ dev_pager_putfake(m)
panic("dev_pager_putfake: bad page");
uma_zfree(fakepg_zone, m);
}
+
+static void
+dev_pager_updatefake(m, paddr)
+ vm_page_t m;
+ vm_paddr_t paddr;
+{
+ if (!(m->flags & PG_FICTITIOUS))
+ panic("dev_pager_updatefake: bad page");
+ m->phys_addr = paddr;
+}
OpenPOWER on IntegriCloud