Currently there is no easy way for a drm driver to safely check and allow drm_vma_offset_node for a drm file just once. Allow drm drivers to call non-refcounted version of drm_vma_node_allow() so that a driver doesn't need to keep track of each drm_vma_node_allow() to call subsequent drm_vma_node_revoke() to prevent memory leak. Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Maxime Ripard <mripard@kernel.org> Cc: Thomas Zimmermann <tzimmermann@suse.de> Cc: David Airlie <airlied@gmail.com> Cc: Daniel Vetter <daniel@ffwll.ch> Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> Cc: Andi Shyti <andi.shyti@linux.intel.com>
Unified · Split
| @@ -240,27 +240,8 @@ void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr, · 239 unmodified lines | |||
| 240 | } | 240 | } |
| 241 | EXPORT_SYMBOL(drm_vma_offset_remove); | 241 | EXPORT_SYMBOL(drm_vma_offset_remove); |
| 242 | 242 | ||
| 243 | /** | 243 | static int vma_node_allow(struct drm_vma_offset_node *node, |
| 244 | * drm_vma_node_allow - Add open-file to list of allowed users | 244 | struct drm_file *tag, bool ref_counted) |
| 245 | * @node: Node to modify | ||
| 246 | * @tag: Tag of file to remove | ||
| 247 | * | ||
| 248 | * Add @tag to the list of allowed open-files for this node. If @tag is | ||
| 249 | * already on this list, the ref-count is incremented. | ||
| 250 | * | ||
| 251 | * The list of allowed-users is preserved across drm_vma_offset_add() and | ||
| 252 | * drm_vma_offset_remove() calls. You may even call it if the node is currently | ||
| 253 | * not added to any offset-manager. | ||
| 254 | * | ||
| 255 | * You must remove all open-files the same number of times as you added them | ||
| 256 | * before destroying the node. Otherwise, you will leak memory. | ||
| 257 | * | ||
| 258 | * This is locked against concurrent access internally. | ||
| 259 | * | ||
| 260 | * RETURNS: | ||
| 261 | * 0 on success, negative error code on internal failure (out-of-mem) | ||
| 262 | */ | ||
| 263 | int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag) | ||
| 264 | { | 245 | { |
| 265 | struct rb_node **iter; | 246 | struct rb_node **iter; |
| 266 | struct rb_node *parent = NULL; | 247 | struct rb_node *parent = NULL; |
| @@ -282,7 +263,8 @@ int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag) · 15 unmodified lines | |||
| 282 | entry = rb_entry(*iter, struct drm_vma_offset_file, vm_rb); | 263 | entry = rb_entry(*iter, struct drm_vma_offset_file, vm_rb); |
| 283 | 264 | ||
| 284 | if (tag == entry->vm_tag) { | 265 | if (tag == entry->vm_tag) { |
| 285 | entry->vm_count++; | 266 | if (ref_counted) |
| 267 | entry->vm_count++; | ||
| 286 | goto unlock; | 268 | goto unlock; |
| 287 | } else if (tag > entry->vm_tag) { | 269 | } else if (tag > entry->vm_tag) { |
| 288 | iter = &(*iter)->rb_right; | 270 | iter = &(*iter)->rb_right; |
| @@ -307,8 +289,58 @@ unlock: · 18 unmodified lines | |||
| 307 | kfree(new); | 289 | kfree(new); |
| 308 | return ret; | 290 | return ret; |
| 309 | } | 291 | } |
| 292 | |||
| 293 | /** | ||
| 294 | * drm_vma_node_allow - Add open-file to list of allowed users | ||
| 295 | * @node: Node to modify | ||
| 296 | * @tag: Tag of file to remove | ||
| 297 | * | ||
| 298 | * Add @tag to the list of allowed open-files for this node. If @tag is | ||
| 299 | * already on this list, the ref-count is incremented. | ||
| 300 | * | ||
| 301 | * The list of allowed-users is preserved across drm_vma_offset_add() and | ||
| 302 | * drm_vma_offset_remove() calls. You may even call it if the node is currently | ||
| 303 | * not added to any offset-manager. | ||
| 304 | * | ||
| 305 | * You must remove all open-files the same number of times as you added them | ||
| 306 | * before destroying the node. Otherwise, you will leak memory. | ||
| 307 | * | ||
| 308 | * This is locked against concurrent access internally. | ||
| 309 | * | ||
| 310 | * RETURNS: | ||
| 311 | * 0 on success, negative error code on internal failure (out-of-mem) | ||
| 312 | */ | ||
| 313 | int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag) | ||
| 314 | { | ||
| 315 | return vma_node_allow(node, tag, true); | ||
| 316 | } | ||
| 310 | EXPORT_SYMBOL(drm_vma_node_allow); | 317 | EXPORT_SYMBOL(drm_vma_node_allow); |
| 311 | 318 | ||
| 319 | /** | ||
| 320 | * drm_vma_node_allow_once - Add open-file to list of allowed users | ||
| 321 | * @node: Node to modify | ||
| 322 | * @tag: Tag of file to remove | ||
| 323 | * | ||
| 324 | * Add @tag to the list of allowed open-files for this node. | ||
| 325 | * | ||
| 326 | * The list of allowed-users is preserved across drm_vma_offset_add() and | ||
| 327 | * drm_vma_offset_remove() calls. You may even call it if the node is currently | ||
| 328 | * not added to any offset-manager. | ||
| 329 | * | ||
| 330 | * This is not ref-counted unlike drm_vma_node_allow() hence drm_vma_node_revoke() | ||
| 331 | * should only be called once after this. | ||
| 332 | * | ||
| 333 | * This is locked against concurrent access internally. | ||
| 334 | * | ||
| 335 | * RETURNS: | ||
| 336 | * 0 on success, negative error code on internal failure (out-of-mem) | ||
| 337 | */ | ||
| 338 | int drm_vma_node_allow_once(struct drm_vma_offset_node *node, struct drm_file *tag) | ||
| 339 | { | ||
| 340 | return vma_node_allow(node, tag, false); | ||
| 341 | } | ||
| 342 | EXPORT_SYMBOL(drm_vma_node_allow_once); | ||
| 343 | |||
| 312 | /** | 344 | /** |
| 313 | * drm_vma_node_revoke - Remove open-file from list of allowed users | 345 | * drm_vma_node_revoke - Remove open-file from list of allowed users |
| 314 | * @node: Node to modify | 346 | * @node: Node to modify |
| @@ -74,6 +74,7 @@ void drm_vma_offset_remove(struct drm_vma_offset_manager *mgr, · 73 unmodified lines | |||
| 74 | struct drm_vma_offset_node *node); | 74 | struct drm_vma_offset_node *node); |
| 75 | 75 | ||
| 76 | int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag); | 76 | int drm_vma_node_allow(struct drm_vma_offset_node *node, struct drm_file *tag); |
| 77 | int drm_vma_node_allow_once(struct drm_vma_offset_node *node, struct drm_file *tag); | ||
| 77 | void drm_vma_node_revoke(struct drm_vma_offset_node *node, | 78 | void drm_vma_node_revoke(struct drm_vma_offset_node *node, |
| 78 | struct drm_file *tag); | 79 | struct drm_file *tag); |
| 79 | bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, | 80 | bool drm_vma_node_is_allowed(struct drm_vma_offset_node *node, |