#include <linux/shmem_fs.h>
#include <linux/dma-buf.h>
#include <linux/mem_encrypt.h>
+#include <linux/pagevec.h>
#include <drm/drmP.h>
#include <drm/drm_vma_manager.h>
#include <drm/drm_gem.h>
}
EXPORT_SYMBOL(drm_gem_create_mmap_offset);
+/*
+ * Move pages to appropriate lru and release the pagevec, decrementing the
+ * ref count of those pages.
+ */
+static void drm_gem_check_release_pagevec(struct pagevec *pvec)
+{
+ check_move_unevictable_pages(pvec);
+ __pagevec_release(pvec);
+ cond_resched();
+}
+
/**
* drm_gem_get_pages - helper to allocate backing pages for a GEM object
* from shmem
{
struct address_space *mapping;
struct page *p, **pages;
+ struct pagevec pvec;
int i, npages;
/* This is the shared memory object that backs the GEM resource */
if (pages == NULL)
return ERR_PTR(-ENOMEM);
+ mapping_set_unevictable(mapping);
+
for (i = 0; i < npages; i++) {
p = shmem_read_mapping_page(mapping, i);
if (IS_ERR(p))
return pages;
fail:
- while (i--)
- put_page(pages[i]);
+ mapping_clear_unevictable(mapping);
+ pagevec_init(&pvec);
+ while (i--) {
+ if (!pagevec_add(&pvec, pages[i]))
+ drm_gem_check_release_pagevec(&pvec);
+ }
+ if (pagevec_count(&pvec))
+ drm_gem_check_release_pagevec(&pvec);
kvfree(pages);
return ERR_CAST(p);
bool dirty, bool accessed)
{
int i, npages;
+ struct address_space *mapping;
+ struct pagevec pvec;
+
+ mapping = file_inode(obj->filp)->i_mapping;
+ mapping_clear_unevictable(mapping);
/* We already BUG_ON() for non-page-aligned sizes in
* drm_gem_object_init(), so we should never hit this unless
npages = obj->size >> PAGE_SHIFT;
+ pagevec_init(&pvec);
for (i = 0; i < npages; i++) {
if (dirty)
set_page_dirty(pages[i]);
mark_page_accessed(pages[i]);
/* Undo the reference we took when populating the table */
- put_page(pages[i]);
+ if (!pagevec_add(&pvec, pages[i]))
+ drm_gem_check_release_pagevec(&pvec);
}
+ if (pagevec_count(&pvec))
+ drm_gem_check_release_pagevec(&pvec);
kvfree(pages);
}