Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: Switch blobs to the new generic modeset obj refcounting

Need to move the free function around a bit, but otherwise mostly
just removing code.

Specifically we can nuke all the _locked variants since the weak idr
reference is now protected by the idr_mutex, which we never hold
anywhere expect in the lookup/reg/unreg functions. And those never
call anything else.

Another benefit of this is that this patch switches the weak reference
logic from kref_put_mutex to kref_get_unless_zero. And the later is in
general more flexible wrt accomodating multiple weak references
protected by different locks, which might or might not come handy
eventually.

But one consequence of that switch is that we need to acquire the
blob_lock from the free function for the list_del calls. That's a bit
tricky to pull off, but works well if we pick the exact same scheme as
is already used for framebuffers. Most important changes:

- filp list is maintainer by create/destroy_blob ioctls directly
(already the case, so we can just remove the redundant list_del from
the free function).

- filp close handler walks the filp-private list lockless - works
because we know no one else can access it. I copied the same comment
from the fb code over to explain this.

- Otherwise we need to sufficiently restrict blob_lock critical
sections to avoid all the unreference calls. Easy to do once the
blob_lock only protects the list, and no longer the weak reference.

Cc: Dave Airlie <airlied@gmail.com>
Cc: Daniel Stone <daniels@collabora.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>

authored by

Daniel Vetter and committed by
Dave Airlie
152ef5fa b0b5511b

+45 -120
+45 -119
drivers/gpu/drm/drm_crtc.c
··· 360 360 obj = NULL; 361 361 if (obj && obj->id != id) 362 362 obj = NULL; 363 - /* don't leak out unref'd fb's */ 364 - if (obj && 365 - obj->type == DRM_MODE_OBJECT_BLOB) 366 - obj = NULL; 367 363 368 364 if (obj && obj->free_cb) { 369 365 if (!kref_get_unless_zero(&obj->refcount)) ··· 385 389 { 386 390 struct drm_mode_object *obj = NULL; 387 391 388 - WARN_ON(type == DRM_MODE_OBJECT_BLOB); 389 392 obj = _object_find(dev, id, type); 390 393 return obj; 391 394 } ··· 4254 4259 return ret; 4255 4260 } 4256 4261 4262 + static void drm_property_free_blob(struct kref *kref) 4263 + { 4264 + struct drm_property_blob *blob = 4265 + container_of(kref, struct drm_property_blob, base.refcount); 4266 + 4267 + mutex_lock(&blob->dev->mode_config.blob_lock); 4268 + list_del(&blob->head_global); 4269 + mutex_unlock(&blob->dev->mode_config.blob_lock); 4270 + 4271 + drm_mode_object_unregister(blob->dev, &blob->base); 4272 + 4273 + kfree(blob); 4274 + } 4275 + 4257 4276 /** 4258 4277 * drm_property_create_blob - Create new blob property 4259 4278 * ··· 4305 4296 if (data) 4306 4297 memcpy(blob->data, data, length); 4307 4298 4308 - mutex_lock(&dev->mode_config.blob_lock); 4309 - 4310 - ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); 4299 + ret = drm_mode_object_get_reg(dev, &blob->base, DRM_MODE_OBJECT_BLOB, 4300 + true, drm_property_free_blob); 4311 4301 if (ret) { 4312 4302 kfree(blob); 4313 - mutex_unlock(&dev->mode_config.blob_lock); 4314 4303 return ERR_PTR(-EINVAL); 4315 4304 } 4316 4305 4317 - kref_init(&blob->refcount); 4318 - 4306 + mutex_lock(&dev->mode_config.blob_lock); 4319 4307 list_add_tail(&blob->head_global, 4320 4308 &dev->mode_config.property_blob_list); 4321 - 4322 4309 mutex_unlock(&dev->mode_config.blob_lock); 4323 4310 4324 4311 return blob; 4325 4312 } 4326 4313 EXPORT_SYMBOL(drm_property_create_blob); 4327 - 4328 - /** 4329 - * drm_property_free_blob - Blob property destructor 4330 - * 4331 - * Internal free function for blob properties; must not be used directly. 4332 - * 4333 - * @kref: Reference 4334 - */ 4335 - static void drm_property_free_blob(struct kref *kref) 4336 - { 4337 - struct drm_property_blob *blob = 4338 - container_of(kref, struct drm_property_blob, refcount); 4339 - 4340 - WARN_ON(!mutex_is_locked(&blob->dev->mode_config.blob_lock)); 4341 - 4342 - list_del(&blob->head_global); 4343 - list_del(&blob->head_file); 4344 - drm_mode_object_unregister(blob->dev, &blob->base); 4345 - 4346 - kfree(blob); 4347 - } 4348 4314 4349 4315 /** 4350 4316 * drm_property_unreference_blob - Unreference a blob property ··· 4330 4346 */ 4331 4347 void drm_property_unreference_blob(struct drm_property_blob *blob) 4332 4348 { 4333 - struct drm_device *dev; 4334 - 4335 4349 if (!blob) 4336 4350 return; 4337 4351 4338 - dev = blob->dev; 4339 - 4340 - DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 4341 - 4342 - if (kref_put_mutex(&blob->refcount, drm_property_free_blob, 4343 - &dev->mode_config.blob_lock)) 4344 - mutex_unlock(&dev->mode_config.blob_lock); 4345 - else 4346 - might_lock(&dev->mode_config.blob_lock); 4352 + drm_mode_object_unreference(&blob->base); 4347 4353 } 4348 4354 EXPORT_SYMBOL(drm_property_unreference_blob); 4349 - 4350 - /** 4351 - * drm_property_unreference_blob_locked - Unreference a blob property with blob_lock held 4352 - * 4353 - * Drop a reference on a blob property. May free the object. This must be 4354 - * called with blob_lock held. 4355 - * 4356 - * @blob: Pointer to blob property 4357 - */ 4358 - static void drm_property_unreference_blob_locked(struct drm_property_blob *blob) 4359 - { 4360 - if (!blob) 4361 - return; 4362 - 4363 - DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 4364 - 4365 - kref_put(&blob->refcount, drm_property_free_blob); 4366 - } 4367 4355 4368 4356 /** 4369 4357 * drm_property_destroy_user_blobs - destroy all blobs created by this client ··· 4347 4391 { 4348 4392 struct drm_property_blob *blob, *bt; 4349 4393 4350 - mutex_lock(&dev->mode_config.blob_lock); 4351 - 4394 + /* 4395 + * When the file gets released that means no one else can access the 4396 + * blob list any more, so no need to grab dev->blob_lock. 4397 + */ 4352 4398 list_for_each_entry_safe(blob, bt, &file_priv->blobs, head_file) { 4353 4399 list_del_init(&blob->head_file); 4354 - drm_property_unreference_blob_locked(blob); 4400 + drm_property_unreference_blob(blob); 4355 4401 } 4356 - 4357 - mutex_unlock(&dev->mode_config.blob_lock); 4358 4402 } 4359 4403 4360 4404 /** ··· 4366 4410 */ 4367 4411 struct drm_property_blob *drm_property_reference_blob(struct drm_property_blob *blob) 4368 4412 { 4369 - DRM_DEBUG("%p: blob ID: %d (%d)\n", blob, blob->base.id, atomic_read(&blob->refcount.refcount)); 4370 - kref_get(&blob->refcount); 4413 + drm_mode_object_reference(&blob->base); 4371 4414 return blob; 4372 4415 } 4373 4416 EXPORT_SYMBOL(drm_property_reference_blob); 4374 - 4375 - /* 4376 - * Like drm_property_lookup_blob, but does not return an additional reference. 4377 - * Must be called with blob_lock held. 4378 - */ 4379 - static struct drm_property_blob *__drm_property_lookup_blob(struct drm_device *dev, 4380 - uint32_t id) 4381 - { 4382 - struct drm_mode_object *obj = NULL; 4383 - struct drm_property_blob *blob; 4384 - 4385 - WARN_ON(!mutex_is_locked(&dev->mode_config.blob_lock)); 4386 - 4387 - mutex_lock(&dev->mode_config.idr_mutex); 4388 - obj = idr_find(&dev->mode_config.crtc_idr, id); 4389 - if (!obj || (obj->type != DRM_MODE_OBJECT_BLOB) || (obj->id != id)) 4390 - blob = NULL; 4391 - else 4392 - blob = obj_to_blob(obj); 4393 - mutex_unlock(&dev->mode_config.idr_mutex); 4394 - 4395 - return blob; 4396 - } 4397 4417 4398 4418 /** 4399 4419 * drm_property_lookup_blob - look up a blob property and take a reference ··· 4383 4451 struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev, 4384 4452 uint32_t id) 4385 4453 { 4386 - struct drm_property_blob *blob; 4454 + struct drm_mode_object *obj; 4455 + struct drm_property_blob *blob = NULL; 4387 4456 4388 - mutex_lock(&dev->mode_config.blob_lock); 4389 - blob = __drm_property_lookup_blob(dev, id); 4390 - if (blob) { 4391 - if (!kref_get_unless_zero(&blob->refcount)) 4392 - blob = NULL; 4393 - } 4394 - mutex_unlock(&dev->mode_config.blob_lock); 4395 - 4457 + obj = _object_find(dev, id, DRM_MODE_OBJECT_BLOB); 4458 + if (obj) 4459 + blob = obj_to_blob(obj); 4396 4460 return blob; 4397 4461 } 4398 4462 EXPORT_SYMBOL(drm_property_lookup_blob); ··· 4493 4565 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4494 4566 return -EINVAL; 4495 4567 4496 - drm_modeset_lock_all(dev); 4497 - mutex_lock(&dev->mode_config.blob_lock); 4498 - blob = __drm_property_lookup_blob(dev, out_resp->blob_id); 4499 - if (!blob) { 4500 - ret = -ENOENT; 4501 - goto done; 4502 - } 4568 + blob = drm_property_lookup_blob(dev, out_resp->blob_id); 4569 + if (!blob) 4570 + return -ENOENT; 4503 4571 4504 4572 if (out_resp->length == blob->length) { 4505 4573 blob_ptr = (void __user *)(unsigned long)out_resp->data; 4506 4574 if (copy_to_user(blob_ptr, blob->data, blob->length)) { 4507 4575 ret = -EFAULT; 4508 - goto done; 4576 + goto unref; 4509 4577 } 4510 4578 } 4511 4579 out_resp->length = blob->length; 4580 + unref: 4581 + drm_property_unreference_blob(blob); 4512 4582 4513 - done: 4514 - mutex_unlock(&dev->mode_config.blob_lock); 4515 - drm_modeset_unlock_all(dev); 4516 4583 return ret; 4517 4584 } 4518 4585 ··· 4586 4663 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 4587 4664 return -EINVAL; 4588 4665 4589 - mutex_lock(&dev->mode_config.blob_lock); 4590 - blob = __drm_property_lookup_blob(dev, out_resp->blob_id); 4591 - if (!blob) { 4592 - ret = -ENOENT; 4593 - goto err; 4594 - } 4666 + blob = drm_property_lookup_blob(dev, out_resp->blob_id); 4667 + if (!blob) 4668 + return -ENOENT; 4595 4669 4670 + mutex_lock(&dev->mode_config.blob_lock); 4596 4671 /* Ensure the property was actually created by this user. */ 4597 4672 list_for_each_entry(bt, &file_priv->blobs, head_file) { 4598 4673 if (bt == blob) { ··· 4607 4686 /* We must drop head_file here, because we may not be the last 4608 4687 * reference on the blob. */ 4609 4688 list_del_init(&blob->head_file); 4610 - drm_property_unreference_blob_locked(blob); 4611 4689 mutex_unlock(&dev->mode_config.blob_lock); 4690 + 4691 + /* One reference from lookup, and one from the filp. */ 4692 + drm_property_unreference_blob(blob); 4693 + drm_property_unreference_blob(blob); 4612 4694 4613 4695 return 0; 4614 4696 4615 4697 err: 4616 4698 mutex_unlock(&dev->mode_config.blob_lock); 4699 + drm_property_unreference_blob(blob); 4700 + 4617 4701 return ret; 4618 4702 } 4619 4703
-1
include/drm/drm_crtc.h
··· 250 250 struct drm_property_blob { 251 251 struct drm_mode_object base; 252 252 struct drm_device *dev; 253 - struct kref refcount; 254 253 struct list_head head_global; 255 254 struct list_head head_file; 256 255 size_t length;