[intel-gem] Use shmem_getpage instead of find_or_create_page
find_or_create_page doesn't quite set up pages correctly; any newly created pages aren't hooked into the shmem object quite right; user space mmaps of those pages end up mapping pages full of zeros which then get written to the real pages inappropriately. This patch requires that the kernel export shmem_getpage.main
parent
52e5d24fae
commit
918420deef
|
@ -320,8 +320,13 @@ i915_gem_object_free_page_list(struct drm_gem_object *obj)
|
|||
|
||||
|
||||
for (i = 0; i < page_count; i++)
|
||||
if (obj_priv->page_list[i] != NULL)
|
||||
if (obj_priv->page_list[i] != NULL) {
|
||||
if (obj_priv->dirty)
|
||||
set_page_dirty(obj_priv->page_list[i]);
|
||||
mark_page_accessed(obj_priv->page_list[i]);
|
||||
page_cache_release(obj_priv->page_list[i]);
|
||||
}
|
||||
obj_priv->dirty = 0;
|
||||
|
||||
drm_free(obj_priv->page_list,
|
||||
page_count * sizeof(struct page *),
|
||||
|
@ -969,6 +974,11 @@ i915_gem_object_get_page_list(struct drm_gem_object *obj)
|
|||
{
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
int page_count, i;
|
||||
struct address_space *mapping;
|
||||
struct inode *inode;
|
||||
struct page *page;
|
||||
int ret;
|
||||
|
||||
if (obj_priv->page_list)
|
||||
return 0;
|
||||
|
||||
|
@ -984,16 +994,25 @@ i915_gem_object_get_page_list(struct drm_gem_object *obj)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
inode = obj->filp->f_path.dentry->d_inode;
|
||||
mapping = inode->i_mapping;
|
||||
for (i = 0; i < page_count; i++) {
|
||||
obj_priv->page_list[i] =
|
||||
find_or_create_page(obj->filp->f_mapping, i, GFP_HIGHUSER);
|
||||
|
||||
if (obj_priv->page_list[i] == NULL) {
|
||||
DRM_ERROR("Failed to find_or_create_page()\n");
|
||||
i915_gem_object_free_page_list(obj);
|
||||
return -ENOMEM;
|
||||
page = find_get_page(mapping, i);
|
||||
if (page == NULL || !PageUptodate(page)) {
|
||||
if (page) {
|
||||
page_cache_release(page);
|
||||
page = NULL;
|
||||
}
|
||||
ret = shmem_getpage(inode, i, &page, SGP_DIRTY, NULL);
|
||||
|
||||
if (ret) {
|
||||
DRM_ERROR("shmem_getpage failed: %d\n", ret);
|
||||
i915_gem_object_free_page_list(obj);
|
||||
return ret;
|
||||
}
|
||||
unlock_page(page);
|
||||
}
|
||||
unlock_page(obj_priv->page_list[i]);
|
||||
obj_priv->page_list[i] = page;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1239,6 +1258,8 @@ i915_gem_object_set_domain(struct drm_gem_object *obj,
|
|||
*/
|
||||
if (write_domain == 0)
|
||||
read_domains |= obj->read_domains;
|
||||
else
|
||||
obj_priv->dirty = 1;
|
||||
|
||||
/*
|
||||
* Flush the current write domain if
|
||||
|
@ -2046,6 +2067,11 @@ int i915_gem_init_object(struct drm_gem_object *obj)
|
|||
|
||||
void i915_gem_free_object(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
|
||||
while (obj_priv->pin_count > 0)
|
||||
i915_gem_object_unpin(obj);
|
||||
|
||||
i915_gem_object_unbind(obj);
|
||||
|
||||
drm_free(obj->driver_private, 1, DRM_MEM_DRIVER);
|
||||
|
|
|
@ -332,6 +332,12 @@ struct drm_i915_gem_object {
|
|||
*/
|
||||
int active;
|
||||
|
||||
/**
|
||||
* This is set if the object has been written to since last bound
|
||||
* to the GTT
|
||||
*/
|
||||
int dirty;
|
||||
|
||||
/** AGP memory structure for our GTT binding. */
|
||||
DRM_AGP_MEM *agp_mem;
|
||||
|
||||
|
|
Loading…
Reference in New Issue