summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/drm_compat.c30
-rw-r--r--linux-core/drm_ttm.c38
-rw-r--r--linux-core/drm_vm.c5
3 files changed, 48 insertions, 25 deletions
diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c
index 162e4656..d387678e 100644
--- a/linux-core/drm_compat.c
+++ b/linux-core/drm_compat.c
@@ -54,19 +54,37 @@ static inline void change_pte_range(struct mm_struct *mm, pmd_t * pmd,
unsigned long addr, unsigned long end)
{
pte_t *pte;
+ struct page *page;
+ unsigned long pfn;
pte = pte_offset_map(pmd, addr);
do {
if (pte_present(*pte)) {
pte_t ptent;
- ptep_get_and_clear(mm, addr, pte);
+ pfn = pte_pfn(*pte);
ptent = *pte;
- lazy_mmu_prot_update(ptent);
- } else {
ptep_get_and_clear(mm, addr, pte);
- }
- if (!pte_none(*pte)) {
- DRM_ERROR("Ugh. Pte was presen\n");
+ if (pfn_valid(pfn)) {
+ page = pfn_to_page(pfn);
+ if (atomic_add_negative(-1, &page->_mapcount)) {
+ if (page_test_and_clear_dirty(page))
+ set_page_dirty(page);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
+ dec_zone_page_state(page, NR_FILE_MAPPED);
+#else
+ dec_page_state(nr_mapped);
+#endif
+ }
+
+ put_page(page);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+ dec_mm_counter(mm, file_rss);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+ dec_mm_counter(mm, rss);
+#else
+ --mm->rss;
+#endif
+ }
}
} while (pte++, addr += PAGE_SIZE, addr != end);
pte_unmap(pte - 1);
diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c
index 889e0001..cd95e311 100644
--- a/linux-core/drm_ttm.c
+++ b/linux-core/drm_ttm.c
@@ -199,6 +199,7 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset,
(page_offset << PAGE_SHIFT),
entry->vma->vm_start +
((page_offset + num_pages) << PAGE_SHIFT));
+
#if !defined(flush_tlb_mm) && defined(MODULE)
flush_tlb = 1;
#endif
@@ -209,7 +210,7 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset,
#endif
for (cur_page = first_page; cur_page != last_page; ++cur_page) {
- if (page_mapcount(*cur_page) != 0) {
+ if (page_mapped(*cur_page)) {
DRM_ERROR("Mapped page detected. Map count is %d\n",
page_mapcount(*cur_page));
return -1;
@@ -239,6 +240,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
}
DRM_DEBUG("Destroying a ttm\n");
+
if (ttm->be_list) {
list_for_each_safe(list, next, &ttm->be_list->head) {
drm_ttm_backend_list_t *entry =
@@ -262,7 +264,22 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
do_tlbflush = 1;
}
if (*cur_page) {
- ClearPageReserved(*cur_page);
+ ClearPageLocked(*cur_page);
+
+ /*
+ * Debugging code. Remove if the error message never
+ * shows up.
+ */
+
+ if (page_count(*cur_page) != 1) {
+ DRM_ERROR("Erroneous page count. "
+ "Leaking pages.\n");
+ }
+
+ /*
+ * End debugging.
+ */
+
__free_page(*cur_page);
--bm->cur_pages;
}
@@ -526,20 +543,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry)
drm_unbind_ttm_region(entry);
if (be) {
- be->clear(entry->be);
-#if 0 /* Hmm, Isn't this done in unbind? */
- if (be->needs_cache_adjust(be)) {
- int ret = drm_ttm_lock_mmap_sem(ttm);
- drm_ttm_lock_mm(ttm, 0, 1);
- unmap_vma_pages(ttm, entry->page_offset,
- entry->num_pages);
- drm_ttm_unlock_mm(ttm, 0, 1);
- drm_set_caching(ttm, entry->page_offset,
- entry->num_pages, 0, 1);
- if (!ret)
- drm_ttm_unlock_mm(ttm, 1, 0);
- }
-#endif
+ be->clear(be);
be->destroy(be);
}
cur_page_flags = ttm->page_flags + entry->page_offset;
@@ -616,7 +620,7 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset,
drm_destroy_ttm_region(entry);
return -ENOMEM;
}
- SetPageReserved(*cur_page);
+ SetPageLocked(*cur_page);
++bm->cur_pages;
}
}
diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c
index e7b808cc..aed0e04f 100644
--- a/linux-core/drm_vm.c
+++ b/linux-core/drm_vm.c
@@ -276,16 +276,17 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma,
++bm->cur_pages;
page = ttm->pages[page_offset] =
alloc_page(GFP_KERNEL);
- SetPageReserved(page);
}
if (!page)
return NOPAGE_OOM;
+ SetPageLocked(page);
+ get_page(page);
+
default_prot = vm_get_page_prot(vma->vm_flags);
BUG_ON(page_flags & DRM_TTM_PAGE_UNCACHED);
vma->vm_page_prot = default_prot;
-
return page;
}