@@ -76,6 +76,7 @@
#include "gt/intel_gpu_commands.h"
#include "gt/intel_ring.h"
+#include "i915_drm_client.h"
#include "i915_gem_context.h"
#include "i915_globals.h"
#include "i915_trace.h"
@@ -2321,6 +2322,10 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
return -EIO;
}
+ ret = i915_drm_client_update(ext_data.fpriv->client, current);
+ if (ret)
+ return ret;
+
ext_data.ctx = i915_gem_create_context(i915, args->flags);
if (IS_ERR(ext_data.ctx))
return PTR_ERR(ext_data.ctx);
@@ -7,7 +7,10 @@
#include <linux/slab.h>
#include <linux/types.h>
+#include <drm/drm_print.h>
+
#include "i915_drm_client.h"
+#include "i915_drv.h"
#include "i915_gem.h"
#include "i915_utils.h"
@@ -20,26 +23,57 @@ void i915_drm_clients_init(struct i915_drm_clients *clients,
xa_init_flags(&clients->xarray, XA_FLAGS_ALLOC);
}
+static struct i915_drm_client_name *get_name(struct i915_drm_client *client,
+ struct task_struct *task)
+{
+ struct i915_drm_client_name *name;
+ int len = strlen(task->comm);
+
+ name = kmalloc(struct_size(name, name, len + 1), GFP_KERNEL);
+ if (!name)
+ return NULL;
+
+ init_rcu_head(&name->rcu);
+ name->client = client;
+ name->pid = get_task_pid(task, PIDTYPE_PID);
+ memcpy(name->name, task->comm, len + 1);
+
+ return name;
+}
+
+static void free_name(struct rcu_head *rcu)
+{
+ struct i915_drm_client_name *name =
+ container_of(rcu, typeof(*name), rcu);
+
+ put_pid(name->pid);
+ kfree(name);
+}
+
static int
__i915_drm_client_register(struct i915_drm_client *client,
struct task_struct *task)
{
- char *name;
+ struct i915_drm_client_name *name;
- name = kstrdup(task->comm, GFP_KERNEL);
+ name = get_name(client, task);
if (!name)
return -ENOMEM;
- client->pid = get_task_pid(task, PIDTYPE_PID);
- client->name = name;
+ RCU_INIT_POINTER(client->name, name);
return 0;
}
static void __i915_drm_client_unregister(struct i915_drm_client *client)
{
- put_pid(fetch_and_zero(&client->pid));
- kfree(fetch_and_zero(&client->name));
+ struct i915_drm_client_name *name;
+
+ mutex_lock(&client->update_lock);
+ name = rcu_replace_pointer(client->name, NULL, true);
+ mutex_unlock(&client->update_lock);
+
+ call_rcu(&name->rcu, free_name);
}
static void __rcu_i915_drm_client_free(struct work_struct *wrk)
@@ -65,6 +99,7 @@ i915_drm_client_add(struct i915_drm_clients *clients, struct task_struct *task)
return ERR_PTR(-ENOMEM);
kref_init(&client->kref);
+ mutex_init(&client->update_lock);
client->clients = clients;
INIT_RCU_WORK(&client->rcu, __rcu_i915_drm_client_free);
@@ -102,6 +137,25 @@ void i915_drm_client_close(struct i915_drm_client *client)
i915_drm_client_put(client);
}
+int
+i915_drm_client_update(struct i915_drm_client *client,
+ struct task_struct *task)
+{
+ struct i915_drm_client_name *name;
+
+ name = get_name(client, task);
+ if (!name)
+ return -ENOMEM;
+
+ mutex_lock(&client->update_lock);
+ if (name->pid != rcu_dereference_protected(client->name, true)->pid)
+ name = rcu_replace_pointer(client->name, name, true);
+ mutex_unlock(&client->update_lock);
+
+ call_rcu(&name->rcu, free_name);
+ return 0;
+}
+
void i915_drm_clients_fini(struct i915_drm_clients *clients)
{
while (!xa_empty(&clients->xarray)) {
@@ -7,6 +7,7 @@
#define __I915_DRM_CLIENT_H__
#include <linux/kref.h>
+#include <linux/mutex.h>
#include <linux/pid.h>
#include <linux/rcupdate.h>
#include <linux/sched.h>
@@ -21,14 +22,22 @@ struct i915_drm_clients {
u32 next_id;
};
+struct i915_drm_client_name {
+ struct rcu_head rcu;
+ struct i915_drm_client *client;
+ struct pid *pid;
+ char name[];
+};
+
struct i915_drm_client {
struct kref kref;
struct rcu_work rcu;
+ struct mutex update_lock; /* Serializes name and pid updates. */
+
unsigned int id;
- struct pid *pid;
- char *name;
+ struct i915_drm_client_name __rcu *name;
bool closed;
struct i915_drm_clients *clients;
@@ -56,6 +65,27 @@ void i915_drm_client_close(struct i915_drm_client *client);
struct i915_drm_client *i915_drm_client_add(struct i915_drm_clients *clients,
struct task_struct *task);
+int i915_drm_client_update(struct i915_drm_client *client,
+ struct task_struct *task);
+
+static inline const struct i915_drm_client_name *
+__i915_drm_client_name(const struct i915_drm_client *client)
+{
+ return rcu_dereference(client->name);
+}
+
+static inline const char *
+i915_drm_client_name(const struct i915_drm_client *client)
+{
+ return __i915_drm_client_name(client)->name;
+}
+
+static inline struct pid *
+i915_drm_client_pid(const struct i915_drm_client *client)
+{
+ return __i915_drm_client_name(client)->pid;
+}
+
void i915_drm_clients_fini(struct i915_drm_clients *clients);
#endif /* !__I915_DRM_CLIENT_H__ */