diff options
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_gem.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_prime.c | 70 | ||||
-rw-r--r-- | include/drm/drmP.h | 12 |
4 files changed, 87 insertions, 20 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 59f459291093..2d2401e9c5ae 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c | |||
@@ -486,6 +486,7 @@ int drm_release(struct inode *inode, struct file *filp) | |||
486 | if (dev->driver->postclose) | 486 | if (dev->driver->postclose) |
487 | dev->driver->postclose(dev, file_priv); | 487 | dev->driver->postclose(dev, file_priv); |
488 | 488 | ||
489 | |||
489 | if (drm_core_check_feature(dev, DRIVER_PRIME)) | 490 | if (drm_core_check_feature(dev, DRIVER_PRIME)) |
490 | drm_prime_destroy_file_private(&file_priv->prime); | 491 | drm_prime_destroy_file_private(&file_priv->prime); |
491 | 492 | ||
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index d47aa774d64b..4b3c533be859 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c | |||
@@ -195,9 +195,14 @@ drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp) | |||
195 | drm_prime_remove_buf_handle(&filp->prime, | 195 | drm_prime_remove_buf_handle(&filp->prime, |
196 | obj->import_attach->dmabuf); | 196 | obj->import_attach->dmabuf); |
197 | } | 197 | } |
198 | if (obj->export_dma_buf) { | 198 | |
199 | /* | ||
200 | * Note: obj->dma_buf can't disappear as long as we still hold a | ||
201 | * handle reference in obj->handle_count. | ||
202 | */ | ||
203 | if (obj->dma_buf) { | ||
199 | drm_prime_remove_buf_handle(&filp->prime, | 204 | drm_prime_remove_buf_handle(&filp->prime, |
200 | obj->export_dma_buf); | 205 | obj->dma_buf); |
201 | } | 206 | } |
202 | } | 207 | } |
203 | 208 | ||
@@ -231,6 +236,15 @@ static void drm_gem_object_handle_free(struct drm_gem_object *obj) | |||
231 | } | 236 | } |
232 | } | 237 | } |
233 | 238 | ||
239 | static void drm_gem_object_exported_dma_buf_free(struct drm_gem_object *obj) | ||
240 | { | ||
241 | /* Unbreak the reference cycle if we have an exported dma_buf. */ | ||
242 | if (obj->dma_buf) { | ||
243 | dma_buf_put(obj->dma_buf); | ||
244 | obj->dma_buf = NULL; | ||
245 | } | ||
246 | } | ||
247 | |||
234 | static void | 248 | static void |
235 | drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj) | 249 | drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj) |
236 | { | 250 | { |
@@ -244,8 +258,10 @@ drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj) | |||
244 | */ | 258 | */ |
245 | 259 | ||
246 | mutex_lock(&obj->dev->object_name_lock); | 260 | mutex_lock(&obj->dev->object_name_lock); |
247 | if (--obj->handle_count == 0) | 261 | if (--obj->handle_count == 0) { |
248 | drm_gem_object_handle_free(obj); | 262 | drm_gem_object_handle_free(obj); |
263 | drm_gem_object_exported_dma_buf_free(obj); | ||
264 | } | ||
249 | mutex_unlock(&obj->dev->object_name_lock); | 265 | mutex_unlock(&obj->dev->object_name_lock); |
250 | 266 | ||
251 | drm_gem_object_unreference_unlocked(obj); | 267 | drm_gem_object_unreference_unlocked(obj); |
@@ -712,6 +728,8 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private) | |||
712 | void | 728 | void |
713 | drm_gem_object_release(struct drm_gem_object *obj) | 729 | drm_gem_object_release(struct drm_gem_object *obj) |
714 | { | 730 | { |
731 | WARN_ON(obj->dma_buf); | ||
732 | |||
715 | if (obj->filp) | 733 | if (obj->filp) |
716 | fput(obj->filp); | 734 | fput(obj->filp); |
717 | } | 735 | } |
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 3d576018893a..5e543e9264d7 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c | |||
@@ -193,11 +193,8 @@ void drm_gem_dmabuf_release(struct dma_buf *dma_buf) | |||
193 | { | 193 | { |
194 | struct drm_gem_object *obj = dma_buf->priv; | 194 | struct drm_gem_object *obj = dma_buf->priv; |
195 | 195 | ||
196 | if (obj->export_dma_buf == dma_buf) { | 196 | /* drop the reference on the export fd holds */ |
197 | /* drop the reference on the export fd holds */ | 197 | drm_gem_object_unreference_unlocked(obj); |
198 | obj->export_dma_buf = NULL; | ||
199 | drm_gem_object_unreference_unlocked(obj); | ||
200 | } | ||
201 | } | 198 | } |
202 | EXPORT_SYMBOL(drm_gem_dmabuf_release); | 199 | EXPORT_SYMBOL(drm_gem_dmabuf_release); |
203 | 200 | ||
@@ -298,6 +295,37 @@ struct dma_buf *drm_gem_prime_export(struct drm_device *dev, | |||
298 | } | 295 | } |
299 | EXPORT_SYMBOL(drm_gem_prime_export); | 296 | EXPORT_SYMBOL(drm_gem_prime_export); |
300 | 297 | ||
298 | static struct dma_buf *export_and_register_object(struct drm_device *dev, | ||
299 | struct drm_gem_object *obj, | ||
300 | uint32_t flags) | ||
301 | { | ||
302 | struct dma_buf *dmabuf; | ||
303 | |||
304 | /* prevent races with concurrent gem_close. */ | ||
305 | if (obj->handle_count == 0) { | ||
306 | dmabuf = ERR_PTR(-ENOENT); | ||
307 | return dmabuf; | ||
308 | } | ||
309 | |||
310 | dmabuf = dev->driver->gem_prime_export(dev, obj, flags); | ||
311 | if (IS_ERR(dmabuf)) { | ||
312 | /* normally the created dma-buf takes ownership of the ref, | ||
313 | * but if that fails then drop the ref | ||
314 | */ | ||
315 | return dmabuf; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Note that callers do not need to clean up the export cache | ||
320 | * since the check for obj->handle_count guarantees that someone | ||
321 | * will clean it up. | ||
322 | */ | ||
323 | obj->dma_buf = dmabuf; | ||
324 | get_dma_buf(obj->dma_buf); | ||
325 | |||
326 | return dmabuf; | ||
327 | } | ||
328 | |||
301 | int drm_gem_prime_handle_to_fd(struct drm_device *dev, | 329 | int drm_gem_prime_handle_to_fd(struct drm_device *dev, |
302 | struct drm_file *file_priv, uint32_t handle, uint32_t flags, | 330 | struct drm_file *file_priv, uint32_t handle, uint32_t flags, |
303 | int *prime_fd) | 331 | int *prime_fd) |
@@ -313,15 +341,20 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, | |||
313 | /* re-export the original imported object */ | 341 | /* re-export the original imported object */ |
314 | if (obj->import_attach) { | 342 | if (obj->import_attach) { |
315 | dmabuf = obj->import_attach->dmabuf; | 343 | dmabuf = obj->import_attach->dmabuf; |
344 | get_dma_buf(dmabuf); | ||
316 | goto out_have_obj; | 345 | goto out_have_obj; |
317 | } | 346 | } |
318 | 347 | ||
319 | if (obj->export_dma_buf) { | 348 | mutex_lock(&dev->object_name_lock); |
320 | dmabuf = obj->export_dma_buf; | 349 | if (obj->dma_buf) { |
350 | get_dma_buf(obj->dma_buf); | ||
351 | dmabuf = obj->dma_buf; | ||
352 | mutex_unlock(&dev->object_name_lock); | ||
321 | goto out_have_obj; | 353 | goto out_have_obj; |
322 | } | 354 | } |
323 | 355 | ||
324 | dmabuf = dev->driver->gem_prime_export(dev, obj, flags); | 356 | dmabuf = export_and_register_object(dev, obj, flags); |
357 | mutex_unlock(&dev->object_name_lock); | ||
325 | if (IS_ERR(dmabuf)) { | 358 | if (IS_ERR(dmabuf)) { |
326 | /* normally the created dma-buf takes ownership of the ref, | 359 | /* normally the created dma-buf takes ownership of the ref, |
327 | * but if that fails then drop the ref | 360 | * but if that fails then drop the ref |
@@ -329,14 +362,13 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, | |||
329 | ret = PTR_ERR(dmabuf); | 362 | ret = PTR_ERR(dmabuf); |
330 | goto out; | 363 | goto out; |
331 | } | 364 | } |
332 | obj->export_dma_buf = dmabuf; | ||
333 | 365 | ||
334 | mutex_lock(&file_priv->prime.lock); | 366 | mutex_lock(&file_priv->prime.lock); |
335 | /* if we've exported this buffer the cheat and add it to the import list | 367 | /* if we've exported this buffer the cheat and add it to the import list |
336 | * so we get the correct handle back | 368 | * so we get the correct handle back |
337 | */ | 369 | */ |
338 | ret = drm_prime_add_buf_handle(&file_priv->prime, | 370 | ret = drm_prime_add_buf_handle(&file_priv->prime, |
339 | obj->export_dma_buf, handle); | 371 | dmabuf, handle); |
340 | if (ret) | 372 | if (ret) |
341 | goto fail_put_dmabuf; | 373 | goto fail_put_dmabuf; |
342 | 374 | ||
@@ -349,7 +381,6 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev, | |||
349 | return 0; | 381 | return 0; |
350 | 382 | ||
351 | out_have_obj: | 383 | out_have_obj: |
352 | get_dma_buf(dmabuf); | ||
353 | ret = dma_buf_fd(dmabuf, flags); | 384 | ret = dma_buf_fd(dmabuf, flags); |
354 | if (ret < 0) { | 385 | if (ret < 0) { |
355 | dma_buf_put(dmabuf); | 386 | dma_buf_put(dmabuf); |
@@ -365,8 +396,6 @@ fail_rm_handle: | |||
365 | dmabuf); | 396 | dmabuf); |
366 | mutex_unlock(&file_priv->prime.lock); | 397 | mutex_unlock(&file_priv->prime.lock); |
367 | fail_put_dmabuf: | 398 | fail_put_dmabuf: |
368 | /* clear NOT to be checked when releasing dma_buf */ | ||
369 | obj->export_dma_buf = NULL; | ||
370 | dma_buf_put(dmabuf); | 399 | dma_buf_put(dmabuf); |
371 | out: | 400 | out: |
372 | drm_gem_object_unreference_unlocked(obj); | 401 | drm_gem_object_unreference_unlocked(obj); |
@@ -448,13 +477,22 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev, | |||
448 | goto out_put; | 477 | goto out_put; |
449 | 478 | ||
450 | /* never seen this one, need to import */ | 479 | /* never seen this one, need to import */ |
480 | mutex_lock(&dev->object_name_lock); | ||
451 | obj = dev->driver->gem_prime_import(dev, dma_buf); | 481 | obj = dev->driver->gem_prime_import(dev, dma_buf); |
452 | if (IS_ERR(obj)) { | 482 | if (IS_ERR(obj)) { |
453 | ret = PTR_ERR(obj); | 483 | ret = PTR_ERR(obj); |
454 | goto out_put; | 484 | goto out_unlock; |
485 | } | ||
486 | |||
487 | if (obj->dma_buf) { | ||
488 | WARN_ON(obj->dma_buf != dma_buf); | ||
489 | } else { | ||
490 | obj->dma_buf = dma_buf; | ||
491 | get_dma_buf(dma_buf); | ||
455 | } | 492 | } |
456 | 493 | ||
457 | ret = drm_gem_handle_create(file_priv, obj, handle); | 494 | /* drm_gem_handle_create_tail unlocks dev->object_name_lock. */ |
495 | ret = drm_gem_handle_create_tail(file_priv, obj, handle); | ||
458 | drm_gem_object_unreference_unlocked(obj); | 496 | drm_gem_object_unreference_unlocked(obj); |
459 | if (ret) | 497 | if (ret) |
460 | goto out_put; | 498 | goto out_put; |
@@ -475,6 +513,8 @@ fail: | |||
475 | * to detach.. which seems ok.. | 513 | * to detach.. which seems ok.. |
476 | */ | 514 | */ |
477 | drm_gem_handle_delete(file_priv, *handle); | 515 | drm_gem_handle_delete(file_priv, *handle); |
516 | out_unlock: | ||
517 | mutex_lock(&dev->object_name_lock); | ||
478 | out_put: | 518 | out_put: |
479 | dma_buf_put(dma_buf); | 519 | dma_buf_put(dma_buf); |
480 | mutex_unlock(&file_priv->prime.lock); | 520 | mutex_unlock(&file_priv->prime.lock); |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 063eac31b97b..a95db49b3f9e 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
@@ -667,8 +667,16 @@ struct drm_gem_object { | |||
667 | 667 | ||
668 | void *driver_private; | 668 | void *driver_private; |
669 | 669 | ||
670 | /* dma buf exported from this GEM object */ | 670 | /** |
671 | struct dma_buf *export_dma_buf; | 671 | * dma_buf - dma buf associated with this GEM object |
672 | * | ||
673 | * Pointer to the dma-buf associated with this gem object (either | ||
674 | * through importing or exporting). We break the resulting reference | ||
675 | * loop when the last gem handle for this object is released. | ||
676 | * | ||
677 | * Protected by obj->object_name_lock | ||
678 | */ | ||
679 | struct dma_buf *dma_buf; | ||
672 | 680 | ||
673 | /** | 681 | /** |
674 | * import_attach - dma buf attachment backing this object | 682 | * import_attach - dma buf attachment backing this object |