[PATCH 4/5] drm/i915: Ouput the user virtual addresses for GFX buffers

Nidhi Gupta nidhi1.gupta at intel.com
Wed Feb 7 07:15:46 UTC 2018


From: Sourab Gupta <sourab.gupta at intel.com>

This patch adds the functionality to output the virtual addresses
of each GFX buffer, mapped into process address space (via interfaces
such as mmap and mmap_gtt).

Signed-off-by: Sourab Gupta <sourab.gupta at intel.com>
Signed-off-by: Akash Goel <akash.goel at intel.com>
Signed-off-by: Nidhi Gupta <nidhi1.gupta at intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h |   3 +
 drivers/gpu/drm/i915/i915_gem.c | 186 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 184 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index baa514f..9a6b45d 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -3573,6 +3573,9 @@ int i915_get_pid_cmdline(struct task_struct *task, char *buffer);
 int i915_gem_obj_insert_pid(struct drm_i915_gem_object *obj);
 void i915_gem_obj_remove_pid(struct drm_i915_gem_object *obj);
 void i915_gem_obj_remove_all_pids(struct drm_i915_gem_object *obj);
+int i915_obj_insert_virt_addr(struct drm_i915_gem_object *obj,
+				unsigned long addr, bool is_map_gtt,
+				bool is_mutex_locked);
 int i915_get_drm_clients_info(struct drm_i915_error_state_buf *m,
 				struct drm_device *dev);
 int i915_gem_get_obj_info(struct drm_i915_error_state_buf *m,
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 6000390..a641c73 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -90,10 +90,16 @@ struct pid_stat_entry {
 	int pid_num;
 };
 
+struct drm_i915_obj_virt_addr {
+	struct list_head head;
+	unsigned long user_virt_addr;
+};
+
 struct drm_i915_obj_pid_info {
 	struct list_head head;
 	pid_t tgid;
 	int open_handle_count;
+	struct list_head virt_addr_head;
 };
 
 struct get_obj_stats_buf {
@@ -1788,6 +1794,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
 	struct drm_i915_gem_mmap *args = data;
 	struct drm_i915_gem_object *obj;
 	unsigned long addr;
+	int ret;
 
 	if (args->flags & ~(I915_MMAP_WC))
 		return -EINVAL;
@@ -1833,6 +1840,10 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
 	if (IS_ERR((void *)addr))
 		return addr;
 
+	ret = i915_obj_insert_virt_addr(obj, addr, false, false);
+	if (ret)
+		return ret;
+
 	args->addr_ptr = (uint64_t) addr;
 
 	return 0;
@@ -2033,6 +2044,9 @@ int i915_gem_fault(struct vm_fault *vmf)
 	if (!i915_vma_set_userfault(vma) && !obj->userfault_count++)
 		list_add(&obj->userfault_link, &dev_priv->mm.userfault_list);
 	GEM_BUG_ON(!obj->userfault_count);
+	if (!ret)
+		ret = i915_obj_insert_virt_addr(obj,
+			(unsigned long)area->vm_start, true, true);
 
 	i915_vma_set_ggtt_write(vma);
 
@@ -6210,6 +6224,7 @@ int i915_gem_obj_insert_pid(struct drm_i915_gem_object *obj)
 		}
 		entry->tgid = current_tgid;
 		entry->open_handle_count = 1;
+		INIT_LIST_HEAD(&entry->virt_addr_head);
 		list_add_tail(&entry->head, &obj->pid_info);
 	}
 
@@ -6221,6 +6236,7 @@ void i915_gem_obj_remove_pid(struct drm_i915_gem_object *obj)
 {
 	pid_t current_tgid = task_tgid_nr(current);
 	struct drm_i915_obj_pid_info *pid_entry, *pid_next;
+	struct drm_i915_obj_virt_addr *virt_entry, *virt_next;
 	int found = 0;
 
 	if (!i915_modparams.memtrack_debug)
@@ -6233,6 +6249,13 @@ void i915_gem_obj_remove_pid(struct drm_i915_gem_object *obj)
 			pid_entry->open_handle_count--;
 			found = 1;
 			if (pid_entry->open_handle_count == 0) {
+				list_for_each_entry_safe(virt_entry,
+						virt_next,
+						&pid_entry->virt_addr_head,
+						head) {
+					list_del(&virt_entry->head);
+					kfree(virt_entry);
+				}
 				list_del(&pid_entry->head);
 				kfree(pid_entry);
 			}
@@ -6249,17 +6272,134 @@ void i915_gem_obj_remove_pid(struct drm_i915_gem_object *obj)
 void i915_gem_obj_remove_all_pids(struct drm_i915_gem_object *obj)
 {
 	struct drm_i915_obj_pid_info *pid_entry, *pid_next;
+	struct drm_i915_obj_virt_addr *virt_entry, *virt_next;
 
 	list_for_each_entry_safe(pid_entry, pid_next, &obj->pid_info, head) {
+		list_for_each_entry_safe(virt_entry,
+					 virt_next,
+					 &pid_entry->virt_addr_head,
+					 head) {
+			list_del(&virt_entry->head);
+			kfree(virt_entry);
+		}
 		list_del(&pid_entry->head);
 		kfree(pid_entry);
 	}
 }
 
+int
+i915_obj_insert_virt_addr(struct drm_i915_gem_object *obj,
+				unsigned long addr,
+				bool is_map_gtt,
+				bool is_mutex_locked)
+{
+	struct drm_i915_obj_pid_info *pid_entry;
+	pid_t current_tgid = task_tgid_nr(current);
+	int ret = 0, found = 0;
+
+	if (!true)
+		return 0;
+
+	if (is_map_gtt)
+		addr |= 1;
+
+	if (!is_mutex_locked) {
+		ret = i915_mutex_lock_interruptible(obj->base.dev);
+		if (ret)
+			return ret;
+	}
+
+	list_for_each_entry(pid_entry, &obj->pid_info, head) {
+		if (pid_entry->tgid == current_tgid) {
+			struct drm_i915_obj_virt_addr *virt_entry, *new_entry;
+
+			list_for_each_entry(virt_entry,
+					    &pid_entry->virt_addr_head,
+					    head) {
+				if (virt_entry->user_virt_addr == addr) {
+					found = 1;
+					break;
+				}
+			}
+			if (found)
+				break;
+			new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
+			if (new_entry == NULL) {
+				DRM_ERROR("alloc failed\n");
+				ret = -ENOMEM;
+				goto out;
+			}
+			new_entry->user_virt_addr = addr;
+			list_add_tail(&new_entry->head,
+				&pid_entry->virt_addr_head);
+			break;
+		}
+	}
+
+out:
+	if (!is_mutex_locked)
+		mutex_unlock(&obj->base.dev->struct_mutex);
+
+	return ret;
+}
+
+static int i915_obj_virt_addr_is_invalid(struct drm_gem_object *obj,
+				struct pid *tgid, unsigned long addr)
+{
+	struct task_struct *task;
+	struct mm_struct *mm;
+	struct vm_area_struct *vma;
+	int locked, ret = 0;
+
+	task = get_pid_task(tgid, PIDTYPE_PID);
+	if (task == NULL) {
+		DRM_DEBUG("null task for tgid=%d\n", pid_nr(tgid));
+		return -EINVAL;
+	}
+
+	mm = get_task_mm(task);
+	if (mm == NULL) {
+		DRM_DEBUG("null mm for tgid=%d\n", pid_nr(tgid));
+		ret = -EINVAL;
+		goto out_task;
+	}
+
+	locked = down_read_trylock(&mm->mmap_sem);
+	if (!locked)
+		goto out_mm;
+
+	vma = find_vma(mm, addr);
+	if (vma) {
+		if (addr & 1) { /* mmap_gtt case */
+			if (vma->vm_pgoff*PAGE_SIZE == (unsigned long)
+				drm_vma_node_offset_addr(&obj->vma_node))
+				ret = 0;
+			else
+				ret = -EINVAL;
+		} else { /* mmap case */
+			if (vma->vm_file == obj->filp)
+				ret = 0;
+			else
+				ret = -EINVAL;
+		}
+	} else
+		ret = -EINVAL;
+
+	up_read(&mm->mmap_sem);
+
+out_mm:
+	async_mmput(mm);
+out_task:
+	put_task_struct(task);
+	return ret;
+}
+
+
 static void i915_obj_pidarray_validate(struct drm_gem_object *gem_obj)
 {
 	struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
 	struct drm_device *dev = gem_obj->dev;
+	struct drm_i915_obj_virt_addr *virt_entry, *virt_next;
 	struct drm_i915_obj_pid_info *pid_entry, *pid_next;
 	struct drm_file *file;
 	struct drm_i915_file_private *file_priv;
@@ -6285,10 +6425,35 @@ static void i915_obj_pidarray_validate(struct drm_gem_object *gem_obj)
 			if (present == 0) {
 			DRM_DEBUG("stale_tgid=%d\n", pid_entry->tgid);
 			list_del(&pid_entry->head);
-			kfree(pid_entry);
+			list_for_each_entry_safe(virt_entry, virt_next,
+					&pid_entry->virt_addr_head,
+					head) {
+				list_del(&virt_entry->head);
+				kfree(virt_entry);
+			}
+		} else {
+			/* Validate the virtual address list */
+			struct task_struct *task =
+				get_pid_task(tgid, PIDTYPE_PID);
+			if (task == NULL)
+				continue;
+
+			list_for_each_entry_safe(virt_entry, virt_next,
+					&pid_entry->virt_addr_head,
+					head) {
+				if (i915_obj_virt_addr_is_invalid(gem_obj, tgid,
+					virt_entry->user_virt_addr)) {
+					DRM_DEBUG("stale_addr=%ld\n",
+					virt_entry->user_virt_addr);
+					list_del(&virt_entry->head);
+					kfree(virt_entry);
+				}
+			}
+			put_task_struct(task);
 			}
 		}
 }
+
 static int i915_obj_find_insert_in_hash(struct drm_i915_gem_object *obj,
 				struct pid_stat_entry *pid_entry,
 				bool *found)
@@ -6359,6 +6524,7 @@ i915_describe_obj(struct get_obj_stats_buf *obj_stat_buf,
 {
 	struct i915_vma *vma;
 	struct drm_i915_obj_pid_info *pid_info_entry;
+	struct drm_i915_obj_virt_addr *virt_entry;
 	struct drm_i915_error_state_buf *m = obj_stat_buf->m;
 	struct pid_stat_entry *pid_entry = obj_stat_buf->entry;
 	struct per_file_obj_mem_info *stats = &pid_entry->stats;
@@ -6416,11 +6582,21 @@ i915_describe_obj(struct get_obj_stats_buf *obj_stat_buf,
 	}
 	if (list_empty(&obj->vma_list))
 		err_puts(m, "                  ");
-
-	list_for_each_entry(pid_info_entry, &obj->pid_info, head)
-		i915_error_printf(m, " (%d: %d)",
+	list_for_each_entry(pid_info_entry, &obj->pid_info, head) {
+		err_printf(m, " (%d: %d:",
 			   pid_info_entry->tgid,
 			   pid_info_entry->open_handle_count);
+		list_for_each_entry(virt_entry,
+				    &pid_info_entry->virt_addr_head, head) {
+			if (virt_entry->user_virt_addr & 1)
+				err_printf(m, " %p",
+				(void *)(virt_entry->user_virt_addr & ~1));
+			else
+				err_printf(m, " %p*",
+				(void *)virt_entry->user_virt_addr);
+		}
+		err_puts(m, ") ");
+	}
 
 	err_puts(m, "\n");
 
@@ -6704,7 +6880,7 @@ __i915_gem_get_obj_info(struct drm_i915_error_state_buf *m,
 
 		file_priv_reqd = file_priv;
 		err_puts(m,
-			"\n Obj Identifier   Obj-Size Resident-Size Pin Tiling Dirty Shared Vmap Stolen Mappable  AllocState Global/PP  GttOffset (PID: handle count)\n");
+			"\n Obj Identifier   Obj-Size Resident-Size Pin Tiling Dirty Shared Vmap Stolen Mappable  AllocState Global/PP  GttOffset (PID: handle count: user virt addrs)\n");
 		spin_lock(&file->table_lock);
 		ret = idr_for_each(&file->object_idr,
 				&i915_drm_gem_obj_info, &obj_stat_buf);
-- 
2.7.4



More information about the Intel-gfx-trybot mailing list