Unified VMA Offset Manager v2 (+Render Node RFC)
Subsystems (16)
v2 cover Unified VMA Offset Manager v2 (+Render Node RFC)
Hi
This is v2 of the unified VMA offset manager series. The first draft is available at LWN [1]. This series replaces the VMA offset managers in GEM and TTM with a unified implementation.
The first 4 patches contain the new VMA offset manager and are the only patches that I propose for mainline inclusion.
Patches 5-8 clean up drm_mm and are informational-only. Daniel has similar patches in i915-next and I will rebase them once it is merged. Ignore them if you're not interested.
Patches 9-19 implement mmap access control. Comments are welcome! They are intended for mainline inclusion, too, but probably require some more review rounds. I'd really appreciate if driver authors could comment on the implementation.
Patch 20 shows the main motivation behind this whole series: render nodes. It is marked RFC and I will resend once the VMA manager is merged upstream. Feel free to test it.
One more note regarding DRM-Master: Render-clients are independent of DRM-Master (see the DocBook documentation). It really doesn't make sense to create/bind a DRM-Master object to render-clients. However, a lot of core DRM code depends on
->master != NULL. Drivers need to take care not to call into those core modules
if they implement DRIVER_RENDER.
I plan on removing multiple-master-support in the next series. So there will be only one global master and each open-file is bound to it. This will make it very easy to phase out "drm_master". The planned "modeset" nodes provide a nice replacement. If anyone knows a **currently used** use-case for multiple-masters, please tell me. I couldn't find one that _actually works_. (SetMaster+DropMaster will obviously stay functional even with drm_master removed).
(series available at: https://github.com/dvdhrm/linux/tree/rnodes)
Comments welcome!
Cheers
David
Changes in v2:
- Drop drm_mm_init() fix (already applied in drm-next)
- Drop drm_mm_node_linked() in favor of drm_mm_node_allocated()
- Adjust DocBook integration
- Rebased on drm-next (and compile tested on ARM)
- Removed unnecessary likely/unlikely marks (except for rbtree paths)
- small fixes (see commit messages for more)
New in v2:
- Cleanup patches for drm_mm. Note that these are marked RFC as Daniel has similar patches pending in i915-next. But the patches show that most of drm_mm is obsolete and can be removed.
I will rebase them once i915-next is merged into drm-next and resend.
- Access Management API: Following Dave's proposal, this series implements mmap-offset access managamenet via a "file_priv" lookup-tree for each node.
- Render-Nodes: Following krh's proposal, I revived render nodes which no longer have the mmap security problem. Driver-implementations still missing, but you can find working examples for i915 and nouveau on dri-devel or [2].
Still To Do:
- See whether _DRM_GEM can be dropped. I haven't checked legacy user-space so far.
- Patch #16 (vmwgfx) has a TODO marker. I couldn't figure out whether the proposed replacement does the same as the old code (with all the side-effects). Would be nice if Thomas could comment on that (CC'ed).
- Patch #18 (gem mmap) adds filp to all VMAs during open and removes them during close. This is not necessary for TTM+GEM drivers which don't use gem_mmap(). However, it works for now and I wanted to avoid 20 more patches fixing each GEM driver. I will provide that in the final series.
[1] Unified VMA Offset Manager v1: https://lwn.net/Articles/557265/
[2] Render-node driver patches: https://gitorious.org/linux-nouveau-pm/linux-nouveau-pm/commits/render_nodes
David Herrmann (20):
drm: add unified vma offset manager
drm/gem: convert to new unified vma manager drm/ttm: convert to unified vma offset manager drm/vma: provide drm_vma_node_unmap() helper drm/mm: add "best_match" to drm_mm_insert_node() drm/ttm: replace drm_mm_pre_get() by direct alloc drm/i915: pre-alloc instead of drm_mm search/get_block drm/mm: remove unused API
drm/vma: add access management helpers drm/ast: implement mmap access managament drm/cirrus: implement mmap access managament drm/mgag200: implement mmap access managament drm/nouveau: implement mmap access managament drm/radeon: implement mmap access managament drm/qxl: implement mmap access managament drm/vmwgfx: implement mmap access managament drm/ttm: prevent mmap access to unauthorized users drm/gem: implement mmap access management
drm: fix minor number range calculation
drm: implement render nodes
Documentation/DocBook/drm.tmpl | 77 ++++++ drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/ast/ast_drv.c | 2 + drivers/gpu/drm/ast/ast_drv.h | 4 + drivers/gpu/drm/ast/ast_main.c | 17 +- drivers/gpu/drm/cirrus/cirrus_drv.h | 4 + drivers/gpu/drm/cirrus/cirrus_main.c | 17 +- drivers/gpu/drm/drm_drv.c | 15 +- drivers/gpu/drm/drm_fops.c | 14 +- drivers/gpu/drm/drm_gem.c | 111 +++----- drivers/gpu/drm/drm_gem_cma_helper.c | 9 +- drivers/gpu/drm/drm_mm.c | 139 ++-------- drivers/gpu/drm/drm_pci.c | 9 + drivers/gpu/drm/drm_platform.c | 9 + drivers/gpu/drm/drm_stub.c | 17 +- drivers/gpu/drm/drm_usb.c | 9 + drivers/gpu/drm/drm_vma_manager.c | 408 +++++++++++++++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_gem.c | 7 +- drivers/gpu/drm/gma500/gem.c | 8 +- drivers/gpu/drm/i915/i915_gem.c | 25 +- drivers/gpu/drm/i915/i915_gem_stolen.c | 72 +++-- drivers/gpu/drm/mgag200/mgag200_drv.c | 2 + drivers/gpu/drm/mgag200/mgag200_drv.h | 4 + drivers/gpu/drm/mgag200/mgag200_main.c | 17 +- drivers/gpu/drm/nouveau/nouveau_display.c | 2 +- drivers/gpu/drm/nouveau/nouveau_gem.c | 21 +- drivers/gpu/drm/omapdrm/omap_gem.c | 11 +- drivers/gpu/drm/omapdrm/omap_gem_helpers.c | 49 +--- drivers/gpu/drm/qxl/qxl_gem.c | 7 +- drivers/gpu/drm/qxl/qxl_object.h | 2 +- drivers/gpu/drm/qxl/qxl_release.c | 2 +- drivers/gpu/drm/radeon/radeon_gem.c | 7 + drivers/gpu/drm/radeon/radeon_object.h | 5 +- drivers/gpu/drm/sis/sis_mm.c | 4 +- drivers/gpu/drm/ttm/ttm_bo.c | 79 +----- drivers/gpu/drm/ttm/ttm_bo_manager.c | 40 ++- drivers/gpu/drm/ttm/ttm_bo_util.c | 3 +- drivers/gpu/drm/ttm/ttm_bo_vm.c | 82 +++--- drivers/gpu/drm/udl/udl_gem.c | 6 +- drivers/gpu/drm/via/via_mm.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 33 ++- include/drm/drmP.h | 15 +- include/drm/drm_mm.h | 110 ++------ include/drm/drm_vma_manager.h | 170 ++++++++++++ include/drm/ttm/ttm_bo_api.h | 15 +- include/drm/ttm/ttm_bo_driver.h | 7 +- include/uapi/drm/drm.h | 2 +- 47 files changed, 1074 insertions(+), 600 deletions(-) create mode 100644 drivers/gpu/drm/drm_vma_manager.c create mode 100644 include/drm/drm_vma_manager.h
Signature · 1 line
1.8.3.2
PATCH v2 1/20 drm: add unified vma offset manager
If we want to map GPU memory into user-space, we need to linearize the addresses to not confuse mm-core. Currently, GEM and TTM both implement their own offset-managers to assign a pgoff to each object for user-space CPU access. GEM uses a hash-table, TTM uses an rbtree.
This patch provides a unified implementation that can be used to replace both. TTM allows partial mmaps with a given offset, so we cannot use hashtables as the start address may not be known at mmap time. Hence, we use the rbtree-implementation of TTM.
We could easily update drm_mm to use an rbtree instead of a linked list for it's object list and thus drop the rbtree from the vma-manager. However, this would slow down drm_mm object allocation for all other use-cases (rbtree insertion) and add another 4-8 bytes to each mm node. Hence, use the separate tree but allow for later migration.
This is a rewrite of the 2012-proposal by David Airlie <[email protected]>
v2:
- fix Docbook integration
- drop drm_mm_node_linked() and use drm_mm_node_allocated()
- remove unjustified likely/unlikely usage (but keep for rbtree paths)
- remove BUG_ON() as drm_mm already does that
- clarify page-based vs. byte-based addresses
- use drm_vma_node_reset() for initialization, too
--- Documentation/DocBook/drm.tmpl | 6 + drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_vma_manager.c | 260 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_vma_manager.h | 139 ++++++++++++++++++++ 4 files changed, 406 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_vma_manager.c create mode 100644 include/drm/drm_vma_manager.h
Documentation/DocBook/drm.tmpl +6 -0
@@ -2212,6 +2212,12 @@ void intel_crt_init(struct drm_device *dev) !Iinclude/drm/drm_rect.h !Edrivers/gpu/drm/drm_rect.c </sect2> + <sect2> + <title>VMA Offset Manager</title> +!Pdrivers/gpu/drm/drm_vma_manager.c vma offset manager +!Edrivers/gpu/drm/drm_vma_manager.c +!Iinclude/drm/drm_vma_manager.h + </sect2> </sect1> <!-- Internals: kms properties -->
drivers/gpu/drm/Makefile +1 -1
@@ -13,7 +13,7 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \ drm_crtc.o drm_modes.o drm_edid.o \ drm_info.o drm_debugfs.o drm_encoder_slave.o \ drm_trace_points.o drm_global.o drm_prime.o \ - drm_rect.o + drm_rect.o drm_vma_manager.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
drivers/gpu/drm/drm_vma_manager.c new file +260 -0
260 lines not on this page · raw message
include/drm/drm_vma_manager.h new file +139 -0
139 lines not on this page · raw message
Signature · 1 line
1.8.3.2
PATCH v2 2/20 drm/gem: convert to new unified vma manager
In reply to David HerrmannUse the new vma manager instead of the old hashtable. Also convert all drivers to use the new convenience helpers. This drops all the (map_list.hash.key << PAGE_SHIFT) non-sense.
Locking and access-management is exactly the same as before with an additional lock inside of the vma-manager, which strictly wouldn't be needed for gem.
v2:
- rebase on drm-next
- init nodes via drm_vma_node_reset() in drm_gem.c
--- drivers/gpu/drm/drm_gem.c | 90 ++++++------------------------ drivers/gpu/drm/drm_gem_cma_helper.c | 9 +-- drivers/gpu/drm/exynos/exynos_drm_gem.c | 7 ++- drivers/gpu/drm/gma500/gem.c | 8 +-- drivers/gpu/drm/i915/i915_gem.c | 9 +-- drivers/gpu/drm/omapdrm/omap_gem.c | 11 ++-- drivers/gpu/drm/omapdrm/omap_gem_helpers.c | 49 +--------------- drivers/gpu/drm/udl/udl_gem.c | 6 +- include/drm/drmP.h | 7 +-- include/drm/drm_vma_manager.h | 1 - include/uapi/drm/drm.h | 2 +- 11 files changed, 49 insertions(+), 150 deletions(-)
drivers/gpu/drm/drm_gem.c +16 -74
@@ -37,6 +37,7 @@#include <linux/shmem_fs.h> #include <linux/dma-buf.h> #include <drm/drmP.h> +#include <drm/drm_vma_manager.h> /** @file drm_gem.c *
@@ -102,14 +103,9 @@ drm_gem_init(struct drm_device *dev) } dev->mm_private = mm; - -if (drm_ht_create (&mm->offset_hash,12 )) { -kfree (mm); -return -ENOMEM ; - } - -drm_mm_init (&mm->offset_manager,DRM_FILE_PAGE_OFFSET_START , -DRM_FILE_PAGE_OFFSET_SIZE ); +drm_vma_offset_manager_init (&mm->vma_manager, +DRM_FILE_PAGE_OFFSET_START , +DRM_FILE_PAGE_OFFSET_SIZE );return 0 ; }
@@ -119,8 +115,7 @@ drm_gem_destroy(struct drm_device *dev) {struct drm_gem_mm *mm = dev->mm_private; -drm_mm_takedown (&mm->offset_manager); -drm_ht_remove (&mm->offset_hash); +drm_vma_offset_manager_destroy (&mm->vma_manager);kfree (mm); dev->mm_private =NULL ; }
@@ -141,6 +136,7 @@ int drm_gem_object_init(struct drm_device *dev,kref_init (&obj->refcount);atomic_set (&obj->handle_count,0 ); +drm_vma_node_reset (&obj->vma_node); obj->size = size;return 0 ;
@@ -162,6 +158,7 @@ int drm_gem_private_object_init(struct drm_device *dev,kref_init (&obj->refcount);atomic_set (&obj->handle_count,0 ); +drm_vma_node_reset (&obj->vma_node); obj->size = size;return 0 ;
@@ -306,12 +303,8 @@ drm_gem_free_mmap_offset(struct drm_gem_object *obj) {struct drm_device *dev = obj->dev;struct drm_gem_mm *mm = dev->mm_private; -struct drm_map_list *list = &obj->map_list; -drm_ht_remove_item (&mm->offset_hash, &list->hash); -drm_mm_put_block (list->file_offset_node); -kfree (list->map); - list->map =NULL ; +drm_vma_offset_remove (&mm->vma_manager, &obj->vma_node); }EXPORT_SYMBOL (drm_gem_free_mmap_offset);
@@ -331,54 +324,9 @@ drm_gem_create_mmap_offset(struct drm_gem_object *obj) {struct drm_device *dev = obj->dev;struct drm_gem_mm *mm = dev->mm_private; -struct drm_map_list *list; -struct drm_local_map *map; -int ret; - -/* Set the object up for mmap'ing */ - list = &obj->map_list; - list->map =kzalloc (sizeof (struct drm_map_list ),GFP_KERNEL ); -if (!list->map) -return -ENOMEM ; - - map = list->map; - map->type = _DRM_GEM; - map->size = obj->size; - map->handle = obj; - -/* Get a DRM GEM mmap offset allocated... */ - list->file_offset_node =drm_mm_search_free (&mm->offset_manager, - obj->size /PAGE_SIZE ,0 , false); - -if (!list->file_offset_node) { -DRM_ERROR ("failed to allocate offset for bo %d\n" , obj->name); - ret = -ENOSPC ; - goto out_free_list; - } - list->file_offset_node =drm_mm_get_block (list->file_offset_node, - obj->size /PAGE_SIZE ,0 ); -if (!list->file_offset_node) { - ret = -ENOMEM ; - goto out_free_list; - } - - list->hash.key = list->file_offset_node->start; - ret =drm_ht_insert_item (&mm->offset_hash, &list->hash); -if (ret) { -DRM_ERROR ("failed to add to map hash\n" ); - goto out_free_mm; - } - -return 0 ; - -out_free_mm: -drm_mm_put_block (list->file_offset_node); -out_free_list: -kfree (list->map); - list->map =NULL ; - -return ret; +return drm_vma_offset_add (&mm->vma_manager, &obj->vma_node, + obj->size /PAGE_SIZE ); }EXPORT_SYMBOL (drm_gem_create_mmap_offset);
@@ -707,8 +655,8 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)struct drm_file *priv = filp->private_data;struct drm_device *dev = priv->minor->dev;struct drm_gem_mm *mm = dev->mm_private; -struct drm_local_map *map =NULL ; -struct drm_hash_item *hash; +struct drm_gem_object *obj; +struct drm_vma_offset_node *node;int ret =0 ;if (drm_device_is_unplugged (dev))
@@ -716,21 +664,15 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)mutex_lock (&dev->struct_mutex); -if (drm_ht_find_item (&mm->offset_hash, vma->vm_pgoff, &hash)) { + node =drm_vma_offset_exact_lookup (&mm->vma_manager, vma->vm_pgoff); +if (!node) {mutex_unlock (&dev->struct_mutex);return drm_mmap (filp, vma); } - map = drm_hash_entry(hash, struct drm_map_list, hash)->map; -if (!map || - ((map->flags & _DRM_RESTRICTED) && !capable (CAP_SYS_ADMIN ))) { - ret = -EPERM ; - goto out_unlock; - } - - ret =drm_gem_mmap_obj (map->handle, map->size, vma); + obj = container_of(node, struct drm_gem_object, vma_node); + ret =drm_gem_mmap_obj (obj, node->vm_pages, vma); -out_unlock:mutex_unlock (&dev->struct_mutex);return ret;
drivers/gpu/drm/drm_gem_cma_helper.c +5 -4
@@ -27,10 +27,11 @@#include <drm/drmP.h> #include <drm/drm.h> #include <drm/drm_gem_cma_helper.h> +#include <drm/drm_vma_manager.h> static unsigned int get_gem_mmap_offset (struct drm_gem_object *obj) { -return (unsigned int )obj->map_list.hash.key <<PAGE_SHIFT ; +return (unsigned int )drm_vma_node_offset_addr (&obj->vma_node); }/*
@@ -172,7 +173,7 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj) {struct drm_gem_cma_object *cma_obj; -if (gem_obj->map_list.map) +if (drm_vma_node_has_offset (&gem_obj->vma_node))drm_gem_free_mmap_offset (gem_obj); cma_obj =to_drm_gem_cma_obj (gem_obj);
@@ -305,8 +306,8 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *mWARN_ON (!mutex_is_locked (&dev->struct_mutex)); -if (obj->map_list.map) - off = (uint64_t )obj->map_list.hash.key; +if (drm_vma_node_has_offset (&obj->vma_node)) + off =drm_vma_node_start (&obj->vma_node); seq_printf(m, "%2d (%2d) %08llx %08Zx %p %d", obj->name, obj->refcount.refcount.counter,
drivers/gpu/drm/exynos/exynos_drm_gem.c +4 -3
@@ -10,6 +10,7 @@*/ #include <drm/drmP.h> +#include <drm/drm_vma_manager.h> #include <linux/shmem_fs.h> #include <drm/exynos_drm.h>
@@ -152,7 +153,7 @@ out:exynos_drm_fini_buf (obj->dev, buf); exynos_gem_obj->buffer =NULL ; -if (obj->map_list.map) +if (drm_vma_node_has_offset (&obj->vma_node))drm_gem_free_mmap_offset (obj);/* release file pointer to gem object. */
@@ -702,13 +703,13 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, goto unlock; } -if (!obj->map_list.map) { +if (!drm_vma_node_has_offset (&obj->vma_node)) { ret =drm_gem_create_mmap_offset (obj);if (ret) goto out; } - *offset = (u64 )obj->map_list.hash.key <<PAGE_SHIFT ; + *offset =drm_vma_node_offset_addr (&obj->vma_node);DRM_DEBUG_KMS ("offset = 0x%lx\n" , (unsigned long )*offset); out:
drivers/gpu/drm/gma500/gem.c +4 -4
@@ -26,6 +26,7 @@#include <drm/drmP.h> #include <drm/drm.h> #include <drm/gma_drm.h> +#include <drm/drm_vma_manager.h> #include "psb_drv.h" int psb_gem_init_object (struct drm_gem_object *obj)
@@ -38,7 +39,7 @@ void psb_gem_free_object(struct drm_gem_object *obj) struct gtt_range *gtt = container_of(obj, struct gtt_range, gem);/* Remove the list map if one is present */ -if (obj->map_list.map) +if (drm_vma_node_has_offset (&obj->vma_node))drm_gem_free_mmap_offset (obj);drm_gem_object_release (obj);
@@ -81,13 +82,12 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev,/* What validation is needed here ? */ /* Make it mmapable */ -if (!obj->map_list.map) { +if (!drm_vma_node_has_offset (&obj->vma_node)) { ret =drm_gem_create_mmap_offset (obj);if (ret) goto out; } -/* GEM should really work out the hash offsets for us */ - *offset = (u64 )obj->map_list.hash.key <<PAGE_SHIFT ; + *offset =drm_vma_node_offset_addr (&obj->vma_node); out:drm_gem_object_unreference (obj); unlock:
drivers/gpu/drm/i915/i915_gem.c +5 -4
@@ -26,6 +26,7 @@*/ #include <drm/drmP.h> +#include <drm/drm_vma_manager.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include "i915_trace.h"
@@ -1427,7 +1428,7 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj)if (obj->base.dev->dev_mapping)unmap_mapping_range (obj->base.dev->dev_mapping, - (loff_t )obj->base.map_list.hash.key<<PAGE_SHIFT , + (loff_t )drm_vma_node_offset_addr (&obj->base.vma_node), obj->base.size,1 ); obj->fault_mappable = false;
@@ -1485,7 +1486,7 @@ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)struct drm_i915_private *dev_priv = obj->base.dev->dev_private;int ret; -if (obj->base.map_list.map) +if (drm_vma_node_has_offset (&obj->base.vma_node))return 0 ; dev_priv->mm.shrinker_no_lock_stealing = true;
@@ -1516,7 +1517,7 @@ out:static void i915_gem_object_free_mmap_offset (struct drm_i915_gem_object *obj) { -if (!obj->base.map_list.map) +if (!drm_vma_node_has_offset (&obj->base.vma_node))return ;drm_gem_free_mmap_offset (&obj->base);
@@ -1557,7 +1558,7 @@ i915_gem_mmap_gtt(struct drm_file *file,if (ret) goto out; - *offset = (u64 )obj->base.map_list.hash.key <<PAGE_SHIFT ; + *offset =drm_vma_node_offset_addr (&obj->base.vma_node); out:drm_gem_object_unreference (&obj->base);
drivers/gpu/drm/omapdrm/omap_gem.c +6 -5
@@ -20,6 +20,7 @@#include <linux/spinlock.h> #include <linux/shmem_fs.h> +#include <drm/drm_vma_manager.h> #include "omap_drv.h" #include "omap_dmm_tiler.h"
@@ -311,7 +312,7 @@ static uint64_t mmap_offset(struct drm_gem_object *obj)WARN_ON (!mutex_is_locked (&dev->struct_mutex)); -if (!obj->map_list.map) { +if (!drm_vma_node_has_offset (&obj->vma_node)) {/* Make it mmapable */ size_t size =omap_gem_mmap_size (obj);int ret =_drm_gem_create_mmap_offset_size (obj, size);
@@ -322,7 +323,7 @@ static uint64_t mmap_offset(struct drm_gem_object *obj) } } -return (uint64_t )obj->map_list.hash.key <<PAGE_SHIFT ; +return drm_vma_node_offset_addr (&obj->vma_node); }uint64_t omap_gem_mmap_offset (struct drm_gem_object *obj)
@@ -1001,8 +1002,8 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m)WARN_ON (!mutex_is_locked (&dev->struct_mutex)); -if (obj->map_list.map) - off = (uint64_t )obj->map_list.hash.key; +if (drm_vma_node_has_offset (&obj->vma_node)) + off =drm_vma_node_start (&obj->vma_node); seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d", omap_obj->flags, obj->name, obj->refcount.refcount.counter,
@@ -1309,7 +1310,7 @@ void omap_gem_free_object(struct drm_gem_object *obj)list_del (&omap_obj->mm_list); -if (obj->map_list.map) +if (drm_vma_node_has_offset (&obj->vma_node))drm_gem_free_mmap_offset (obj);/* this means the object is still pinned.. which really should
drivers/gpu/drm/omapdrm/omap_gem_helpers.c +2 -47
54 lines not on this page · raw message
drivers/gpu/drm/udl/udl_gem.c +3 -3
@@ -223,7 +223,7 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj)if (obj->pages)udl_gem_put_pages (obj); -if (gem_obj->map_list.map) +if (drm_vma_node_has_offset (&gem_obj->vma_node))drm_gem_free_mmap_offset (gem_obj); }
@@ -247,13 +247,13 @@ int udl_gem_mmap(struct drm_file *file, struct drm_device *dev, ret =udl_gem_get_pages (gobj,GFP_KERNEL );if (ret) goto out; -if (!gobj->base.map_list.map) { +if (!drm_vma_node_has_offset (&gobj->base.vma_node)) { ret =drm_gem_create_mmap_offset (obj);if (ret) goto out; } - *offset = (u64 )gobj->base.map_list.hash.key <<PAGE_SHIFT ; + *offset =drm_vma_node_offset_addr (&gobj->base.vma_node); out:drm_gem_object_unreference (&gobj->base);
include/drm/drmP.h +3 -4
@@ -71,6 +71,7 @@#include <asm/pgalloc.h> #include <drm/drm.h> #include <drm/drm_sarea.h> +#include <drm/drm_vma_manager.h> #include <linux/idr.h>
@@ -587,7 +588,6 @@ struct drm_map_list {struct drm_local_map *map;/**< mapping */ uint64_t user_token;struct drm_master *master; -struct drm_mm_node *file_offset_node;/**< fake offset */ };/**
@@ -622,8 +622,7 @@ struct drm_ati_pcigart_info {* GEM specific mm private for tracking GEM objects */ struct drm_gem_mm { -struct drm_mm offset_manager;/**< Offset mgmt for buffer objects */ -struct drm_open_hash offset_hash;/**< User token hash table for maps */ +struct drm_vma_offset_manager vma_manager; };/**
@@ -644,7 +643,7 @@ struct drm_gem_object {struct file *filp;/* Mapping info for this object */ -struct drm_map_list map_list; +struct drm_vma_offset_node vma_node;/** * Size of the object, in bytes. Immutable over the object's
include/drm/drm_vma_manager.h +0 -1
@@ -23,7 +23,6 @@* OTHER DEALINGS IN THE SOFTWARE. */ -#include <drm/drmP.h> #include <drm/drm_mm.h> #include <linux/module.h> #include <linux/rbtree.h>
include/uapi/drm/drm.h +1 -1
@@ -181,7 +181,7 @@ enum drm_map_type { _DRM_AGP =3 ,/**< AGP/GART */ _DRM_SCATTER_GATHER =4 ,/**< Scatter/gather memory for PCI DMA */ _DRM_CONSISTENT =5 ,/**< Consistent memory for PCI DMA */ - _DRM_GEM = 6, /**< GEM object */ + _DRM_GEM = 6, /**< GEM object (obsolete) */ };/**
Signature · 1 line
1.8.3.2
Re: [PATCH v2 02/20] drm/gem: convert to new unified vma manager
Hi
Quoted 11 lines · David Herrmann
Use the new vma manager instead of the old hashtable. Also convert all drivers to use the new convenience helpers. This drops all the (map_list.hash.key <<
PAGE_SHIFT) non-sense.Locking and access-management is exactly the same as before with an additional lock inside of the vma-manager, which strictly wouldn't be needed for gem.
v2:
- rebase on drm-next
- init nodes viadrm_vma_node_reset()indrm_gem.c
I missed the tegra driver and any staging driver. I will fix that in v3 and reduce the series to a minimum.
Regards
David
Quoted 543 lines
Signed-off-by David Herrmann <[email protected]>--- drivers/gpu/drm/drm_gem.c | 90 ++++++------------------------ drivers/gpu/drm/drm_gem_cma_helper.c | 9 +-- drivers/gpu/drm/exynos/exynos_drm_gem.c | 7 ++- drivers/gpu/drm/gma500/gem.c | 8 +-- drivers/gpu/drm/i915/i915_gem.c | 9 +-- drivers/gpu/drm/omapdrm/omap_gem.c | 11 ++-- drivers/gpu/drm/omapdrm/omap_gem_helpers.c | 49 +--------------- drivers/gpu/drm/udl/udl_gem.c | 6 +- include/drm/drmP.h | 7 +-- include/drm/drm_vma_manager.h | 1 - include/uapi/drm/drm.h | 2 +- 11 files changed, 49 insertions(+), 150 deletions(-)drivers/gpu/drm/drm_gem.c +16
-74@@ -37,6 +37,7 @@#include <linux/shmem_fs.h> #include <linux/dma-buf.h> #include <drm/drmP.h> +#include <drm/drm_vma_manager.h> /** @file drm_gem.c * @@ -102,14 +103,9 @@ drm_gem_init(struct drm_device *dev) } dev->mm_private = mm; - -if (drm_ht_create (&mm->offset_hash,12 )) { -kfree (mm); -return -ENOMEM ; - } - -drm_mm_init (&mm->offset_manager,DRM_FILE_PAGE_OFFSET_START , -DRM_FILE_PAGE_OFFSET_SIZE ); +drm_vma_offset_manager_init (&mm->vma_manager, +DRM_FILE_PAGE_OFFSET_START , +DRM_FILE_PAGE_OFFSET_SIZE );return 0 ; }@@ -119,8 +115,7 @@ drm_gem_destroy(struct drm_device *dev) {struct drm_gem_mm *mm = dev->mm_private; -drm_mm_takedown (&mm->offset_manager); -drm_ht_remove (&mm->offset_hash); +drm_vma_offset_manager_destroy (&mm->vma_manager);kfree (mm); dev->mm_private =NULL ; }@@ -141,6 +136,7 @@ int drm_gem_object_init(struct drm_device *dev,kref_init (&obj->refcount);atomic_set (&obj->handle_count,0 ); +drm_vma_node_reset (&obj->vma_node); obj->size = size;return 0 ;@@ -162,6 +158,7 @@ int drm_gem_private_object_init(struct drm_device *dev,kref_init (&obj->refcount);atomic_set (&obj->handle_count,0 ); +drm_vma_node_reset (&obj->vma_node); obj->size = size;return 0 ;@@ -306,12 +303,8 @@ drm_gem_free_mmap_offset(struct drm_gem_object *obj) {struct drm_device *dev = obj->dev;struct drm_gem_mm *mm = dev->mm_private; -struct drm_map_list *list = &obj->map_list; -drm_ht_remove_item (&mm->offset_hash, &list->hash); -drm_mm_put_block (list->file_offset_node); -kfree (list->map); - list->map =NULL ; +drm_vma_offset_remove (&mm->vma_manager, &obj->vma_node); }EXPORT_SYMBOL (drm_gem_free_mmap_offset);@@ -331,54 +324,9 @@ drm_gem_create_mmap_offset(struct drm_gem_object *obj) {struct drm_device *dev = obj->dev;struct drm_gem_mm *mm = dev->mm_private; -struct drm_map_list *list; -struct drm_local_map *map; -int ret; - -/* Set the object up for mmap'ing */ - list = &obj->map_list; - list->map =kzalloc (sizeof (struct drm_map_list ),GFP_KERNEL ); -if (!list->map) -return -ENOMEM ; - - map = list->map; - map->type = _DRM_GEM; - map->size = obj->size; - map->handle = obj; - -/* Get a DRM GEM mmap offset allocated... */ - list->file_offset_node =drm_mm_search_free (&mm->offset_manager, - obj->size /PAGE_SIZE ,0 , false); - -if (!list->file_offset_node) { -DRM_ERROR ("failed to allocate offset for bo %d\n" , obj->name); - ret = -ENOSPC ; - goto out_free_list; - } - list->file_offset_node =drm_mm_get_block (list->file_offset_node, - obj->size /PAGE_SIZE ,0 ); -if (!list->file_offset_node) { - ret = -ENOMEM ; - goto out_free_list; - } - - list->hash.key = list->file_offset_node->start; - ret =drm_ht_insert_item (&mm->offset_hash, &list->hash); -if (ret) { -DRM_ERROR ("failed to add to map hash\n" ); - goto out_free_mm; - } - -return 0 ; - -out_free_mm: -drm_mm_put_block (list->file_offset_node); -out_free_list: -kfree (list->map); - list->map =NULL ; - -return ret; +return drm_vma_offset_add (&mm->vma_manager, &obj->vma_node, + obj->size /PAGE_SIZE ); }EXPORT_SYMBOL (drm_gem_create_mmap_offset);@@ -707,8 +655,8 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)struct drm_file *priv = filp->private_data;struct drm_device *dev = priv->minor->dev;struct drm_gem_mm *mm = dev->mm_private; -struct drm_local_map *map =NULL ; -struct drm_hash_item *hash; +struct drm_gem_object *obj; +struct drm_vma_offset_node *node;int ret =0 ;if (drm_device_is_unplugged (dev))@@ -716,21 +664,15 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)mutex_lock (&dev->struct_mutex); -if (drm_ht_find_item (&mm->offset_hash, vma->vm_pgoff, &hash)) { + node =drm_vma_offset_exact_lookup (&mm->vma_manager, vma->vm_pgoff); +if (!node) {mutex_unlock (&dev->struct_mutex);return drm_mmap (filp, vma); } - map = drm_hash_entry(hash, struct drm_map_list, hash)->map; -if (!map || - ((map->flags & _DRM_RESTRICTED) && !capable (CAP_SYS_ADMIN ))) { - ret = -EPERM ; - goto out_unlock; - } - - ret =drm_gem_mmap_obj (map->handle, map->size, vma); + obj = container_of(node, struct drm_gem_object, vma_node); + ret =drm_gem_mmap_obj (obj, node->vm_pages, vma); -out_unlock:mutex_unlock (&dev->struct_mutex);return ret;drivers/gpu/drm/drm_gem_cma_helper.c +5
-4@@ -27,10 +27,11 @@#include <drm/drmP.h> #include <drm/drm.h> #include <drm/drm_gem_cma_helper.h> +#include <drm/drm_vma_manager.h> static unsigned int get_gem_mmap_offset (struct drm_gem_object *obj) { -return (unsigned int )obj->map_list.hash.key <<PAGE_SHIFT ; +return (unsigned int )drm_vma_node_offset_addr (&obj->vma_node); }/* @@ -172,7 +173,7 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj) {struct drm_gem_cma_object *cma_obj; -if (gem_obj->map_list.map) +if (drm_vma_node_has_offset (&gem_obj->vma_node))drm_gem_free_mmap_offset (gem_obj); cma_obj =to_drm_gem_cma_obj (gem_obj);@@ -305,8 +306,8 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *mWARN_ON (!mutex_is_locked (&dev->struct_mutex)); -if (obj->map_list.map) - off = (uint64_t )obj->map_list.hash.key; +if (drm_vma_node_has_offset (&obj->vma_node)) + off =drm_vma_node_start (&obj->vma_node); seq_printf(m, "%2d (%2d) %08llx %08Zx %p %d", obj->name, obj->refcount.refcount.counter,drivers/gpu/drm/exynos/exynos_drm_gem.c +4
-3@@ -10,6 +10,7 @@*/ #include <drm/drmP.h> +#include <drm/drm_vma_manager.h> #include <linux/shmem_fs.h> #include <drm/exynos_drm.h> @@ -152,7 +153,7 @@ out:exynos_drm_fini_buf (obj->dev, buf); exynos_gem_obj->buffer =NULL ; -if (obj->map_list.map) +if (drm_vma_node_has_offset (&obj->vma_node))drm_gem_free_mmap_offset (obj);/* release file pointer to gem object. */ @@ -702,13 +703,13 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv, goto unlock; } -if (!obj->map_list.map) { +if (!drm_vma_node_has_offset (&obj->vma_node)) { ret =drm_gem_create_mmap_offset (obj);if (ret) goto out; } - *offset = (u64 )obj->map_list.hash.key <<PAGE_SHIFT ; + *offset =drm_vma_node_offset_addr (&obj->vma_node);DRM_DEBUG_KMS ("offset = 0x%lx\n" , (unsigned long )*offset); out:drivers/gpu/drm/gma500/gem.c +4
-4@@ -26,6 +26,7 @@#include <drm/drmP.h> #include <drm/drm.h> #include <drm/gma_drm.h> +#include <drm/drm_vma_manager.h> #include "psb_drv.h" int psb_gem_init_object (struct drm_gem_object *obj)@@ -38,7 +39,7 @@ void psb_gem_free_object(struct drm_gem_object *obj) struct gtt_range *gtt = container_of(obj, struct gtt_range, gem);/* Remove the list map if one is present */ -if (obj->map_list.map) +if (drm_vma_node_has_offset (&obj->vma_node))drm_gem_free_mmap_offset (obj);drm_gem_object_release (obj);@@ -81,13 +82,12 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev,/* What validation is needed here ? */ /* Make it mmapable */ -if (!obj->map_list.map) { +if (!drm_vma_node_has_offset (&obj->vma_node)) { ret =drm_gem_create_mmap_offset (obj);if (ret) goto out; } -/* GEM should really work out the hash offsets for us */ - *offset = (u64 )obj->map_list.hash.key <<PAGE_SHIFT ; + *offset =drm_vma_node_offset_addr (&obj->vma_node); out:drm_gem_object_unreference (obj); unlock:drivers/gpu/drm/i915/i915_gem.c +5
-4@@ -26,6 +26,7 @@*/ #include <drm/drmP.h> +#include <drm/drm_vma_manager.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include "i915_trace.h" @@ -1427,7 +1428,7 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj)if (obj->base.dev->dev_mapping)unmap_mapping_range (obj->base.dev->dev_mapping, - (loff_t )obj->base.map_list.hash.key<<PAGE_SHIFT , + (loff_t )drm_vma_node_offset_addr (&obj->base.vma_node), obj->base.size,1 ); obj->fault_mappable = false;@@ -1485,7 +1486,7 @@ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)struct drm_i915_private *dev_priv = obj->base.dev->dev_private;int ret; -if (obj->base.map_list.map) +if (drm_vma_node_has_offset (&obj->base.vma_node))return 0 ; dev_priv->mm.shrinker_no_lock_stealing = true;@@ -1516,7 +1517,7 @@ out:static void i915_gem_object_free_mmap_offset (struct drm_i915_gem_object *obj) { -if (!obj->base.map_list.map) +if (!drm_vma_node_has_offset (&obj->base.vma_node))return ;drm_gem_free_mmap_offset (&obj->base);@@ -1557,7 +1558,7 @@ i915_gem_mmap_gtt(struct drm_file *file,if (ret) goto out; - *offset = (u64 )obj->base.map_list.hash.key <<PAGE_SHIFT ; + *offset =drm_vma_node_offset_addr (&obj->base.vma_node); out:drm_gem_object_unreference (&obj->base);drivers/gpu/drm/omapdrm/omap_gem.c +6
-5@@ -20,6 +20,7 @@#include <linux/spinlock.h> #include <linux/shmem_fs.h> +#include <drm/drm_vma_manager.h> #include "omap_drv.h" #include "omap_dmm_tiler.h" @@ -311,7 +312,7 @@ static uint64_t mmap_offset(struct drm_gem_object *obj)WARN_ON (!mutex_is_locked (&dev->struct_mutex)); -if (!obj->map_list.map) { +if (!drm_vma_node_has_offset (&obj->vma_node)) {/* Make it mmapable */ size_t size =omap_gem_mmap_size (obj);int ret =_drm_gem_create_mmap_offset_size (obj, size);@@ -322,7 +323,7 @@ static uint64_t mmap_offset(struct drm_gem_object *obj) } } -return (uint64_t )obj->map_list.hash.key <<PAGE_SHIFT ; +return drm_vma_node_offset_addr (&obj->vma_node); }uint64_t omap_gem_mmap_offset (struct drm_gem_object *obj)@@ -1001,8 +1002,8 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m)WARN_ON (!mutex_is_locked (&dev->struct_mutex)); -if (obj->map_list.map) - off = (uint64_t )obj->map_list.hash.key; +if (drm_vma_node_has_offset (&obj->vma_node)) + off =drm_vma_node_start (&obj->vma_node); seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d", omap_obj->flags, obj->name, obj->refcount.refcount.counter,@@ -1309,7 +1310,7 @@ void omap_gem_free_object(struct drm_gem_object *obj)list_del (&omap_obj->mm_list); -if (obj->map_list.map) +if (drm_vma_node_has_offset (&obj->vma_node))drm_gem_free_mmap_offset (obj);/* this means the object is still pinned.. which really should drivers/gpu/drm/omapdrm/omap_gem_helpers.c +2
-47@@ -118,52 +118,7 @@ _drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size) {struct drm_device *dev = obj->dev;struct drm_gem_mm *mm = dev->mm_private; -struct drm_map_list *list; -struct drm_local_map *map; -int ret =0 ; - -/* Set the object up for mmap'ing */ - list = &obj->map_list; - list->map =kzalloc (sizeof (struct drm_map_list ),GFP_KERNEL ); -if (!list->map) -return -ENOMEM ; - - map = list->map; - map->type = _DRM_GEM; - map->size = size; - map->handle = obj; - -/* Get a DRM GEM mmap offset allocated... */ - list->file_offset_node =drm_mm_search_free (&mm->offset_manager, - size /PAGE_SIZE ,0 ,0 ); - -if (!list->file_offset_node) { -DRM_ERROR ("failed to allocate offset for bo %d\n" , obj->name); - ret = -ENOSPC ; - goto out_free_list; - } - - list->file_offset_node =drm_mm_get_block (list->file_offset_node, - size /PAGE_SIZE ,0 ); -if (!list->file_offset_node) { - ret = -ENOMEM ; - goto out_free_list; - } - - list->hash.key = list->file_offset_node->start; - ret =drm_ht_insert_item (&mm->offset_hash, &list->hash); -if (ret) { -DRM_ERROR ("failed to add to map hash\n" ); - goto out_free_mm; - } - -return 0 ; - -out_free_mm: -drm_mm_put_block (list->file_offset_node); -out_free_list: -kfree (list->map); - list->map =NULL ; -return ret; +return drm_vma_offset_add (&mm->vma_manager, &obj->vma_node, + size /PAGE_SIZE ); }drivers/gpu/drm/udl/udl_gem.c +3
-3@@ -223,7 +223,7 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj)if (obj->pages)udl_gem_put_pages (obj); -if (gem_obj->map_list.map) +if (drm_vma_node_has_offset (&gem_obj->vma_node))drm_gem_free_mmap_offset (gem_obj); }@@ -247,13 +247,13 @@ int udl_gem_mmap(struct drm_file *file, struct drm_device *dev, ret =udl_gem_get_pages (gobj,GFP_KERNEL );if (ret) goto out; -if (!gobj->base.map_list.map) { +if (!drm_vma_node_has_offset (&gobj->base.vma_node)) { ret =drm_gem_create_mmap_offset (obj);if (ret) goto out; } - *offset = (u64 )gobj->base.map_list.hash.key <<PAGE_SHIFT ; + *offset =drm_vma_node_offset_addr (&gobj->base.vma_node); out:drm_gem_object_unreference (&gobj->base);include/drm/drmP.h +3
-4@@ -71,6 +71,7 @@#include <asm/pgalloc.h> #include <drm/drm.h> #include <drm/drm_sarea.h> +#include <drm/drm_vma_manager.h> #include <linux/idr.h> @@ -587,7 +588,6 @@ struct drm_map_list {struct drm_local_map *map;/**< mapping */ uint64_t user_token;struct drm_master *master; -struct drm_mm_node *file_offset_node;/**< fake offset */ };/** @@ -622,8 +622,7 @@ struct drm_ati_pcigart_info {* GEM specific mm private for tracking GEM objects */ struct drm_gem_mm { -struct drm_mm offset_manager;/**< Offset mgmt for buffer objects */ -struct drm_open_hash offset_hash;/**< User token hash table for maps */ +struct drm_vma_offset_manager vma_manager; };/** @@ -644,7 +643,7 @@ struct drm_gem_object {struct file *filp;/* Mapping info for this object */ -struct drm_map_list map_list; +struct drm_vma_offset_node vma_node;/** * Size of the object, in bytes. Immutable over the object's include/drm/drm_vma_manager.h +0
-1@@ -23,7 +23,6 @@* OTHER DEALINGS IN THE SOFTWARE. */ -#include <drm/drmP.h> #include <drm/drm_mm.h> #include <linux/module.h> #include <linux/rbtree.h> include/uapi/drm/drm.h +1
-2@@ -181,7 +181,7 @@ enum drm_map_type { _DRM_AGP =3 ,/**< AGP/GART */ _DRM_SCATTER_GATHER =4 ,/**< Scatter/gather memory for PCI DMA */ _DRM_CONSISTENT =5 ,/**< Consistent memory for PCI DMA */ - _DRM_GEM = 6, /**< GEM object */ + _DRM_GEM = 6, /**< GEM object (obsolete) */ };/** -- 1.8.3.2
PATCH v2 3/20 drm/ttm: convert to unified vma offset manager
In reply to David HerrmannUse the new vma-manager infrastructure. This doesn't change any implementation details as the vma-offset-manager is nearly copied 1-to-1 from TTM.
Even though the vma-manager uses its own locks, we still need bo->vm_lock to prevent bos from being destroyed before we can get a reference during lookup. However, this lock is not needed during vm-setup as we still hold a reference there.
This also drops the addr_space_offset member as it is a copy of vm_start in vma_node objects. Use the accessor functions instead.
--- drivers/gpu/drm/ast/ast_main.c | 2 +- drivers/gpu/drm/cirrus/cirrus_main.c | 2 +- drivers/gpu/drm/mgag200/mgag200_main.c | 2 +- drivers/gpu/drm/nouveau/nouveau_display.c | 2 +- drivers/gpu/drm/nouveau/nouveau_gem.c | 2 +- drivers/gpu/drm/qxl/qxl_object.h | 2 +- drivers/gpu/drm/qxl/qxl_release.c | 2 +- drivers/gpu/drm/radeon/radeon_object.h | 5 +- drivers/gpu/drm/ttm/ttm_bo.c | 84 ++++++------------------------- drivers/gpu/drm/ttm/ttm_bo_util.c | 3 +- drivers/gpu/drm/ttm/ttm_bo_vm.c | 81 ++++++++++++----------------- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 4 +- include/drm/ttm/ttm_bo_api.h | 15 ++---- include/drm/ttm/ttm_bo_driver.h | 7 +-- 14 files changed, 65 insertions(+), 148 deletions(-)
drivers/gpu/drm/ast/ast_main.c +1 -1
@@ -487,7 +487,7 @@ void ast_gem_free_object(struct drm_gem_object *obj)static inline u64 ast_bo_mmap_offset (struct ast_bo *bo) { -return bo->bo.addr_space_offset; +return drm_vma_node_offset_addr (&bo->bo.vma_node); } int ast_dumb_mmap_offset(struct drm_file *file,
drivers/gpu/drm/cirrus/cirrus_main.c +1 -1
@@ -294,7 +294,7 @@ void cirrus_gem_free_object(struct drm_gem_object *obj)static inline u64 cirrus_bo_mmap_offset (struct cirrus_bo *bo) { -return bo->bo.addr_space_offset; +return drm_vma_node_offset_addr (&bo->bo.vma_node); }int
drivers/gpu/drm/mgag200/mgag200_main.c +1 -1
@@ -349,7 +349,7 @@ void mgag200_gem_free_object(struct drm_gem_object *obj)static inline u64 mgag200_bo_mmap_offset (struct mgag200_bo *bo) { -return bo->bo.addr_space_offset; +return drm_vma_node_offset_addr (&bo->bo.vma_node); }int
drivers/gpu/drm/nouveau/nouveau_display.c +1 -1
@@ -697,7 +697,7 @@ nouveau_display_dumb_map_offset(struct drm_file *file_priv, gem =drm_gem_object_lookup (dev, file_priv, handle);if (gem) {struct nouveau_bo *bo = gem->driver_private; - *poffset = bo->bo.addr_space_offset; + *poffset =drm_vma_node_offset_addr (&bo->bo.vma_node);drm_gem_object_unreference_unlocked (gem);return 0 ; }
drivers/gpu/drm/nouveau/nouveau_gem.c +1 -1
@@ -226,7 +226,7 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem, } rep->size = nvbo->bo.mem.num_pages <<PAGE_SHIFT ; - rep->map_handle = nvbo->bo.addr_space_offset; + rep->map_handle =drm_vma_node_offset_addr (&nvbo->bo.vma_node); rep->tile_mode = nvbo->tile_mode; rep->tile_flags = nvbo->tile_flags;return 0 ;
drivers/gpu/drm/qxl/qxl_object.h +1 -1
@@ -59,7 +59,7 @@ static inline unsigned long qxl_bo_size(struct qxl_bo *bo)static inline u64 qxl_bo_mmap_offset (struct qxl_bo *bo) { -return bo->tbo.addr_space_offset; +return drm_vma_node_offset_addr (&bo->tbo.vma_node); } static inline int qxl_bo_wait(struct qxl_bo *bo, u32 *mem_type,
drivers/gpu/drm/qxl/qxl_release.c +1 -1
@@ -87,7 +87,7 @@ qxl_release_free(struct qxl_device *qdev,for (i =0 ; i < release->bo_count; ++i) {QXL_INFO (qdev,"release %llx\n" , - release->bos[i]->tbo.addr_space_offset +drm_vma_node_offset_addr (&release->bos[i]->tbo.vma_node) -DRM_FILE_OFFSET );qxl_fence_remove_release (&release->bos[i]->fence, release->id);qxl_bo_unref (&release->bos[i]);
drivers/gpu/drm/radeon/radeon_object.h +1 -4
@@ -113,13 +113,10 @@ static inline unsigned radeon_bo_gpu_page_alignment(struct radeon_bo *bo)* @bo: radeon object for which we query the offset * * Returns mmap offset of the object. -* -* Note: addr_space_offset is constant after ttm bo init thus isn't protected -* by any lock. */ static inline u64 radeon_bo_mmap_offset (struct radeon_bo *bo) { -return bo->tbo.addr_space_offset; +return drm_vma_node_offset_addr (&bo->tbo.vma_node); } extern int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type,
drivers/gpu/drm/ttm/ttm_bo.c +15 -69
131 lines not on this page · raw message
drivers/gpu/drm/ttm/ttm_bo_util.c +2 -1
@@ -30,6 +30,7 @@#include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_placement.h> +#include <drm/drm_vma_manager.h> #include <linux/io.h> #include <linux/highmem.h> #include <linux/wait.h>
@@ -450,7 +451,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,INIT_LIST_HEAD (&fbo->lru);INIT_LIST_HEAD (&fbo->swap);INIT_LIST_HEAD (&fbo->io_reserve_lru); - fbo->vm_node =NULL ; +drm_vma_node_reset (&fbo->vma_node);atomic_set (&fbo->cpu_writers,0 );spin_lock (&bdev->fence_lock);
drivers/gpu/drm/ttm/ttm_bo_vm.c +31 -50
125 lines not on this page · raw message
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +2 -2
@@ -500,7 +500,7 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, goto out_no_dmabuf; rep->handle = handle; - rep->map_handle = dma_buf->base.addr_space_offset; + rep->map_handle =drm_vma_node_offset_addr (&dma_buf->base.vma_node); rep->cur_gmr_id = handle; rep->cur_gmr_offset =0 ;
@@ -834,7 +834,7 @@ int vmw_dumb_map_offset(struct drm_file *file_priv,if (ret !=0 )return -EINVAL ; - *offset = out_buf->base.addr_space_offset; + *offset =drm_vma_node_offset_addr (&out_buf->base.vma_node);vmw_dmabuf_unreference (&out_buf);return 0 ; }
include/drm/ttm/ttm_bo_api.h +3 -12
@@ -32,12 +32,12 @@#define _TTM_BO_API_H_#include <drm/drm_hashtab.h> +#include <drm/drm_vma_manager.h> #include <linux/kref.h> #include <linux/list.h> #include <linux/wait.h> #include <linux/mutex.h> #include <linux/mm.h> -#include <linux/rbtree.h> #include <linux/bitmap.h> #include <linux/reservation.h>
@@ -145,7 +145,6 @@ struct ttm_tt;* @type: The bo type. * @destroy: Destruction function. If NULL, kfree is used. * @num_pages: Actual number of pages. -* @addr_space_offset: Address space offset. * @acc_size: Accounted size for this object. * @kref: Reference count of this buffer object. When this refcount reaches * zero, the object is put on the delayed delete list.
@@ -166,8 +165,7 @@ struct ttm_tt;* @swap: List head for swap LRU list. * @sync_obj: Pointer to a synchronization object. * @priv_flags: Flags describing buffer object internal state. -* @vm_rb: Rb node for the vm rb tree. -* @vm_node: Address space manager node. +* @vma_node: Address space manager node. * @offset: The current GPU offset, which can have different meanings * depending on the memory type. For SYSTEM type memory, it should be 0. * @cur_placement: Hint of current placement.
@@ -194,7 +192,6 @@ struct ttm_buffer_object {enum ttm_bo_type type;void (*destroy) (struct ttm_buffer_object *);unsigned long num_pages; -uint64_t addr_space_offset;size_t acc_size;/**
@@ -238,13 +235,7 @@ struct ttm_buffer_object {void *sync_obj;unsigned long priv_flags; -/** -* Members protected by the bdev::vm_lock -*/ - -struct rb_node vm_rb; -struct drm_mm_node *vm_node; - +struct drm_vma_offset_node vma_node;/** * Special members that are protected by the reserve lock
include/drm/ttm/ttm_bo_driver.h +4 -3
@@ -36,6 +36,7 @@#include <ttm/ttm_placement.h> #include <drm/drm_mm.h> #include <drm/drm_global.h> +#include <drm/drm_vma_manager.h> #include <linux/workqueue.h> #include <linux/fs.h> #include <linux/spinlock.h>
@@ -519,7 +520,7 @@ struct ttm_bo_global {* @man: An array of mem_type_managers. * @fence_lock: Protects the synchronizing members on *all* bos belonging * to this device. -* @addr_space_mm: Range manager for the device address space. +* @vma_manager: Address space manager * lru_lock: Spinlock that protects the buffer+device lru lists and * ddestroy lists. * @val_seq: Current validation sequence.
@@ -540,11 +541,11 @@ struct ttm_bo_device {rwlock_t vm_lock;struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES ];spinlock_t fence_lock; +/* * Protected by the vm lock. */ -struct rb_root addr_space_rb; -struct drm_mm addr_space_mm; +struct drm_vma_offset_manager vma_manager;/* * Protected by the global:lru lock.
Signature · 1 line
1.8.3.2
PATCH v2 4/20 drm/vma: provide drm_vma_node_unmap() helper
In reply to David HerrmannInstead of unmapping the nodes in TTM and GEM users manually, we provide a generic wrapper which does the correct thing for all vma-nodes.
v2: remove bdev->dev_mapping test in ttm_bo_unmap_virtual_unlocked() as ttm_mem_io_free_vm() does nothing in that case (io_reserved_vm is 0).
--- drivers/gpu/drm/i915/i915_gem.c | 6 +----- drivers/gpu/drm/ttm/ttm_bo.c | 11 +---------- include/drm/drm_vma_manager.h | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 15 deletions(-)
drivers/gpu/drm/i915/i915_gem.c +1 -5
@@ -1426,11 +1426,7 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj)if (!obj->fault_mappable)return ; -if (obj->base.dev->dev_mapping) -unmap_mapping_range (obj->base.dev->dev_mapping, - (loff_t )drm_vma_node_offset_addr (&obj->base.vma_node), - obj->base.size,1 ); - +drm_vma_node_unmap (&obj->base.vma_node, obj->base.dev->dev_mapping); obj->fault_mappable = false; }
drivers/gpu/drm/ttm/ttm_bo.c +1 -10
@@ -1493,17 +1493,8 @@ bool ttm_mem_reg_is_pci(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)void ttm_bo_unmap_virtual_locked (struct ttm_buffer_object *bo) {struct ttm_bo_device *bdev = bo->bdev; -loff_t offset, holelen; -if (!bdev->dev_mapping) -return ; - -if (drm_vma_node_has_offset (&bo->vma_node)) { - offset = (loff_t )drm_vma_node_offset_addr (&bo->vma_node); - holelen = ((loff_t ) bo->mem.num_pages) <<PAGE_SHIFT ; - -unmap_mapping_range (bdev->dev_mapping, offset, holelen,1 ); - } +drm_vma_node_unmap (&bo->vma_node, bdev->dev_mapping);ttm_mem_io_free_vm (bo); }
include/drm/drm_vma_manager.h +16 -0
@@ -24,6 +24,7 @@*/ #include <drm/drm_mm.h> +#include <linux/mm.h> #include <linux/module.h> #include <linux/rbtree.h> #include <linux/spinlock.h>
@@ -135,4 +136,19 @@ static inline __u64 drm_vma_node_offset_addr(struct drm_vma_offset_node *node) return ((__u64)node->vm_node.start) << PAGE_SHIFT; } +/** drm_vma_node_unmap() +* +* Unmap all userspace mappings for a given offset node. The mappings must be +* associated with the @file_mapping address-space. If no offset exists or +* the address-space is invalid, nothing is done. +*/ +static inline void drm_vma_node_unmap (struct drm_vma_offset_node *node, +struct address_space *file_mapping) +{ +if (file_mapping &&drm_vma_node_has_offset (node)) +unmap_mapping_range (file_mapping, +drm_vma_node_offset_addr (node), + node->vm_pages <<PAGE_SHIFT ,1 ); +} +#endif /* __DRM_VMA_MANAGER_H__ */
Signature · 1 line
1.8.3.2
RFC v2 5/20 drm/mm: add "best_match" to drm_mm_insert_node()
In reply to David HerrmannAdd a "best_match" argument similar to the drm_mm_search_*() helpers so we can convert TTM to use them in follow up patches.
Also move the non-generic aliases to drm_mm.h header instead of keeping them in the source file.
--- drivers/gpu/drm/drm_mm.c | 23 ++++------------------- drivers/gpu/drm/drm_vma_manager.c | 4 ++-- drivers/gpu/drm/i915/i915_gem.c | 3 ++- drivers/gpu/drm/sis/sis_mm.c | 4 ++-- drivers/gpu/drm/via/via_mm.c | 4 ++-- include/drm/drm_mm.h | 38 ++++++++++++++++++++++++++------------ 6 files changed, 38 insertions(+), 38 deletions(-)
drivers/gpu/drm/drm_mm.c +4 -19
@@ -217,12 +217,12 @@ EXPORT_SYMBOL(drm_mm_get_block_generic);*/ int drm_mm_insert_node_generic (struct drm_mm *mm,struct drm_mm_node *node,unsigned long size,unsigned alignment, -unsigned long color) +unsigned long color,bool best_match) {struct drm_mm_node *hole_node; hole_node =drm_mm_search_free_generic (mm, size, alignment, - color,0 ); + color, best_match);if (!hole_node)return -ENOSPC ;
@@ -231,13 +231,6 @@ int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node, }EXPORT_SYMBOL (drm_mm_insert_node_generic); -int drm_mm_insert_node (struct drm_mm *mm,struct drm_mm_node *node, -unsigned long size,unsigned alignment) -{ -return drm_mm_insert_node_generic (mm, node, size, alignment,0 ); -} -EXPORT_SYMBOL (drm_mm_insert_node); - static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, struct drm_mm_node *node, unsigned long size, unsigned alignment,
@@ -318,13 +311,13 @@ EXPORT_SYMBOL(drm_mm_get_block_range_generic);*/ int drm_mm_insert_node_in_range_generic (struct drm_mm *mm,struct drm_mm_node *node,unsigned long size,unsigned alignment,unsigned long color, -unsigned long start,unsigned long end) +unsigned long start,unsigned long end,bool best_match) {struct drm_mm_node *hole_node; hole_node =drm_mm_search_free_in_range_generic (mm, size, alignment, color, - start, end,0 ); + start, end, best_match);if (!hole_node)return -ENOSPC ;
@@ -335,14 +328,6 @@ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *n }EXPORT_SYMBOL (drm_mm_insert_node_in_range_generic); -int drm_mm_insert_node_in_range (struct drm_mm *mm,struct drm_mm_node *node, -unsigned long size,unsigned alignment, -unsigned long start,unsigned long end) -{ -return drm_mm_insert_node_in_range_generic (mm, node, size, alignment,0 , start, end); -} -EXPORT_SYMBOL (drm_mm_insert_node_in_range); -/** * Remove a memory node from the allocator. */
drivers/gpu/drm/drm_vma_manager.c +2 -2
@@ -218,8 +218,8 @@ int drm_vma_offset_add(struct drm_vma_offset_manager *mgr, goto out_unlock; } - ret =drm_mm_insert_node_generic (&mgr->vm_addr_space_mm, - &node->vm_node, pages,0 ,0 ); + ret =drm_mm_insert_node (&mgr->vm_addr_space_mm, &node->vm_node, + pages,0 , false);if (ret) goto out_unlock;
drivers/gpu/drm/i915/i915_gem.c +2 -1
@@ -3130,7 +3130,8 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, search_free: ret =drm_mm_insert_node_in_range_generic (&dev_priv->mm.gtt_space, node, size, alignment, - obj->cache_level,0 , gtt_max); + obj->cache_level,0 , gtt_max, + false);if (ret) { ret = i915_gem_evict_something(dev, size, alignment, obj->cache_level,
drivers/gpu/drm/sis/sis_mm.c +2 -2
@@ -109,7 +109,7 @@ static int sis_drm_alloc(struct drm_device *dev, struct drm_file *file,if (pool ==AGP_TYPE ) { retval =drm_mm_insert_node (&dev_priv->agp_mm, &item->mm_node, - mem->size,0 ); + mem->size,0 , false); offset = item->mm_node.start; }else {#if defined(CONFIG_FB_SIS ) || defined(CONFIG_FB_SIS_MODULE )
@@ -121,7 +121,7 @@ static int sis_drm_alloc(struct drm_device *dev, struct drm_file *file,#else retval =drm_mm_insert_node (&dev_priv->vram_mm, &item->mm_node, - mem->size,0 ); + mem->size,0 , false); offset = item->mm_node.start;#endif }
drivers/gpu/drm/via/via_mm.c +2 -2
@@ -140,11 +140,11 @@ int via_mem_alloc(struct drm_device *dev, void *data,if (mem->type ==VIA_MEM_AGP ) retval =drm_mm_insert_node (&dev_priv->agp_mm, &item->mm_node, - tmpSize,0 ); + tmpSize,0 , false);else retval =drm_mm_insert_node (&dev_priv->vram_mm, &item->mm_node, - tmpSize,0 ); + tmpSize,0 , false);if (retval) goto fail_alloc;
include/drm/drm_mm.h +26 -12
@@ -188,28 +188,42 @@ static inline struct drm_mm_node *drm_mm_get_block_atomic_range( start, end, 1); } -extern int drm_mm_insert_node (struct drm_mm *mm, -struct drm_mm_node *node, -unsigned long size, -unsigned alignment); -extern int drm_mm_insert_node_in_range (struct drm_mm *mm, -struct drm_mm_node *node, -unsigned long size, -unsigned alignment, -unsigned long start, -unsigned long end);extern int drm_mm_insert_node_generic (struct drm_mm *mm,struct drm_mm_node *node,unsigned long size,unsigned alignment, -unsigned long color); +unsigned long color, +bool best_match); +static inline int drm_mm_insert_node (struct drm_mm *mm, +struct drm_mm_node *node, +unsigned long size, +unsigned alignment, +bool best_match) +{ +return drm_mm_insert_node_generic (mm, node, size, alignment,0 , + best_match); +} +extern int drm_mm_insert_node_in_range_generic (struct drm_mm *mm,struct drm_mm_node *node,unsigned long size,unsigned alignment,unsigned long color,unsigned long start, -unsigned long end); +unsigned long end, +bool best_match); +static inline int drm_mm_insert_node_in_range (struct drm_mm *mm, +struct drm_mm_node *node, +unsigned long size, +unsigned alignment, +unsigned long start, +unsigned long end, +bool best_match) +{ +return drm_mm_insert_node_in_range_generic (mm, node, size, alignment, +0 , start, end, best_match); +} +extern void drm_mm_put_block (struct drm_mm_node *cur);extern void drm_mm_remove_node (struct drm_mm_node *node);extern void drm_mm_replace_node (struct drm_mm_node *old,struct drm_mm_node *new);
Signature · 1 line
1.8.3.2
RFC v2 6/20 drm/ttm: replace drm_mm_pre_get() by direct alloc
In reply to David HerrmannInstead of calling drm_mm_pre_get() in a row, we now preallocate the node and then use the atomic insertion functions. This has the exact same semantics and there is no reason to use the racy pre-allocations.
--- drivers/gpu/drm/ttm/ttm_bo_manager.c | 40 +++++++++++++++++------------------- 1 file changed, 19 insertions(+), 21 deletions(-)
drivers/gpu/drm/ttm/ttm_bo_manager.c +19 -21
@@ -61,28 +61,24 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, lpfn = placement->lpfn;if (!lpfn) lpfn = man->size; -do { - ret =drm_mm_pre_get (mm); -if (unlikely (ret)) -return ret; -spin_lock (&rman->lock); - node =drm_mm_search_free_in_range (mm, - mem->num_pages, mem->page_alignment, - placement->fpfn, lpfn,1 ); -if (unlikely (node ==NULL )) { -spin_unlock (&rman->lock); -return 0 ; - } - node =drm_mm_get_block_atomic_range (node, mem->num_pages, - mem->page_alignment, - placement->fpfn, - lpfn); -spin_unlock (&rman->lock); - }while (node ==NULL ); + node =kzalloc (sizeof (*node),GFP_KERNEL ); +if (!node) +return -ENOMEM ; + +spin_lock (&rman->lock); + ret =drm_mm_insert_node_in_range (mm, node, mem->num_pages, + mem->page_alignment, + placement->fpfn, lpfn, true); +spin_unlock (&rman->lock); + +if (unlikely (ret)) { +kfree (node); + }else { + mem->mm_node = node; + mem->start = node->start; + } - mem->mm_node = node; - mem->start = node->start;return 0 ; }
@@ -93,8 +89,10 @@ static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,if (mem->mm_node) {spin_lock (&rman->lock); -drm_mm_put_block (mem->mm_node); +drm_mm_remove_node (mem->mm_node);spin_unlock (&rman->lock); + +kfree (mem->mm_node); mem->mm_node =NULL ; } }
Signature · 1 line
1.8.3.2
RFC v2 7/20 drm/i915: pre-alloc instead of drm_mm search/get_block
In reply to David Herrmanni915 is the last user of the weird search+get_block drm_mm API. Convert it to an explicit kmalloc()+insert_node().
--- drivers/gpu/drm/i915/i915_gem.c | 9 +++-- drivers/gpu/drm/i915/i915_gem_stolen.c | 72 ++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 28 deletions(-)
drivers/gpu/drm/i915/i915_gem.c +6 -3
@@ -2628,7 +2628,8 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)/* Avoid an unnecessary call to unbind on rebind. */ obj->map_and_fenceable = true; -drm_mm_put_block (obj->gtt_space); +drm_mm_remove_node (obj->gtt_space); +kfree (obj->gtt_space); obj->gtt_space =NULL ; obj->gtt_offset =0 ;
@@ -3146,14 +3147,16 @@ search_free: }if (WARN_ON (!i915_gem_valid_gtt_space (dev, node, obj->cache_level))) {i915_gem_object_unpin_pages (obj); -drm_mm_put_block (node); +drm_mm_remove_node (node); +kfree (node);return -EINVAL ; } ret =i915_gem_gtt_prepare_object (obj);if (ret) {i915_gem_object_unpin_pages (obj); -drm_mm_put_block (node); +drm_mm_remove_node (node); +kfree (node);return ret; }
drivers/gpu/drm/i915/i915_gem_stolen.c +47 -25
133 lines not on this page · raw message
Signature · 1 line
1.8.3.2
RFC v2 8/20 drm/mm: remove unused API
In reply to David HerrmannThese calls are no longer used. Remove them.
--- drivers/gpu/drm/drm_mm.c | 116 ++++++++--------------------------------------- include/drm/drm_mm.h | 74 ------------------------------ 2 files changed, 19 insertions(+), 171 deletions(-)
drivers/gpu/drm/drm_mm.c +19 -97
@@ -49,6 +49,19 @@#define MM_UNUSED_TARGET 4 +static struct drm_mm_node *drm_mm_search_free_generic (const struct drm_mm *mm, +unsigned long size, +unsigned alignment, +unsigned long color, +bool best_match); +static struct drm_mm_node *drm_mm_search_free_in_range_generic (const struct drm_mm *mm, +unsigned long size, +unsigned alignment, +unsigned long color, +unsigned long start, +unsigned long end, +bool best_match); +static struct drm_mm_node *drm_mm_kmalloc (struct drm_mm *mm,int atomic) {struct drm_mm_node *child;
@@ -74,34 +87,6 @@ static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)return child; } -/* drm_mm_pre_get() - pre allocate drm_mm_node structure -* drm_mm: memory manager struct we are pre-allocating for -* -* Returns 0 on success or -ENOMEM if allocation fails. -*/ -int drm_mm_pre_get (struct drm_mm *mm) -{ -struct drm_mm_node *node; - -spin_lock (&mm->unused_lock); -while (mm->num_unused <MM_UNUSED_TARGET ) { -spin_unlock (&mm->unused_lock); - node =kzalloc (sizeof (*node),GFP_KERNEL ); -spin_lock (&mm->unused_lock); - -if (unlikely (node ==NULL )) { -int ret = (mm->num_unused <2 ) ? -ENOMEM :0 ; -spin_unlock (&mm->unused_lock); -return ret; - } - ++mm->num_unused; -list_add_tail (&node->node_list, &mm->unused_nodes); - } -spin_unlock (&mm->unused_lock); -return 0 ; -} -EXPORT_SYMBOL (drm_mm_pre_get); - static void drm_mm_insert_helper(struct drm_mm_node *hole_node, struct drm_mm_node *node, unsigned long size, unsigned alignment,
@@ -192,24 +177,6 @@ struct drm_mm_node *drm_mm_create_block(struct drm_mm *mm, }EXPORT_SYMBOL (drm_mm_create_block); -struct drm_mm_node *drm_mm_get_block_generic (struct drm_mm_node *hole_node, -unsigned long size, -unsigned alignment, -unsigned long color, -int atomic) -{ -struct drm_mm_node *node; - - node =drm_mm_kmalloc (hole_node->mm, atomic); -if (unlikely (node ==NULL )) -return NULL ; - -drm_mm_insert_helper (hole_node, node, size, alignment, color); - -return node; -} -EXPORT_SYMBOL (drm_mm_get_block_generic); -/** * Search for free space and insert a preallocated memory node. Returns * -ENOSPC if no suitable free area is available. The preallocated memory node
@@ -283,27 +250,6 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, } } -struct drm_mm_node *drm_mm_get_block_range_generic (struct drm_mm_node *hole_node, -unsigned long size, -unsigned alignment, -unsigned long color, -unsigned long start, -unsigned long end, -int atomic) -{ -struct drm_mm_node *node; - - node =drm_mm_kmalloc (hole_node->mm, atomic); -if (unlikely (node ==NULL )) -return NULL ; - -drm_mm_insert_helper_range (hole_node, node, size, alignment, color, - start, end); - -return node; -} -EXPORT_SYMBOL (drm_mm_get_block_range_generic); -/** * Search for free space and insert a preallocated memory node. Returns * -ENOSPC if no suitable free area is available. This is for range
@@ -362,28 +308,6 @@ void drm_mm_remove_node(struct drm_mm_node *node) }EXPORT_SYMBOL (drm_mm_remove_node); -/* -* Remove a memory node from the allocator and free the allocated struct -* drm_mm_node. Only to be used on a struct drm_mm_node obtained by one of the -* drm_mm_get_block functions. -*/ -void drm_mm_put_block (struct drm_mm_node *node) -{ - -struct drm_mm *mm = node->mm; - -drm_mm_remove_node (node); - -spin_lock (&mm->unused_lock); -if (mm->num_unused <MM_UNUSED_TARGET ) { -list_add (&node->node_list, &mm->unused_nodes); - ++mm->num_unused; - }else -kfree (node); -spin_unlock (&mm->unused_lock); -} -EXPORT_SYMBOL (drm_mm_put_block); -static int check_free_hole (unsigned long start,unsigned long end,unsigned long size,unsigned alignment) {
@@ -399,11 +323,11 @@ static int check_free_hole(unsigned long start, unsigned long end,return end >= start + size; } -struct drm_mm_node *drm_mm_search_free_generic (const struct drm_mm *mm, -unsigned long size, -unsigned alignment, -unsigned long color, -bool best_match) +static struct drm_mm_node *drm_mm_search_free_generic (const struct drm_mm *mm, +unsigned long size, +unsigned alignment, +unsigned long color, +bool best_match) {struct drm_mm_node *entry;struct drm_mm_node *best;
@@ -437,9 +361,8 @@ struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,return best; } -EXPORT_SYMBOL (drm_mm_search_free_generic); -struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm, +static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm, unsigned long size, unsigned alignment, unsigned long color,
@@ -484,7 +407,6 @@ struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm,return best; } -EXPORT_SYMBOL (drm_mm_search_free_in_range_generic);/** * Moves an allocation. To be used with embedded struct drm_mm_node.
include/drm/drm_mm.h +0 -74
93 lines not on this page · raw message
Signature · 1 line
1.8.3.2
PATCH v2 9/20 drm/vma: add access management helpers
In reply to David HerrmannThe VMA offset manager uses a device-global address-space, hence, any user can currently map any offset-node they want. They only need to guess the right offset. If we wanted per open-file offset spaces, we'd either need VM_NONLINEAR mappings or multiple "struct address_space" trees. As both doesn't really scale, we implement access management in the VMA manager itself.
We use an rb-tree to store open-files for each VMA node. On each mmap call, GEM, TTM or the drivers must check whether the current user is allowed to map this file.
We add a separate lock for each node as there is no generic lock available for the caller to protect the node easily.
--- drivers/gpu/drm/drm_vma_manager.c | 148 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_vma_manager.h | 16 +++++ 2 files changed, 164 insertions(+)
drivers/gpu/drm/drm_vma_manager.c +148 -0
@@ -25,6 +25,7 @@#include <drm/drmP.h> #include <drm/drm_mm.h> #include <drm/drm_vma_manager.h> +#include <linux/fs.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/rbtree.h>
@@ -58,6 +59,13 @@* must always be page-aligned (as usual). * If you want to get a valid byte-based user-space address for a given offset, * please see drm_vma_node_offset_addr(). +* +* Additionally to offset management, the vma offset manager also handles access +* management. For every open-file context that is allowed to access a given +* node, you must call drm_vma_node_allow(). Otherwise, an mmap() call on this +* open-file with the offset of the node will fail with -EACCES. To revoke +* access again, use drm_vma_node_revoke(). However, the caller is responsible +* for destroying already existing mappings, if required. */ /**
@@ -258,3 +266,143 @@ void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr,write_unlock (&mgr->vm_lock); }EXPORT_SYMBOL (drm_vma_offset_remove); + +/** +* drm_vma_node_allow - Add open-file to list of allowed users +* @node: Node to modify +* @filp: Open file to add +* +* Add @filp to the list of allowed open-files for this node. If @filp is +* already on this list, the ref-count is incremented. +* +* The list of allowed-users is preserved across drm_vma_offset_add() and +* drm_vma_offset_remove() calls. You may even call it if the node is currently +* not added to any offset-manager. +* +* You must remove all open-files the same number of times as you added them +* before destroying the node. Otherwise, you will leak memory. +* +* This is locked against concurrent access internally. +* +* RETURNS: +* 0 on success, negative error code on internal failure (out-of-mem) +*/ +int drm_vma_node_allow (struct drm_vma_offset_node *node,struct file *filp) +{ +struct rb_node **iter; +struct rb_node *parent =NULL ; +struct drm_vma_offset_file *entry; +int ret =0 ; + +write_lock (&node->vm_lock); + + iter = &node->vm_files.rb_node; + +while (likely (*iter)) { + parent = *iter; + entry = rb_entry(*iter, struct drm_vma_offset_file, vm_rb); + +if (filp == entry->vm_filp) { + entry->vm_count++; + goto unlock; + }else if (filp > entry->vm_filp) { + iter = &(*iter)->rb_right; + }else { + iter = &(*iter)->rb_left; + } + } + + entry =kmalloc (sizeof (*entry),GFP_KERNEL ); +if (!entry) { + ret = -ENOMEM ; + goto unlock; + } + + entry->vm_filp = filp; + entry->vm_count =1 ; +rb_link_node (&entry->vm_rb, parent, iter); +rb_insert_color (&entry->vm_rb, &node->vm_files); + +unlock: +write_unlock (&node->vm_lock); +return ret; +} +EXPORT_SYMBOL (drm_vma_node_allow); + +/** +* drm_vma_node_revoke - Remove open-file from list of allowed users +* @node: Node to modify +* @filp: Open file to remove +* +* Decrement the ref-count of @filp in the list of allowed open-files on @node. +* If the ref-count drops to zero, remove @filp from the list. You must call +* this once for every drm_vma_node_allow() on @filp. +* +* This is locked against concurrent access internally. +* +* If @filp is not on the list, nothing is done. +*/ +void drm_vma_node_revoke (struct drm_vma_offset_node *node,struct file *filp) +{ +struct drm_vma_offset_file *entry; +struct rb_node *iter; + +write_lock (&node->vm_lock); + + iter = node->vm_files.rb_node; +while (likely (iter)) { + entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb); +if (filp == entry->vm_filp) { +if (!--entry->vm_count) { +rb_erase (&entry->vm_rb, &node->vm_files); +kfree (entry); + } +break ; + }else if (filp > entry->vm_filp) { + iter = iter->rb_right; + }else { + iter = iter->rb_left; + } + } + +write_unlock (&node->vm_lock); +} +EXPORT_SYMBOL (drm_vma_node_revoke); + +/** +* drm_vma_node_is_allowed - Check whether an open-file is granted access +* @node: Node to check +* @filp: Open-file to check for +* +* Search the list in @node whether @filp is currently on the list of allowed +* open-files (see drm_vma_node_allow()). +* +* This is locked against concurrent access internally. +* +* RETURNS: +* true iff @filp is on the list +*/ +bool drm_vma_node_is_allowed (struct drm_vma_offset_node *node, +struct file *filp) +{ +struct drm_vma_offset_file *entry; +struct rb_node *iter; + +read_lock (&node->vm_lock); + + iter = node->vm_files.rb_node; +while (likely (iter)) { + entry = rb_entry(iter, struct drm_vma_offset_file, vm_rb); +if (filp == entry->vm_filp) +break ; +else if (filp > entry->vm_filp) + iter = iter->rb_right; +else + iter = iter->rb_left; + } + +read_unlock (&node->vm_lock); + +return iter; +} +EXPORT_SYMBOL (drm_vma_node_is_allowed);
include/drm/drm_vma_manager.h +16 -0
@@ -24,16 +24,25 @@*/ #include <drm/drm_mm.h> +#include <linux/fs.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/rbtree.h> #include <linux/spinlock.h> #include <linux/types.h> +struct drm_vma_offset_file { +struct rb_node vm_rb; +struct file *vm_filp; +unsigned long vm_count; +}; +struct drm_vma_offset_node { +rwlock_t vm_lock;struct drm_mm_node vm_node;struct rb_node vm_rb;unsigned long vm_pages; +struct rb_root vm_files; };struct drm_vma_offset_manager {
@@ -54,6 +63,11 @@ int drm_vma_offset_add(struct drm_vma_offset_manager *mgr,void drm_vma_offset_remove (struct drm_vma_offset_manager *mgr,struct drm_vma_offset_node *node); +int drm_vma_node_allow (struct drm_vma_offset_node *node,struct file *filp); +void drm_vma_node_revoke (struct drm_vma_offset_node *node,struct file *filp); +bool drm_vma_node_is_allowed (struct drm_vma_offset_node *node, +struct file *filp); +/** * drm_vma_offset_exact_lookup() - Look up node by exact address * @mgr: Manager object
@@ -85,6 +99,8 @@ drm_vma_offset_exact_lookup(struct drm_vma_offset_manager *mgr,static inline void drm_vma_node_reset (struct drm_vma_offset_node *node) {memset (node,0 ,sizeof (*node)); + node->vm_files =RB_ROOT ; +rwlock_init (&node->vm_lock); }/**
Signature · 1 line
1.8.3.2
PATCH v2 10/20 drm/ast: implement mmap access managament
In reply to David HerrmannCorrectly allow and revoke buffer access on each open/close via the new VMA offset manager.
--- drivers/gpu/drm/ast/ast_drv.c | 2 ++ drivers/gpu/drm/ast/ast_drv.h | 4 ++++ drivers/gpu/drm/ast/ast_main.c | 15 +++++++++++++++ 3 files changed, 21 insertions(+)
drivers/gpu/drm/ast/ast_drv.c +2 -0
@@ -214,6 +214,8 @@ static struct drm_driver driver = { .gem_init_object = ast_gem_init_object, .gem_free_object = ast_gem_free_object, + .gem_open_object = ast_gem_open_object, + .gem_close_object = ast_gem_close_object, .dumb_create = ast_dumb_create, .dumb_map_offset = ast_dumb_mmap_offset, .dumb_destroy = ast_dumb_destroy,
drivers/gpu/drm/ast/ast_drv.h +4 -0
@@ -328,6 +328,10 @@ extern int ast_dumb_destroy(struct drm_file *file,extern int ast_gem_init_object (struct drm_gem_object *obj);extern void ast_gem_free_object (struct drm_gem_object *obj); +extern int ast_gem_open_object (struct drm_gem_object *obj, +struct drm_file *file_priv); +extern void ast_gem_close_object (struct drm_gem_object *obj, +struct drm_file *file_priv); extern int ast_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, uint32_t handle,
drivers/gpu/drm/ast/ast_main.c +15 -0
@@ -484,6 +484,21 @@ void ast_gem_free_object(struct drm_gem_object *obj)ast_bo_unref (&ast_bo); } +int ast_gem_open_object (struct drm_gem_object *obj, +struct drm_file *file_priv) +{ +struct ast_bo *ast_bo =gem_to_ast_bo (obj); + +return drm_vma_node_allow (&ast_bo->bo.vma_node, file_priv->filp); +} + +void ast_gem_close_object (struct drm_gem_object *obj, +struct drm_file *file_priv) +{ +struct ast_bo *ast_bo =gem_to_ast_bo (obj); + +drm_vma_node_revoke (&ast_bo->bo.vma_node, file_priv->filp); +}static inline u64 ast_bo_mmap_offset (struct ast_bo *bo) {
Signature · 1 line
1.8.3.2
PATCH v2 11/20 drm/cirrus: implement mmap access managament
In reply to David HerrmannCorrectly allow and revoke buffer access on each open/close via the new VMA offset manager.
--- drivers/gpu/drm/cirrus/cirrus_drv.h | 4 ++++ drivers/gpu/drm/cirrus/cirrus_main.c | 15 +++++++++++++++ 2 files changed, 19 insertions(+)
drivers/gpu/drm/cirrus/cirrus_drv.h +4 -0
@@ -193,6 +193,10 @@ int cirrus_device_init(struct cirrus_device *cdev,void cirrus_device_fini (struct cirrus_device *cdev);int cirrus_gem_init_object (struct drm_gem_object *obj);void cirrus_gem_free_object (struct drm_gem_object *obj); +int cirrus_gem_open_object (struct drm_gem_object *obj, +struct drm_file *file_priv); +void cirrus_gem_close_object (struct drm_gem_object *obj, +struct drm_file *file_priv); int cirrus_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, uint32_t handle,
drivers/gpu/drm/cirrus/cirrus_main.c +15 -0
@@ -291,6 +291,21 @@ void cirrus_gem_free_object(struct drm_gem_object *obj)cirrus_bo_unref (&cirrus_bo); } +int cirrus_gem_open_object (struct drm_gem_object *obj, +struct drm_file *file_priv) +{ +struct cirrus_bo *bo =gem_to_cirrus_bo (obj); + +return drm_vma_node_allow (&bo->bo.vma_node, file_priv->filp); +} + +void cirrus_gem_close_object (struct drm_gem_object *obj, +struct drm_file *file_priv) +{ +struct cirrus_bo *bo =gem_to_cirrus_bo (obj); + +drm_vma_node_revoke (&bo->bo.vma_node, file_priv->filp); +}static inline u64 cirrus_bo_mmap_offset (struct cirrus_bo *bo) {
Signature · 1 line
1.8.3.2
PATCH v2 12/20 drm/mgag200: implement mmap access managament
In reply to David HerrmannCorrectly allow and revoke buffer access on each open/close via the new VMA offset manager.
--- drivers/gpu/drm/mgag200/mgag200_drv.c | 2 ++ drivers/gpu/drm/mgag200/mgag200_drv.h | 4 ++++ drivers/gpu/drm/mgag200/mgag200_main.c | 15 +++++++++++++++ 3 files changed, 21 insertions(+)
drivers/gpu/drm/mgag200/mgag200_drv.c +2 -0
@@ -102,6 +102,8 @@ static struct drm_driver driver = { .gem_init_object = mgag200_gem_init_object, .gem_free_object = mgag200_gem_free_object, + .gem_open_object = mgag200_gem_open_object, + .gem_close_object = mgag200_gem_close_object, .dumb_create = mgag200_dumb_create, .dumb_map_offset = mgag200_dumb_mmap_offset, .dumb_destroy = mgag200_dumb_destroy,
drivers/gpu/drm/mgag200/mgag200_drv.h +4 -0
@@ -268,6 +268,10 @@ int mgag200_dumb_destroy(struct drm_file *file,struct drm_device *dev, uint32_t handle);void mgag200_gem_free_object (struct drm_gem_object *obj); +int mgag200_gem_open_object (struct drm_gem_object *obj, +struct drm_file *file_priv); +void mgag200_gem_close_object (struct drm_gem_object *obj, +struct drm_file *file_priv); int mgag200_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
drivers/gpu/drm/mgag200/mgag200_main.c +15 -0
@@ -346,6 +346,21 @@ void mgag200_gem_free_object(struct drm_gem_object *obj)mgag200_bo_unref (&mgag200_bo); } +int mgag200_gem_open_object (struct drm_gem_object *obj, +struct drm_file *file_priv) +{ +struct mgag200_bo *bo =gem_to_mga_bo (obj); + +return drm_vma_node_allow (&bo->bo.vma_node, file_priv->filp); +} + +void mgag200_gem_close_object (struct drm_gem_object *obj, +struct drm_file *file_priv) +{ +struct mgag200_bo *bo =gem_to_mga_bo (obj); + +drm_vma_node_revoke (&bo->bo.vma_node, file_priv->filp); +}static inline u64 mgag200_bo_mmap_offset (struct mgag200_bo *bo) {
Signature · 1 line
1.8.3.2
PATCH v2 13/20 drm/nouveau: implement mmap access managament
In reply to David HerrmannCorrectly allow and revoke buffer access on each open/close via the new VMA offset manager.
--- drivers/gpu/drm/nouveau/nouveau_gem.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)
drivers/gpu/drm/nouveau/nouveau_gem.c +15 -4
@@ -73,32 +73,41 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)struct nouveau_vma *vma;int ret; + ret =drm_vma_node_allow (&nvbo->bo.vma_node, file_priv->filp); +if (ret) +return ret; +if (!cli->base.vm)return 0 ; ret =ttm_bo_reserve (&nvbo->bo, false, false, false,0 );if (ret) -return ret; + goto err_node; vma =nouveau_bo_vma_find (nvbo, cli->base.vm);if (!vma) { vma =kzalloc (sizeof (*vma),GFP_KERNEL );if (!vma) { ret = -ENOMEM ; - goto out; + goto err_reserve; } ret =nouveau_bo_vma_add (nvbo, cli->base.vm, vma);if (ret) {kfree (vma); - goto out; + goto err_reserve; } }else { vma->refcount++; } -out:ttm_bo_unreserve (&nvbo->bo); +return 0 ; + +err_reserve: +ttm_bo_unreserve (&nvbo->bo); +err_node: +drm_vma_node_revoke (&nvbo->bo.vma_node, file_priv->filp);return ret; }
@@ -145,6 +154,8 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)struct nouveau_vma *vma;int ret; +drm_vma_node_revoke (&nvbo->bo.vma_node, file_priv->filp); +if (!cli->base.vm)return ;
Signature · 1 line
1.8.3.2
PATCH v2 14/20 drm/radeon: implement mmap access managament
In reply to David HerrmannCorrectly allow and revoke buffer access on each open/close via the new VMA offset manager.
--- drivers/gpu/drm/radeon/radeon_gem.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/gpu/drm/radeon/radeon_gem.c +7 -0
@@ -147,12 +147,17 @@ int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_pristruct radeon_bo_va *bo_va;int r; + r =drm_vma_node_allow (&rbo->tbo.vma_node, file_priv->filp); +if (r) +return r; +if (rdev->family <CHIP_CAYMAN ) {return 0 ; } r =radeon_bo_reserve (rbo, false);if (r) { +drm_vma_node_revoke (&rbo->tbo.vma_node, file_priv->filp);return r; }
@@ -177,6 +182,8 @@ void radeon_gem_object_close(struct drm_gem_object *obj,struct radeon_bo_va *bo_va;int r; +drm_vma_node_revoke (&rbo->tbo.vma_node, file_priv->filp); +if (rdev->family <CHIP_CAYMAN ) {return ; }
Signature · 1 line
1.8.3.2
PATCH v2 15/20 drm/qxl: implement mmap access managament
In reply to David HerrmannCorrectly allow and revoke buffer access on each open/close via the new VMA offset manager.
--- drivers/gpu/drm/qxl/qxl_gem.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/gpu/drm/qxl/qxl_gem.c +6 -1
@@ -129,12 +129,17 @@ void qxl_gem_object_unpin(struct drm_gem_object *obj)int qxl_gem_object_open (struct drm_gem_object *obj,struct drm_file *file_priv) { -return 0 ; +struct qxl_bo *qobj = obj->driver_private; + +return drm_vma_node_allow (&qobj->tbo.vma_node, file_priv->filp); }void qxl_gem_object_close (struct drm_gem_object *obj,struct drm_file *file_priv) { +struct qxl_bo *qobj = obj->driver_private; + +drm_vma_node_revoke (&qobj->tbo.vma_node, file_priv->filp); }int qxl_gem_init (struct qxl_device *qdev)
Signature · 1 line
1.8.3.2
PATCH v2 16/20 drm/vmwgfx: implement mmap access managament
In reply to David HerrmannCorrectly allow and revoke buffer access on each open/close via the new VMA offset manager.
Also remove unused vmw_user_dmabuf_reference() to prevent from using it later without correctly adding mmap permissions.
--- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-)
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +17 -12
@@ -499,6 +499,12 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,if (unlikely (ret !=0 )) goto out_no_dmabuf; + ret =drm_vma_node_allow (&dma_buf->base.vma_node, file_priv->filp); +if (ret) { +vmw_dmabuf_unreference (&dma_buf); + goto out_no_dmabuf; + } + rep->handle = handle; rep->map_handle =drm_vma_node_offset_addr (&dma_buf->base.vma_node); rep->cur_gmr_id = handle;
@@ -517,7 +523,18 @@ int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data, {struct drm_vmw_unref_dmabuf_arg *arg = (struct drm_vmw_unref_dmabuf_arg *)data; +struct ttm_object_file *tfile =vmw_fpriv (file_priv)->tfile; +struct vmw_dma_buffer *dma_buf; +int ret; + + ret =vmw_user_dmabuf_lookup (tfile, arg->handle, &dma_buf); +if (ret) +return -EINVAL ; +drm_vma_node_revoke (&dma_buf->base.vma_node, file_priv->filp); +vmw_dmabuf_unreference (&dma_buf); + +/* FIXME: is this equivalent to vmw_dmabuf_unreference(dma_buf)? */ return ttm_ref_object_base_unref (vmw_fpriv (file_priv)->tfile, arg->handle,TTM_REF_USAGE );
@@ -551,18 +568,6 @@ int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,return 0 ; } -int vmw_user_dmabuf_reference (struct ttm_object_file *tfile, -struct vmw_dma_buffer *dma_buf) -{ -struct vmw_user_dma_buffer *user_bo; - -if (dma_buf->base.destroy != vmw_user_dmabuf_destroy) -return -EINVAL ; - - user_bo = container_of(dma_buf, struct vmw_user_dma_buffer, dma); -return ttm_ref_object_add (tfile, &user_bo->base,TTM_REF_USAGE ,NULL ); -} -/* * Stream management */
Signature · 1 line
1.8.3.2
PATCH v2 17/20 drm/ttm: prevent mmap access to unauthorized users
In reply to David HerrmannIf a user does not have access to a given buffer, we must not allow them to mmap it. Otherwise, users could "guess" the buffer offsets of other users and get access to the buffer.
All TTM drivers already use the new VMA offset manager access management so we can enable TTM mmap access management now.
--- drivers/gpu/drm/ttm/ttm_bo_vm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/gpu/drm/ttm/ttm_bo_vm.c +5 -4
@@ -219,7 +219,8 @@ static const struct vm_operations_struct ttm_bo_vm_ops = { .close = ttm_bo_vm_close }; -static struct ttm_buffer_object *ttm_bo_vm_lookup (struct ttm_bo_device *bdev, +static struct ttm_buffer_object *ttm_bo_vm_lookup (struct file *filp, +struct ttm_bo_device *bdev,unsigned long offset,unsigned long pages) {
@@ -229,7 +230,7 @@ static struct ttm_buffer_object *ttm_bo_vm_lookup(struct ttm_bo_device *bdev,read_lock (&bdev->vm_lock); node =drm_vma_offset_lookup (&bdev->vma_manager, offset, pages); -if (likely (node)) { +if (likely (node) &&drm_vma_node_is_allowed (node, filp)) { bo = container_of(node, struct ttm_buffer_object, vma_node);if (!kref_get_unless_zero (&bo->kref)) bo =NULL ;
@@ -250,7 +251,7 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,struct ttm_buffer_object *bo;int ret; - bo =ttm_bo_vm_lookup (bdev, vma->vm_pgoff,vma_pages (vma)); + bo =ttm_bo_vm_lookup (filp, bdev, vma->vm_pgoff,vma_pages (vma));if (unlikely (!bo))return -EINVAL ;
@@ -310,7 +311,7 @@ ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp,bool no_wait = false;bool dummy; - bo =ttm_bo_vm_lookup (bdev, dev_offset,1 ); + bo =ttm_bo_vm_lookup (filp, bdev, dev_offset,1 );if (unlikely (bo ==NULL ))return -EFAULT ;
Signature · 1 line
1.8.3.2
PATCH v2 18/20 drm/gem: implement mmap access management
In reply to David HerrmannImplement automatic access management for mmap offsets for all GEM drivers. This prevents user-space applications from "guessing" GEM BO offsets and accessing buffers which they don't own.
--- drivers/gpu/drm/drm_gem.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
drivers/gpu/drm/drm_gem.c +17 -4
@@ -240,6 +240,7 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)spin_unlock (&filp->table_lock);drm_gem_remove_prime_handles (obj, filp); +drm_vma_node_revoke (&obj->vma_node, filp->filp);if (dev->driver->gem_close_object) dev->driver->gem_close_object (obj, filp);
@@ -279,15 +280,23 @@ drm_gem_handle_create(struct drm_file *file_priv,drm_gem_object_handle_reference (obj); + ret =drm_vma_node_allow (&obj->vma_node, file_priv->filp); +if (ret) + goto err_handle; +if (dev->driver->gem_open_object) { ret = dev->driver->gem_open_object (obj, file_priv); -if (ret) { -drm_gem_handle_delete (file_priv, *handlep); -return ret; - } +if (ret) + goto err_vma; }return 0 ; + +err_vma: +drm_vma_node_revoke (&obj->vma_node, file_priv->filp); +err_handle: +drm_gem_handle_delete (file_priv, *handlep); +return ret; }EXPORT_SYMBOL (drm_gem_handle_create);
@@ -476,6 +485,7 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)struct drm_device *dev = obj->dev;drm_gem_remove_prime_handles (obj, file_priv); +drm_vma_node_revoke (&obj->vma_node, file_priv->filp);if (dev->driver->gem_close_object) dev->driver->gem_close_object (obj, file_priv);
@@ -668,6 +678,9 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)if (!node) {mutex_unlock (&dev->struct_mutex);return drm_mmap (filp, vma); + }else if (!drm_vma_node_is_allowed (node, filp)) { +mutex_unlock (&dev->struct_mutex); +return -EACCES ; } obj = container_of(node, struct drm_gem_object, vma_node);
Signature · 1 line
1.8.3.2
PATCH v2 19/20 drm: fix minor number range calculation
In reply to David HerrmannCurrently, both ranges overlap. Fix the limits so both ranges are mutually exclusive. Also use the occasion to convert whitespaces to tabs.
--- drivers/gpu/drm/drm_stub.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/gpu/drm/drm_stub.c +6 -6
@@ -113,12 +113,12 @@ static int drm_minor_get_id(struct drm_device *dev, int type)int base =0 , limit =63 ;if (type ==DRM_MINOR_CONTROL ) { - base +=64 ; - limit = base +127 ; - }else if (type ==DRM_MINOR_RENDER ) { - base +=128 ; - limit = base +255 ; - } + base +=64 ; + limit = base +63 ; + }else if (type ==DRM_MINOR_RENDER ) { + base +=128 ; + limit = base +63 ; + }mutex_lock (&dev->struct_mutex); ret =idr_alloc (&drm_minors_idr,NULL , base, limit,GFP_KERNEL );
Signature · 6 lines
1.8.3.2 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH v2 20/20 drm: implement render nodes
In reply to David HerrmannRender nodes provide an API for userspace to use non-privileged GPU commands without any running DRM-Master. It is useful for offscreen rendering, GPGPU clients, and normal render clients which do not perform modesetting.
Compared to legacy clients, render clients no longer need any authentication to perform client ioctls. Instead, user-space controls render/client access to GPUs via filesystem access-modes on the render-node. Once a render-node was opened, a client has full access to the client/render operations on the GPU. However, no modesetting or ioctls that affect global state are allowed on render nodes.
To prevent privilege-escalation, drivers must explicitly state that they support render nodes. They must mark their render-only ioctls as DRM_RENDER_ALLOW so render clients can use them. Furthermore, they must support clients without any attached master.
If filesystem access-modes are not enough for fine-grained access control to render nodes (very unlikely, considering the versaitlity of FS-ACLs), you may still fall-back to fd-passing from server to client (which allows arbitrary access-control). However, note that revoking access is currently impossible and unlikely to get implemented.
Note: Render clients no longer have any associated DRM-Master as they are supposed to be independent of any server state. DRM core highly depends on file_priv->master to be non-NULL for modesetting/ctx/etc. commands. Therefore, drivers must be very careful to not require DRM-Master if they support DRIVER_RENDER.
--- Documentation/DocBook/drm.tmpl | 71 ++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_drv.c | 15 ++++----- drivers/gpu/drm/drm_fops.c | 14 ++++----- drivers/gpu/drm/drm_pci.c | 9 ++++++ drivers/gpu/drm/drm_platform.c | 9 ++++++ drivers/gpu/drm/drm_stub.c | 5 +++ drivers/gpu/drm/drm_usb.c | 9 ++++++ include/drm/drmP.h | 8 +++++ 8 files changed, 126 insertions(+), 14 deletions(-)
Documentation/DocBook/drm.tmpl +71 -0
@@ -234,6 +234,12 @@ Driver implements DRM PRIME buffer sharing. </para></listitem> </varlistentry> + <varlistentry> + <term>DRIVER_RENDER</term> + <listitem><para> + Driver supports dedicated render nodes. + </para></listitem> + </varlistentry> </variablelist> </sect3> <sect3>
@@ -2663,6 +2669,71 @@ int (*resume) (struct drm_device *);</synopsis> info, since man pages should cover the rest. </para> + <!-- External: render nodes --> + + <sect1> + <title>Render nodes</title> + <para> + DRM core provides multiple character-devices for user-space to use. + Depending on which device is opened, user-space can perform a different + set of operations (mainly ioctls). The primary node is always created + and called <term>card<num></term>. Additionally, a currently + unused control node, called <term>controlD<num></term> is also + created. The primary node provides all legacy operations and + historically was the only interface used by userspace. With KMS, the + control node was introduced. However, the planned KMS control interface + has never been written and so the control node stays unused to date. + </para> + <para> + With the increased use of offscreen renderers and GPGPU applications, + clients no longer require running compositors or graphics servers to + make use of a GPU. But the DRM API required unprivileged clients to + authenticate to a DRM-Master prior to getting GPU access. To avoid this + step and to grant clients GPU access without authenticating, render + nodes were introduced. Render nodes solely serve render clients, that + is, no modesetting or privileged ioctls can be issued on render nodes. + Only non-global rendering commands are allowed. If a driver supports + render nodes, it must advertise it via the <term>DRIVER_RENDER</term> + DRM driver capability. If not supported, the primary node must be used + for render clients together with the legacy drmAuth authentication + procedure. + </para> + <para> + If a driver advertises render node support, DRM core will create a + separate render node called <term>renderD<num></term>. There will + be one render node per device. No ioctls except for + <term>GEM_CLOSE</term>, <term>GEM_FLINK</term> and PRIME-related ioctls + will be allowed on this node. Especially <term>GEM_OPEN</term> will be + explicitly prohibited. Render nodes are designed to avoid the + buffer-leaks, which occur if clients guess the flink names or mmap + offsets on the legacy interface. Additionally to this basic interface, + drivers must mark their driver-dependent render-only ioctls as + <term>DRM_RENDER_ALLOW</term> so render clients can use them. Driver + authors must be careful not to allow any privileged ioctls on render + nodes. + </para> + <para> + With render nodes, user-space can now control access to the render node + via basic file-system access-modes. A running graphics server which + authenticates clients on the privileged primary/legacy node is no longer + required. Instead, a client can open the render node and is immediately + granted GPU access. Communication between clients (or servers) is done + via PRIME. FLINK from render node to legacy node is also supported, + however, FLINK from legacy node to render node is prohibited. New + clients must not use the insecure FLINK interface. + </para> + <para> + Besides dropping all modeset/global ioctls, render nodes also drop the + DRM-Master concept. There is no reason to associate render clients with + a DRM-Master as they are independent of any graphics server. Besides, + they must work without any running master, anyway. + Drivers must be able to run without a master object if they support + render nodes. If, on the other hand, a driver requires shared state + between clients which is visible to user-space and accessible beyond + open-file boundaries, they cannot support render nodes. + </para> + </sect1> + <!-- External: vblank handling --> <sect1>
drivers/gpu/drm/drm_drv.c +8 -7
@@ -68,7 +68,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {DRM_IOCTL_DEF (DRM_IOCTL_GET_MAP , drm_getmap,DRM_UNLOCKED ),DRM_IOCTL_DEF (DRM_IOCTL_GET_CLIENT , drm_getclient,DRM_UNLOCKED ),DRM_IOCTL_DEF (DRM_IOCTL_GET_STATS , drm_getstats,DRM_UNLOCKED ), -DRM_IOCTL_DEF (DRM_IOCTL_GET_CAP , drm_getcap,DRM_UNLOCKED ), +DRM_IOCTL_DEF (DRM_IOCTL_GET_CAP , drm_getcap,DRM_UNLOCKED |DRM_RENDER_ALLOW ),DRM_IOCTL_DEF (DRM_IOCTL_SET_VERSION , drm_setversion,DRM_MASTER ), DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
@@ -131,14 +131,14 @@ static const struct drm_ioctl_desc drm_ioctls[] = {DRM_IOCTL_DEF (DRM_IOCTL_UPDATE_DRAW , drm_noop,DRM_AUTH |DRM_MASTER |DRM_ROOT_ONLY ), -DRM_IOCTL_DEF (DRM_IOCTL_GEM_CLOSE , drm_gem_close_ioctl,DRM_UNLOCKED ), -DRM_IOCTL_DEF (DRM_IOCTL_GEM_FLINK , drm_gem_flink_ioctl,DRM_AUTH |DRM_UNLOCKED ), +DRM_IOCTL_DEF (DRM_IOCTL_GEM_CLOSE , drm_gem_close_ioctl,DRM_UNLOCKED |DRM_RENDER_ALLOW ), +DRM_IOCTL_DEF (DRM_IOCTL_GEM_FLINK , drm_gem_flink_ioctl,DRM_AUTH |DRM_UNLOCKED |DRM_RENDER_ALLOW ),DRM_IOCTL_DEF (DRM_IOCTL_GEM_OPEN , drm_gem_open_ioctl,DRM_AUTH |DRM_UNLOCKED ),DRM_IOCTL_DEF (DRM_IOCTL_MODE_GETRESOURCES , drm_mode_getresources,DRM_CONTROL_ALLOW |DRM_UNLOCKED ), -DRM_IOCTL_DEF (DRM_IOCTL_PRIME_HANDLE_TO_FD , drm_prime_handle_to_fd_ioctl,DRM_AUTH |DRM_UNLOCKED ), -DRM_IOCTL_DEF (DRM_IOCTL_PRIME_FD_TO_HANDLE , drm_prime_fd_to_handle_ioctl,DRM_AUTH |DRM_UNLOCKED ), +DRM_IOCTL_DEF (DRM_IOCTL_PRIME_HANDLE_TO_FD , drm_prime_handle_to_fd_ioctl,DRM_AUTH |DRM_UNLOCKED |DRM_RENDER_ALLOW ), +DRM_IOCTL_DEF (DRM_IOCTL_PRIME_FD_TO_HANDLE , drm_prime_fd_to_handle_ioctl,DRM_AUTH |DRM_UNLOCKED |DRM_RENDER_ALLOW ),DRM_IOCTL_DEF (DRM_IOCTL_MODE_GETPLANERESOURCES , drm_mode_getplane_res,DRM_CONTROL_ALLOW |DRM_UNLOCKED ), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
@@ -428,9 +428,10 @@ long drm_ioctl(struct file *filp,DRM_DEBUG ("no function\n" ); retcode = -EINVAL ; }else if (((ioctl->flags &DRM_ROOT_ONLY ) && !capable (CAP_SYS_ADMIN )) || - ((ioctl->flags &DRM_AUTH ) && !file_priv->authenticated) || + ((ioctl->flags &DRM_AUTH ) && !drm_is_render_client (file_priv) && !file_priv->authenticated) || ((ioctl->flags &DRM_MASTER ) && !file_priv->is_master) || - (!(ioctl->flags &DRM_CONTROL_ALLOW ) && (file_priv->minor->type ==DRM_MINOR_CONTROL ))) { + (!(ioctl->flags &DRM_CONTROL_ALLOW ) && (file_priv->minor->type ==DRM_MINOR_CONTROL )) || + (!(ioctl->flags &DRM_RENDER_ALLOW ) &&drm_is_render_client (file_priv))) { retcode = -EACCES ; }else {if (cmd & (IOC_IN |IOC_OUT )) {
drivers/gpu/drm/drm_fops.c +7 -7
@@ -300,10 +300,10 @@ static int drm_open_helper(struct inode *inode, struct file *filp, goto out_prime_destroy; } - -/* if there is no current master make this fd it */ +/* if there is no current master make this fd it, but do not create +* any master object for render clients */ mutex_lock (&dev->struct_mutex); -if (!priv->minor->master) { +if (!priv->minor->master && !drm_is_render_client (priv)) {/* create a new master */ priv->minor->master =drm_master_create (priv->minor);if (!priv->minor->master) {
@@ -341,12 +341,11 @@ static int drm_open_helper(struct inode *inode, struct file *filp, goto out_close; } } -mutex_unlock (&dev->struct_mutex); - }else { + }else if (!drm_is_render_client (priv)) {/* get a reference to the master */ priv->master =drm_master_get (priv->minor->master); -mutex_unlock (&dev->struct_mutex); } +mutex_unlock (&dev->struct_mutex);mutex_lock (&dev->struct_mutex);list_add (&priv->lhead, &dev->filelist);
@@ -547,7 +546,8 @@ int drm_release(struct inode *inode, struct file *filp) iput(container_of(dev->dev_mapping, struct inode, i_data));/* drop the reference held my the file priv */ -drm_master_put (&file_priv->master); +if (file_priv->master) +drm_master_put (&file_priv->master); file_priv->is_master =0 ;list_del (&file_priv->lhead);mutex_unlock (&dev->struct_mutex);
drivers/gpu/drm/drm_pci.c +9 -0
@@ -348,6 +348,12 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, goto err_g2; } +if (drm_core_check_feature (dev,DRIVER_RENDER )) { + ret =drm_get_minor (dev, &dev->render,DRM_MINOR_RENDER ); +if (ret) + goto err_g21; + } +if ((ret =drm_get_minor (dev, &dev->primary,DRM_MINOR_LEGACY ))) goto err_g3;
@@ -377,6 +383,9 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, err_g4:drm_put_minor (&dev->primary); err_g3: +if (drm_core_check_feature (dev,DRIVER_RENDER )) +drm_put_minor (&dev->render); +err_g21:if (drm_core_check_feature (dev,DRIVER_MODESET ))drm_put_minor (&dev->control); err_g2:
drivers/gpu/drm/drm_platform.c +9 -0
@@ -69,6 +69,12 @@ int drm_get_platform_dev(struct platform_device *platdev, goto err_g1; } +if (drm_core_check_feature (dev,DRIVER_RENDER )) { + ret =drm_get_minor (dev, &dev->render,DRM_MINOR_RENDER ); +if (ret) + goto err_g11; + } + ret =drm_get_minor (dev, &dev->primary,DRM_MINOR_LEGACY );if (ret) goto err_g2;
@@ -100,6 +106,9 @@ int drm_get_platform_dev(struct platform_device *platdev, err_g3:drm_put_minor (&dev->primary); err_g2: +if (drm_core_check_feature (dev,DRIVER_RENDER )) +drm_put_minor (&dev->render); +err_g11:if (drm_core_check_feature (dev,DRIVER_MODESET ))drm_put_minor (&dev->control); err_g1:
drivers/gpu/drm/drm_stub.c +5 -0
@@ -473,6 +473,9 @@ void drm_put_dev(struct drm_device *dev)if (drm_core_check_feature (dev,DRIVER_MODESET ))drm_put_minor (&dev->control); +if (drm_core_check_feature (dev,DRIVER_RENDER )) +drm_put_minor (&dev->render); +if (driver->driver_features &DRIVER_GEM )drm_gem_destroy (dev);
@@ -489,6 +492,8 @@ void drm_unplug_dev(struct drm_device *dev)/* for a USB device */ if (drm_core_check_feature (dev,DRIVER_MODESET ))drm_unplug_minor (dev->control); +if (drm_core_check_feature (dev,DRIVER_RENDER )) +drm_unplug_minor (dev->render);drm_unplug_minor (dev->primary);mutex_lock (&drm_global_mutex);
drivers/gpu/drm/drm_usb.c +9 -0
@@ -33,6 +33,12 @@ int drm_get_usb_dev(struct usb_interface *interface,if (ret) goto err_g1; +if (drm_core_check_feature (dev,DRIVER_RENDER )) { + ret =drm_get_minor (dev, &dev->render,DRM_MINOR_RENDER ); +if (ret) + goto err_g11; + } + ret =drm_get_minor (dev, &dev->primary,DRM_MINOR_LEGACY );if (ret) goto err_g2;
@@ -62,6 +68,9 @@ int drm_get_usb_dev(struct usb_interface *interface, err_g3:drm_put_minor (&dev->primary); err_g2: +if (drm_core_check_feature (dev,DRIVER_RENDER )) +drm_put_minor (&dev->render); +err_g11:drm_put_minor (&dev->control); err_g1:kfree (dev);
include/drm/drmP.h +8 -0
@@ -154,6 +154,7 @@ int drm_err(const char *func, const char *format, ...);#define DRIVER_GEM 0x1000#define DRIVER_MODESET 0x2000#define DRIVER_PRIME 0x4000 +#define DRIVER_RENDER 0x8000#define DRIVER_BUS_PCI 0x1#define DRIVER_BUS_PLATFORM 0x2
@@ -308,6 +309,7 @@ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,#define DRM_ROOT_ONLY 0x4#define DRM_CONTROL_ALLOW 0x8#define DRM_UNLOCKED 0x10 +#define DRM_RENDER_ALLOW 0x20struct drm_ioctl_desc {unsigned int cmd;
@@ -1204,6 +1206,7 @@ struct drm_device {unsigned int agp_buffer_token;struct drm_minor *control;/**< Control node for card */ struct drm_minor *primary;/**< render type primary screen head */ +struct drm_minor *render;/**< render node for card */ struct drm_mode_config mode_config;/**< Current mode config */
@@ -1269,6 +1272,11 @@ static inline bool drm_modeset_is_locked(struct drm_device *dev)return mutex_is_locked (&dev->mode_config.mutex); } +static inline bool drm_is_render_client (struct drm_file *file_priv) +{ +return file_priv->minor->type ==DRM_MINOR_RENDER ; +} +/******************************************************************/ /** \name Internal function definitions */ /*@{*/
Signature · 6 lines
1.8.3.2 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
Quoted 32 lines · David Herrmann
Hi
This is v2 of the unified VMA offset manager series. The first draft is available at LWN [1]. This series replaces the VMA offset managers in GEM and TTM with a unified implementation.
The first 4 patches contain the new VMA offset manager and are the only patches that I propose for mainline inclusion.
Patches 5-8 clean updrm_mmand are informational-only. Daniel has similar patches in i915-next and I will rebase them once it is merged. Ignore them if you're not interested.
Patches 9-19 implement mmap access control. Comments are welcome! They are intended for mainline inclusion, too, but probably require some more review rounds. I'd really appreciate if driver authors could comment on the implementation.
Patch 20 shows the main motivation behind this whole series: render nodes. It is marked RFC and I will resend once the VMA manager is merged upstream. Feel free to test it.One more note regarding DRM-Master: Render-clients are independent of DRM-Master (see the DocBook documentation). It really doesn't make sense to create/bind a DRM-Master object to render-clients. However, a lot of core DRM code depends on
->master != NULL. Drivers need to take care not to call into those core modules
if they implementDRIVER_RENDER.
I plan on removing multiple-master-support in the next series. So there will be only one global master and each open-file is bound to it. This will make it very easy to phase out "drm_master". The planned "modeset" nodes provide a nice replacement. If anyone knows a **currently used** use-case for multiple-masters, please tell me. I couldn't find one that_actuallyworks_. (SetMaster+DropMaster will obviously stay functional even withdrm_masterremoved).
Quoted 5 lines
(series available at: https://github.com/dvdhrm/linux/tree/rnodes)
Comments welcome!
Cheers
David
Hi David,
Thanks for this patchset. I am away from my computers for testing but I was wondering if you based your vma rework on Dave's implementation. If so, you may have the same bug that I had with it.
I cannot remember the details of the bug, but I could trigger it by rebooting kde around 13 times on radeon. I didn't have this problem with Nouveau.
I am not competent to judge this work but I will try to test it and check with my security tests that I wrote that the problem is indeed solved on nouveau and radeon.
Looking forward to seeing your proposition for the userspace :)
Cheers,
Martin
Hi
Quoted 55 lines · Martin Peres
Quoted 46 lines · David Herrmann
Hi
This is v2 of the unified VMA offset manager series. The first draft is available at LWN [1]. This series replaces the VMA offset managers in GEM and
TTM with a unified implementation.The first 4 patches contain the new VMA offset manager and are the only patches
that I propose for mainline inclusion.
Patches 5-8 clean updrm_mmand are informational-only. Daniel has similar patches in i915-next and I will rebase them once it is merged. Ignore them if you're not interested.
Patches 9-19 implement mmap access control. Comments are welcome! They are intended for mainline inclusion, too, but probably require some more review
rounds. I'd really appreciate if driver authors could comment on the implementation.
Patch 20 shows the main motivation behind this whole series: render nodes. It is
marked RFC and I will resend once the VMA manager is merged upstream. Feel free
to test it.One more note regarding DRM-Master: Render-clients are independent of DRM-Master
(see the DocBook documentation). It really doesn't make sense to create/bind a
DRM-Master object to render-clients. However, a lot of core DRM code depends on
->master != NULL. Drivers need to take care not to call into those core
modules
if they implementDRIVER_RENDER.
I plan on removing multiple-master-support in the next series. So there will be
only one global master and each open-file is bound to it. This will make it very
easy to phase out "drm_master". The planned "modeset" nodes provide a nice replacement. If anyone knows a **currently used** use-case for multiple-masters,
please tell me. I couldn't find one that_actuallyworks_. (SetMaster+DropMaster
will obviously stay functional even withdrm_masterremoved).Quoted 5 lines
(series available at: https://github.com/dvdhrm/linux/tree/rnodes)
Comments welcome!
Cheers
DavidHi David,
Quoted 7 lines
Thanks for this patchset. I am away from my computers for testing but I was wondering if you based your vma rework on Dave's implementation. If so, you may have the same bug that I had with it.
I cannot remember the details of the bug, but I could trigger it by rebooting
kde around 13 times on radeon. I didn't have this problem with Nouveau.
It is based on Dave's code, but I rewrote all of it and fixed several bugs. For instance, there was a TTM ref-count leak for BOs in TTM core and a TTM locking issue. I didn't encounter any bugs so far, but I didn't try to restart the xserver 13 times. I will do some more stress-tests, but it is quite likely you hit one of those two bugs with radeon.
Quoted 3 lines
I am not competent to judge this work but I will try to test it and check with my security tests that I wrote that the problem is indeed solved on nouveau and radeon.
The changes are actually quite simple. I intentionally kept TTM locking as it was before, even though I think we could reduce it now. Anyway, I will resend v3 (which now includes tegra and staging) this weekend. Hopefully we can get it into linux-next soon.
Thanks!
David
Quoted 4 lines
Looking forward to seeing your proposition for the userspace :)
Cheers,
Martin
Quoted 63 lines · David Herrmann
Hi
Quoted 53 lines · Martin Peres
Quoted 45 lines · David Herrmann
Hi
This is v2 of the unified VMA offset manager series. The first draft is available at LWN [1]. This series replaces the VMA offset managers in GEM and
TTM with a unified implementation.The first 4 patches contain the new VMA offset manager and are the only patches
that I propose for mainline inclusion.
Patches 5-8 clean updrm_mmand are informational-only. Daniel has similar patches in i915-next and I will rebase them once it is merged. Ignore them if you're not interested.
Patches 9-19 implement mmap access control. Comments are welcome! They are intended for mainline inclusion, too, but probably require some more review
rounds. I'd really appreciate if driver authors could comment on the implementation.
Patch 20 shows the main motivation behind this whole series: render nodes. It is
marked RFC and I will resend once the VMA manager is merged upstream. Feel free
to test it.One more note regarding DRM-Master: Render-clients are independent of DRM-Master
(see the DocBook documentation). It really doesn't make sense to create/bind a
DRM-Master object to render-clients. However, a lot of core DRM code depends on
->master != NULL. Drivers need to take care not to call into those core
modules
if they implementDRIVER_RENDER.
I plan on removing multiple-master-support in the next series. So there will be
only one global master and each open-file is bound to it. This will make it very
easy to phase out "drm_master". The planned "modeset" nodes provide a nice replacement. If anyone knows a **currently used** use-case for multiple-masters,
please tell me. I couldn't find one that_actuallyworks_. (SetMaster+DropMaster
will obviously stay functional even withdrm_masterremoved).Quoted 5 lines
(series available at: https://github.com/dvdhrm/linux/tree/rnodes)
Comments welcome!
Cheers
DavidHi David,
Quoted 7 lines
Thanks for this patchset. I am away from my computers for testing but I was wondering if you based your vma rework on Dave's implementation. If so, you may have the same bug that I had with it.
I cannot remember the details of the bug, but I could trigger it by rebooting
kde around 13 times on radeon. I didn't have this problem with Nouveau.
Quoted 6 lines
It is based on Dave's code, but I rewrote all of it and fixed several bugs. For instance, there was a TTM ref-count leak for BOs in TTM core and a TTM locking issue. I didn't encounter any bugs so far, but I didn't try to restart the xserver 13 times. I will do some more stress-tests, but it is quite likely you hit one of those two bugs with radeon.
Yeah, the problem I had was related to ref-count and I was trying to fix the locking too.
Quoted 7 lines
Quoted 3 lines
I am not competent to judge this work but I will try to test it and check with my security tests that I wrote that the problem is indeed solved on nouveau and radeon.
The changes are actually quite simple. I intentionally kept TTM locking as it was before, even though I think we could reduce it now. Anyway, I will resend v3 (which now includes tegra and staging) this weekend. Hopefully we can get it into linux-next soon.
Very nice! Looking forward to it.