From: Matt Roper <matthew.d.roper@intel.com>
To: dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org,
cgroups@vger.kernel.org
Cc: Tejun Heo <tj@kernel.org>
Subject: [PATCH RFC v2 1/7] cgroup: Allow drivers to store data associated with a cgroup
Date: Thu, 1 Feb 2018 11:53:09 -0800 [thread overview]
Message-ID: <20180201195315.4956-2-matthew.d.roper@intel.com> (raw)
In-Reply-To: <20180201195315.4956-1-matthew.d.roper@intel.com>
There are cases where drivers need to adjust behavior or control
device-specific resources according to the type of clients (processes)
submitting requests. Linux cgroups are a natural fit for this type of
resource control and policy management, so we need a way for drivers to
associate their own driver-specific and device-specific data with
individual cgroups.
This is different than the cgroup controller support that exists today
in several important ways:
* Drivers may be built as modules (and unloaded/reloaded) which is not
something cgroup controllers support today.
* Drivers may wish to provide their own interface to allow userspace to
adjust driver-specific settings (e.g., via a driver ioctl rather than
via the kernfs filesystem).
* A single driver may be managing multiple devices and wish to maintain
different driver-specific cgroup data for each.
To use this mechanism, drivers should call cgroup_driver_init() to
register themselves and provide provide handler functions for allocating
driver-specific data structures; this call will return a handle that can
be used to lookup the driver-specific data associated with the device.
Drivers managing multiple devices that wish to track separate data for
each device may register themselves multiple times (e.g., a graphics
driver might call cgroup_driver_init() for each drm_device it manages).
At runtime, drivers may call cgroup_driver_get_data() to fetch the
driver-specific data associated with a cgroup. The driver-specific data
(which should be a driver-defined subclass of 'struct
cgroup_driver_data') will be allocated if one doesn't already exist.
Management of driver-specific data by the cgroups framework is protected
by cgroup_mutex, but drivers are responsible for performing their own
synchronization on the per-cgroup data they receive, if necessary. Note
that driver-specific data for a cgroup will only be allocated if/when
the driver first requests data for that cgroup. The driver data will
also be automatically destroyed if the cgroup it belongs to is removed.
Finally, drivers should cgroup_driver_release() on driver unload to
destroy all of their driver-specific data.
Note that technically these interfaces aren't restricted to drivers
(other non-driver parts of the kernel could make use of them as well).
I expect drivers to be the primary consumers of this interface and
couldn't think of a more appropriate generic name (the term "subsystem"
would probably be more accurate, but that's already used by cgroup
controllers).
Cc: Tejun Heo <tj@kernel.org>
Cc: cgroups@vger.kernel.org
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
include/linux/cgroup-defs.h | 37 ++++++++++++
include/linux/cgroup.h | 27 +++++++++
init/Kconfig | 4 ++
kernel/cgroup/Makefile | 1 +
kernel/cgroup/cgroup.c | 1 +
kernel/cgroup/cgroup_driver.c | 130 ++++++++++++++++++++++++++++++++++++++++++
6 files changed, 200 insertions(+)
create mode 100644 kernel/cgroup/cgroup_driver.c
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index 8b7fd8eeccee..5728e3afc95f 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -8,6 +8,7 @@
#ifndef _LINUX_CGROUP_DEFS_H
#define _LINUX_CGROUP_DEFS_H
+#include <linux/hashtable.h>
#include <linux/limits.h>
#include <linux/list.h>
#include <linux/idr.h>
@@ -27,6 +28,7 @@ struct cgroup;
struct cgroup_root;
struct cgroup_subsys;
struct cgroup_taskset;
+struct cgroup_driver;
struct kernfs_node;
struct kernfs_ops;
struct kernfs_open_file;
@@ -307,6 +309,22 @@ struct cgroup_stat {
struct prev_cputime prev_cputime;
};
+/*
+ * Driver-specific cgroup data. Drivers should subclass this structure with
+ * their own fields for data that should be stored alongside individual
+ * cgroups.
+ */
+struct cgroup_driver_data {
+ /* Driver this data structure is associated with */
+ struct cgroup_driver *drv;
+
+ /* Node in cgroup's data hashtable */
+ struct hlist_node cgroupnode;
+
+ /* Node in driver's data list; used to cleanup on driver unload */
+ struct list_head drivernode;
+};
+
struct cgroup {
/* self css with NULL ->ss, points back to this cgroup */
struct cgroup_subsys_state self;
@@ -427,6 +445,12 @@ struct cgroup {
/* used to store eBPF programs */
struct cgroup_bpf bpf;
+ /*
+ * list of cgroup_driver_data structures; used to manage
+ * driver-specific data associated with individual cgroups
+ */
+ DECLARE_HASHTABLE(driver_data, 4);
+
/* ids of the ancestors at each level including self */
int ancestor_ids[];
};
@@ -662,6 +686,19 @@ struct cgroup_subsys {
unsigned int depends_on;
};
+/* Function table for handling driver-specific cgroup data */
+struct cgroup_driver_funcs {
+ /* Allocates driver-specific data for a cgroup */
+ struct cgroup_driver_data *(*alloc_data)(struct cgroup_driver *drv);
+
+ /*
+ * Frees a driver-specific datastructure.
+ *
+ * This function is optional; if NULL, data will be kvfree()'d.
+ */
+ void (*free_data)(struct cgroup_driver_data *data);
+};
+
extern struct percpu_rw_semaphore cgroup_threadgroup_rwsem;
/**
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 473e0c0abb86..0ba1374122c7 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -833,4 +833,31 @@ static inline void put_cgroup_ns(struct cgroup_namespace *ns)
free_cgroup_ns(ns);
}
+struct cgroup_driver_funcs;
+
+#ifdef CONFIG_CGROUP_DRIVER
+
+struct cgroup_driver *cgroup_driver_init(struct cgroup_driver_funcs *funcs);
+void cgroup_driver_release(struct cgroup_driver *drv);
+struct cgroup_driver_data * cgroup_driver_get_data(struct cgroup_driver *drv,
+ struct cgroup *cgrp,
+ bool *is_new);
+
+#else /* !CONFIG_CGROUP_DRIVER */
+
+static inline struct cgroup_driver *
+cgroup_driver_init(struct cgroup_driver_funcs *funcs) {
+ return NULL;
+}
+static inline void cgroup_driver_release(struct cgroup_driver *drv) {}
+static inline struct cgroup_driver_data *
+cgroup_driver_get_data(struct cgroup_driver *drv,
+ struct cgroup *cgrp,
+ bool *is_new)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+#endif /* !CONFIG_CGROUP_DRIVER */
+
#endif /* _LINUX_CGROUP_H */
diff --git a/init/Kconfig b/init/Kconfig
index a9a2e2c86671..5f942ed8d248 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -873,6 +873,10 @@ config SOCK_CGROUP_DATA
bool
default n
+config CGROUP_DRIVER
+ bool
+ default n
+
endif # CGROUPS
menuconfig NAMESPACES
diff --git a/kernel/cgroup/Makefile b/kernel/cgroup/Makefile
index 2be89a003185..669ef66da3a2 100644
--- a/kernel/cgroup/Makefile
+++ b/kernel/cgroup/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_CGROUP_PIDS) += pids.o
obj-$(CONFIG_CGROUP_RDMA) += rdma.o
obj-$(CONFIG_CPUSETS) += cpuset.o
obj-$(CONFIG_CGROUP_DEBUG) += debug.o
+obj-$(CONFIG_CGROUP_DRIVER) += cgroup_driver.o
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 7e4c44538119..b926713a1860 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -1838,6 +1838,7 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
INIT_LIST_HEAD(&cgrp->self.children);
INIT_LIST_HEAD(&cgrp->cset_links);
INIT_LIST_HEAD(&cgrp->pidlists);
+ hash_init(cgrp->driver_data);
mutex_init(&cgrp->pidlist_mutex);
cgrp->self.cgroup = cgrp;
cgrp->self.flags |= CSS_ONLINE;
diff --git a/kernel/cgroup/cgroup_driver.c b/kernel/cgroup/cgroup_driver.c
new file mode 100644
index 000000000000..0d893395dc7b
--- /dev/null
+++ b/kernel/cgroup/cgroup_driver.c
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include "cgroup-internal.h"
+
+#include <linux/hashtable.h>
+#include <linux/mm.h>
+
+/*
+ * General data structure returned by cgroup_driver_init() and used as a
+ * hashtable key to lookup driver-specific data.
+ */
+struct cgroup_driver {
+ /* Functions this driver uses to manage its data */
+ struct cgroup_driver_funcs *funcs;
+
+ /*
+ * List of driver-specific data structures that need to be cleaned up
+ * if driver is unloaded.
+ */
+ struct list_head datalist;
+};
+
+/**
+ * cgroup_driver_init - initialize cgroups driver-specific data management
+ * @funcs: driver-specific data management functions
+ *
+ * Drivers that wish to store driver-specific data alongside individual
+ * cgroups should call this and provide a function table of driver-specific
+ * data operations.
+ *
+ * RETURNS:
+ * An instance of 'struct cgroup_driver' that will be used to help manage
+ * data storage for the invoking driver. If an error occurs, a negative
+ * error code will be returned. If CONFIG_CGROUP_DRIVER is not set, NULL
+ * will be returned.
+ */
+struct cgroup_driver *
+cgroup_driver_init(struct cgroup_driver_funcs *funcs)
+{
+ struct cgroup_driver *drv;
+
+ drv = kzalloc(sizeof *drv, GFP_KERNEL);
+ if (!drv)
+ return ERR_PTR(-ENOMEM);
+
+ drv->funcs = funcs;
+ INIT_LIST_HEAD(&drv->datalist);
+
+ return drv;
+}
+EXPORT_SYMBOL(cgroup_driver_init);
+
+/**
+ * cgroup_driver_release - release all driver-specific data for a driver
+ * @drv: driver to release data for
+ *
+ * Drivers storing their own data alongside cgroups should call this function
+ * when unloaded to ensure all driver-specific data is released.
+ */
+void
+cgroup_driver_release(struct cgroup_driver *drv)
+{
+ struct cgroup_driver_data *data, *tmp;
+
+ mutex_lock(&cgroup_mutex);
+ list_for_each_entry_safe(data, tmp, &drv->datalist, drivernode) {
+ hlist_del(&data->cgroupnode);
+ list_del(&data->drivernode);
+ if (drv->funcs && drv->funcs->free_data)
+ drv->funcs->free_data(data);
+ else
+ kvfree(data);
+ }
+ mutex_unlock(&cgroup_mutex);
+
+ kfree(drv);
+}
+EXPORT_SYMBOL(cgroup_driver_release);
+
+/**
+ * cgroup_driver_get_data - retrieve/allocate driver-specific data for a cgroup
+ * @drv: driver wishing to fetch data
+ * @cgrp: cgroup to fetch data for
+ * @is_new: will be set to true if a new structure is allocated
+ *
+ * Fetches the driver-specific data structure associated with a cgroup, if one
+ * has previously been set. If no driver data has been associated with this
+ * cgroup, a new driver-specific data structure is allocated and returned.
+ *
+ * RETURNS:
+ * The driver data previously associated with this cgroup, or a fresh data
+ * structure allocated via drv->funcs->alloc_data() if no data has previously
+ * been associated. On error, a negative error code is returned.
+ */
+struct cgroup_driver_data *
+cgroup_driver_get_data(struct cgroup_driver *drv,
+ struct cgroup *cgrp,
+ bool *is_new)
+{
+ struct cgroup_driver_data *data;
+
+ /* We only support driver-specific data on the cgroup-v2 hierarchy */
+ if (!cgroup_on_dfl(cgrp))
+ return ERR_PTR(-EINVAL);
+
+ mutex_lock(&cgroup_mutex);
+
+ if (is_new)
+ *is_new = false;
+ hash_for_each_possible(cgrp->driver_data, data, cgroupnode,
+ (unsigned long)drv)
+ if (data->drv == drv)
+ goto out;
+
+ /* First time for this cgroup; alloc and store new data */
+ data = drv->funcs->alloc_data(drv);
+ if (!IS_ERR(data)) {
+ data->drv = drv;
+ hash_add(cgrp->driver_data, &data->cgroupnode,
+ (unsigned long)drv);
+ list_add(&data->drivernode, &drv->datalist);
+ if (is_new)
+ *is_new = true;
+ }
+
+out:
+ mutex_unlock(&cgroup_mutex);
+ return data;
+}
+EXPORT_SYMBOL(cgroup_driver_get_data);
--
2.14.3
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
next prev parent reply other threads:[~2018-02-01 19:53 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-02-01 19:53 [PATCH RFC v2 0/7] DRM management via cgroups Matt Roper
2018-02-01 19:53 ` Matt Roper [this message]
[not found] ` <20180201195315.4956-2-matthew.d.roper-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2018-02-07 22:11 ` [PATCH RFC v2 1/7] cgroup: Allow drivers to store data associated with a cgroup Tejun Heo
2018-02-01 19:53 ` [PATCH RFC v2 2/7] kernfs: Export kernfs_get_inode Matt Roper
[not found] ` <20180201195315.4956-3-matthew.d.roper-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2018-02-01 20:04 ` [Intel-gfx] " Chris Wilson
2018-02-01 19:53 ` [PATCH RFC v2 3/7] cgroup: Add interface to allow drivers to lookup process cgroup membership Matt Roper
2018-02-01 20:49 ` [Intel-gfx] " Chris Wilson
2018-02-01 21:25 ` Matt Roper
2018-02-07 22:42 ` Tejun Heo
2018-02-01 19:53 ` [PATCH RFC v2 4/7] drm: Add helper to obtain cgroup of drm_file's owning process Matt Roper
[not found] ` <20180201195315.4956-5-matthew.d.roper-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2018-02-01 20:10 ` [Intel-gfx] " Chris Wilson
2018-02-01 19:53 ` [PATCH RFC v2 5/7] drm/i915: cgroup integration Matt Roper
[not found] ` <20180201195315.4956-6-matthew.d.roper-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2018-02-01 20:11 ` Chris Wilson
2018-02-01 20:12 ` Chris Wilson
2018-02-01 20:15 ` Chris Wilson
[not found] ` <20180201195315.4956-1-matthew.d.roper-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2018-02-01 19:53 ` [PATCH RFC v2 6/7] drm/i915: Introduce 'priority offset' for GPU contexts Matt Roper
[not found] ` <20180201195315.4956-7-matthew.d.roper-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2018-02-01 20:22 ` Chris Wilson
2018-02-01 19:53 ` [PATCH RFC v2 7/7] drm/i915: Add context priority & priority offset to debugfs Matt Roper
[not found] ` <20180201195315.4956-8-matthew.d.roper-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2018-02-01 20:24 ` Chris Wilson
2018-02-01 19:56 ` [IGT PATCH RFC] tools: Introduce intel_cgroup tool Matt Roper
2018-02-01 20:27 ` [Intel-gfx] " Chris Wilson
[not found] ` <151751685381.28099.5351495854502256843-M6iVdVfohj6unts5RBS2dVaTQe2KTcn/@public.gmane.org>
2018-02-01 23:14 ` Matt Roper
2018-02-07 21:50 ` Tejun Heo
2018-02-07 21:54 ` Tejun Heo
2018-02-01 20:14 ` ✓ Fi.CI.BAT: success for DRM management via cgroups (rev2) Patchwork
2018-02-01 20:15 ` ✗ Fi.CI.BAT: failure for tools: Introduce intel_cgroup tool Patchwork
2018-02-01 23:52 ` ✗ Fi.CI.IGT: failure for DRM management via cgroups (rev2) Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180201195315.4956-2-matthew.d.roper@intel.com \
--to=matthew.d.roper@intel.com \
--cc=cgroups@vger.kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-gfx@lists.freedesktop.org \
--cc=tj@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox