@@ -145,6 +145,7 @@ int drm_gem_object_init(struct drm_device *dev,
kref_init(&obj->refcount);
atomic_set(&obj->handle_count, 0);
+ atomic_set(&obj->obj_name_count, 0);
obj->size = size;
return 0;
@@ -166,6 +167,7 @@ int drm_gem_private_object_init(struct drm_device *dev,
kref_init(&obj->refcount);
atomic_set(&obj->handle_count, 0);
+ atomic_set(&obj->obj_name_count, 0);
obj->size = size;
return 0;
@@ -452,6 +454,16 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
return -ENOENT;
again:
+ /*
+ * return current object name increasing reference count of
+ * this object name if exists already.
+ */
+ if (obj->name) {
+ args->name = (uint64_t)obj->name;
+ drm_gem_object_unreference_unlocked(obj);
+ return 0;
+ }
+
if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) {
ret = -ENOMEM;
goto err;
@@ -461,6 +473,7 @@ again:
if (!obj->name) {
ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
&obj->name);
+ atomic_set(&obj->obj_name_count, 1);
args->name = (uint64_t) obj->name;
spin_unlock(&dev->object_name_lock);
@@ -502,8 +515,10 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
spin_lock(&dev->object_name_lock);
obj = idr_find(&dev->object_name_idr, (int) args->name);
- if (obj)
+ if (obj) {
drm_gem_object_reference(obj);
+ atomic_inc(&obj->obj_name_count);
+ }
spin_unlock(&dev->object_name_lock);
if (!obj)
return -ENOENT;
@@ -612,9 +627,25 @@ void drm_gem_object_handle_free(struct drm_gem_object *obj)
/* Remove any name for this object */
spin_lock(&dev->object_name_lock);
if (obj->name) {
- idr_remove(&dev->object_name_idr, obj->name);
- obj->name = 0;
+ /*
+ * The name of this object could being referenced
+ * by another process so remove the name after checking
+ * the obj_name_count of this object.
+ */
+ if (atomic_dec_and_test(&obj->obj_name_count)) {
+ idr_remove(&dev->object_name_idr, obj->name);
+ obj->name = 0;
+ } else {
+ /*
+ * this object name is being referenced by other yet
+ * so do not unreference this.
+ */
+ spin_unlock(&dev->object_name_lock);
+ return;
+ }
+
spin_unlock(&dev->object_name_lock);
+
/*
* The object name held a reference to this object, drop
* that now.
@@ -628,6 +628,18 @@ struct drm_gem_object {
/** Handle count of this object. Each handle also holds a reference */
atomic_t handle_count; /* number of handles on this object */
+ /*
+ * Name count of this object.
+ *
+ * This count is initialized as 0 with drm_gem_object_init or
+ * drm_gem_private_object_init call. After that, this count is
+ * increased if the name of this object exists already
+ * otherwise is set to 1 at flink. And finally, the name of
+ * this object will be released when this count reaches 0
+ * by gem close.
+ */
+ atomic_t obj_name_count;
+
/** Related drm device */
struct drm_device *dev;