forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
drm/i915: Expose list of clients in sysfs
Expose a list of clients with open file handles in sysfs. This will be a basis for a top-like utility showing per-client and per- engine GPU load. Currently we only expose each client's pid and name under opaque numbered directories in /sys/class/drm/card0/clients/. For instance: /sys/class/drm/card0/clients/3/name: Xorg /sys/class/drm/card0/clients/3/pid: 5664 v2: Chris Wilson: * Enclose new members into dedicated structs. * Protect against failed sysfs registration. v3: * sysfs_attr_init. v4: * Fix for internal clients. v5: * Use cyclic ida for client id. (Chris) * Do not leak pid reference. (Chris) * Tidy code with some locals. v6: * Use xa_alloc_cyclic to simplify locking. (Chris) * No need to unregister individial sysfs files. (Chris) * Rebase on top of fpriv kref. * Track client closed status and reflect in sysfs. v7: * Make drm_client more standalone concept. v8: * Simplify sysfs show. (Chris) * Always track name and pid. v9: * Fix cyclic id assignment. v10: * No need for a mutex around xa_alloc_cyclic. * Refactor sysfs into own function. * Unregister sysfs before freeing pid and name. * Move clients setup into own function. v11: * Call clients init directly from driver init. (Chris) v12: * Do not fail client add on id wrap. (Maciej) v13 (Lucas): Rebase on upstream Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Aravind Iddamsetty <aravind.iddamsetty@intel.com> # v11 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
- Loading branch information
1 parent
3062794
commit 68ec040
Showing
7 changed files
with
311 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
// SPDX-License-Identifier: MIT | ||
/* | ||
* Copyright © 2020 Intel Corporation | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/slab.h> | ||
#include <linux/types.h> | ||
|
||
#include "i915_drm_client.h" | ||
#include "i915_gem.h" | ||
#include "i915_utils.h" | ||
|
||
void i915_drm_clients_init(struct i915_drm_clients *clients, | ||
struct drm_i915_private *i915) | ||
{ | ||
clients->i915 = i915; | ||
|
||
clients->next_id = 0; | ||
xa_init_flags(&clients->xarray, XA_FLAGS_ALLOC); | ||
} | ||
|
||
static ssize_t | ||
show_client_name(struct device *kdev, struct device_attribute *attr, char *buf) | ||
{ | ||
struct i915_drm_client *client = | ||
container_of(attr, typeof(*client), attr.name); | ||
|
||
return sysfs_emit(buf, | ||
READ_ONCE(client->closed) ? "<%s>\n" : "%s\n", | ||
client->name); | ||
} | ||
|
||
static ssize_t | ||
show_client_pid(struct device *kdev, struct device_attribute *attr, char *buf) | ||
{ | ||
struct i915_drm_client *client = | ||
container_of(attr, typeof(*client), attr.pid); | ||
|
||
return sysfs_emit(buf, | ||
READ_ONCE(client->closed) ? "<%u>\n" : "%u\n", | ||
pid_nr(client->pid)); | ||
} | ||
|
||
static int __client_register_sysfs(struct i915_drm_client *client) | ||
{ | ||
const struct { | ||
const char *name; | ||
struct device_attribute *attr; | ||
ssize_t (*show)(struct device *dev, | ||
struct device_attribute *attr, | ||
char *buf); | ||
} files[] = { | ||
{ "name", &client->attr.name, show_client_name }, | ||
{ "pid", &client->attr.pid, show_client_pid }, | ||
}; | ||
unsigned int i; | ||
char buf[16]; | ||
int ret; | ||
|
||
ret = scnprintf(buf, sizeof(buf), "%u", client->id); | ||
if (ret == sizeof(buf)) | ||
return -EINVAL; | ||
|
||
client->root = kobject_create_and_add(buf, client->clients->root); | ||
if (!client->root) | ||
return -ENOMEM; | ||
|
||
for (i = 0; i < ARRAY_SIZE(files); i++) { | ||
struct device_attribute *attr = files[i].attr; | ||
|
||
sysfs_attr_init(&attr->attr); | ||
|
||
attr->attr.name = files[i].name; | ||
attr->attr.mode = 0444; | ||
attr->show = files[i].show; | ||
|
||
ret = sysfs_create_file(client->root, &attr->attr); | ||
if (ret) | ||
break; | ||
} | ||
|
||
if (ret) | ||
kobject_put(client->root); | ||
|
||
return ret; | ||
} | ||
|
||
static void __client_unregister_sysfs(struct i915_drm_client *client) | ||
{ | ||
kobject_put(fetch_and_zero(&client->root)); | ||
} | ||
|
||
static int | ||
__i915_drm_client_register(struct i915_drm_client *client, | ||
struct task_struct *task) | ||
{ | ||
struct i915_drm_clients *clients = client->clients; | ||
char *name; | ||
int ret; | ||
|
||
name = kstrdup(task->comm, GFP_KERNEL); | ||
if (!name) | ||
return -ENOMEM; | ||
|
||
client->pid = get_task_pid(task, PIDTYPE_PID); | ||
client->name = name; | ||
|
||
if (!clients->root) | ||
return 0; /* intel_fbdev_init registers a client before sysfs */ | ||
|
||
ret = __client_register_sysfs(client); | ||
if (ret) | ||
goto err_sysfs; | ||
|
||
return 0; | ||
|
||
err_sysfs: | ||
put_pid(client->pid); | ||
kfree(client->name); | ||
|
||
return ret; | ||
} | ||
|
||
static void __i915_drm_client_unregister(struct i915_drm_client *client) | ||
{ | ||
__client_unregister_sysfs(client); | ||
|
||
put_pid(fetch_and_zero(&client->pid)); | ||
kfree(fetch_and_zero(&client->name)); | ||
} | ||
|
||
static void __rcu_i915_drm_client_free(struct work_struct *wrk) | ||
{ | ||
struct i915_drm_client *client = | ||
container_of(wrk, typeof(*client), rcu.work); | ||
|
||
__i915_drm_client_unregister(client); | ||
|
||
xa_erase(&client->clients->xarray, client->id); | ||
kfree(client); | ||
} | ||
|
||
struct i915_drm_client * | ||
i915_drm_client_add(struct i915_drm_clients *clients, struct task_struct *task) | ||
{ | ||
struct i915_drm_client *client; | ||
int ret; | ||
|
||
client = kzalloc(sizeof(*client), GFP_KERNEL); | ||
if (!client) | ||
return ERR_PTR(-ENOMEM); | ||
|
||
kref_init(&client->kref); | ||
client->clients = clients; | ||
INIT_RCU_WORK(&client->rcu, __rcu_i915_drm_client_free); | ||
|
||
ret = xa_alloc_cyclic(&clients->xarray, &client->id, client, | ||
xa_limit_32b, &clients->next_id, GFP_KERNEL); | ||
if (ret < 0) | ||
goto err_id; | ||
|
||
ret = __i915_drm_client_register(client, task); | ||
if (ret) | ||
goto err_register; | ||
|
||
return client; | ||
|
||
err_register: | ||
xa_erase(&clients->xarray, client->id); | ||
err_id: | ||
kfree(client); | ||
|
||
return ERR_PTR(ret); | ||
} | ||
|
||
void __i915_drm_client_free(struct kref *kref) | ||
{ | ||
struct i915_drm_client *client = | ||
container_of(kref, typeof(*client), kref); | ||
|
||
queue_rcu_work(system_wq, &client->rcu); | ||
} | ||
|
||
void i915_drm_client_close(struct i915_drm_client *client) | ||
{ | ||
GEM_BUG_ON(READ_ONCE(client->closed)); | ||
WRITE_ONCE(client->closed, true); | ||
i915_drm_client_put(client); | ||
} | ||
|
||
void i915_drm_clients_fini(struct i915_drm_clients *clients) | ||
{ | ||
while (!xa_empty(&clients->xarray)) { | ||
rcu_barrier(); | ||
flush_workqueue(system_wq); | ||
} | ||
|
||
xa_destroy(&clients->xarray); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* SPDX-License-Identifier: MIT */ | ||
/* | ||
* Copyright © 2020 Intel Corporation | ||
*/ | ||
|
||
#ifndef __I915_DRM_CLIENT_H__ | ||
#define __I915_DRM_CLIENT_H__ | ||
|
||
#include <linux/device.h> | ||
#include <linux/kobject.h> | ||
#include <linux/kref.h> | ||
#include <linux/pid.h> | ||
#include <linux/rcupdate.h> | ||
#include <linux/sched.h> | ||
#include <linux/xarray.h> | ||
|
||
struct drm_i915_private; | ||
|
||
struct i915_drm_clients { | ||
struct drm_i915_private *i915; | ||
|
||
struct xarray xarray; | ||
u32 next_id; | ||
|
||
struct kobject *root; | ||
}; | ||
|
||
struct i915_drm_client { | ||
struct kref kref; | ||
|
||
struct rcu_work rcu; | ||
|
||
unsigned int id; | ||
struct pid *pid; | ||
char *name; | ||
bool closed; | ||
|
||
struct i915_drm_clients *clients; | ||
|
||
struct kobject *root; | ||
struct { | ||
struct device_attribute pid; | ||
struct device_attribute name; | ||
} attr; | ||
}; | ||
|
||
void i915_drm_clients_init(struct i915_drm_clients *clients, | ||
struct drm_i915_private *i915); | ||
|
||
static inline struct i915_drm_client * | ||
i915_drm_client_get(struct i915_drm_client *client) | ||
{ | ||
kref_get(&client->kref); | ||
return client; | ||
} | ||
|
||
void __i915_drm_client_free(struct kref *kref); | ||
|
||
static inline void i915_drm_client_put(struct i915_drm_client *client) | ||
{ | ||
kref_put(&client->kref, __i915_drm_client_free); | ||
} | ||
|
||
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); | ||
|
||
void i915_drm_clients_fini(struct i915_drm_clients *clients); | ||
|
||
#endif /* !__I915_DRM_CLIENT_H__ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.