Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0e8a139 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull cgroup updates from Tejun Heo:

 - xattr support added.  The implementation is shared with tmpfs.  The
   usage is restricted and intended to be used to manage per-cgroup
   metadata by system software.  tmpfs changes are routed through this
   branch with Hugh's permission.

 - cgroup subsystem ID handling simplified.

* 'for-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup:
  cgroup: Define CGROUP_SUBSYS_COUNT according the configuration
  cgroup: Assign subsystem IDs during compile time
  cgroup: Do not depend on a given order when populating the subsys array
  cgroup: Wrap subsystem selection macro
  cgroup: Remove CGROUP_BUILTIN_SUBSYS_COUNT
  cgroup: net_prio: Do not define task_netpioidx() when not selected
  cgroup: net_cls: Do not define task_cls_classid() when not selected
  cgroup: net_cls: Move sock_update_classid() declaration to cls_cgroup.h
  cgroup: trivial fixes for Documentation/cgroups/cgroups.txt
  xattr: mark variable as uninitialized to make both gcc and smatch happy
  fs: add missing documentation to simple_xattr functions
  cgroup: add documentation on extended attributes usage
  cgroup: rename subsys_bits to subsys_mask
  cgroup: add xattr support
  cgroup: revise how we re-populate root directory
  xattr: extract simple_xattr code from tmpfs
parents 033d9959 a6f00298
Loading
Loading
Loading
Loading
+56 −36
Original line number Original line Diff line number Diff line
@@ -29,7 +29,8 @@ CONTENTS:
  3.1 Overview
  3.1 Overview
  3.2 Synchronization
  3.2 Synchronization
  3.3 Subsystem API
  3.3 Subsystem API
4. Questions
4. Extended attributes usage
5. Questions


1. Control Groups
1. Control Groups
=================
=================
@@ -62,9 +63,9 @@ an instance of the cgroup virtual filesystem associated with it.
At any one time there may be multiple active hierarchies of task
At any one time there may be multiple active hierarchies of task
cgroups. Each hierarchy is a partition of all tasks in the system.
cgroups. Each hierarchy is a partition of all tasks in the system.


User level code may create and destroy cgroups by name in an
User-level code may create and destroy cgroups by name in an
instance of the cgroup virtual file system, specify and query to
instance of the cgroup virtual file system, specify and query to
which cgroup a task is assigned, and list the task pids assigned to
which cgroup a task is assigned, and list the task PIDs assigned to
a cgroup. Those creations and assignments only affect the hierarchy
a cgroup. Those creations and assignments only affect the hierarchy
associated with that instance of the cgroup file system.
associated with that instance of the cgroup file system.


@@ -72,7 +73,7 @@ On their own, the only use for cgroups is for simple job
tracking. The intention is that other subsystems hook into the generic
tracking. The intention is that other subsystems hook into the generic
cgroup support to provide new attributes for cgroups, such as
cgroup support to provide new attributes for cgroups, such as
accounting/limiting the resources which processes in a cgroup can
accounting/limiting the resources which processes in a cgroup can
access. For example, cpusets (see Documentation/cgroups/cpusets.txt) allows
access. For example, cpusets (see Documentation/cgroups/cpusets.txt) allow
you to associate a set of CPUs and a set of memory nodes with the
you to associate a set of CPUs and a set of memory nodes with the
tasks in each cgroup.
tasks in each cgroup.


@@ -80,11 +81,11 @@ tasks in each cgroup.
----------------------------
----------------------------


There are multiple efforts to provide process aggregations in the
There are multiple efforts to provide process aggregations in the
Linux kernel, mainly for resource tracking purposes. Such efforts
Linux kernel, mainly for resource-tracking purposes. Such efforts
include cpusets, CKRM/ResGroups, UserBeanCounters, and virtual server
include cpusets, CKRM/ResGroups, UserBeanCounters, and virtual server
namespaces. These all require the basic notion of a
namespaces. These all require the basic notion of a
grouping/partitioning of processes, with newly forked processes ending
grouping/partitioning of processes, with newly forked processes ending
in the same group (cgroup) as their parent process.
up in the same group (cgroup) as their parent process.


The kernel cgroup patch provides the minimum essential kernel
The kernel cgroup patch provides the minimum essential kernel
mechanisms required to efficiently implement such groups. It has
mechanisms required to efficiently implement such groups. It has
@@ -127,14 +128,14 @@ following lines:
                               / \
                               / \
               Professors (15%)  students (5%)
               Professors (15%)  students (5%)


Browsers like Firefox/Lynx go into the WWW network class, while (k)nfsd go
Browsers like Firefox/Lynx go into the WWW network class, while (k)nfsd goes
into NFS network class.
into the NFS network class.


At the same time Firefox/Lynx will share an appropriate CPU/Memory class
At the same time Firefox/Lynx will share an appropriate CPU/Memory class
depending on who launched it (prof/student).
depending on who launched it (prof/student).


With the ability to classify tasks differently for different resources
With the ability to classify tasks differently for different resources
(by putting those resource subsystems in different hierarchies) then
(by putting those resource subsystems in different hierarchies),
the admin can easily set up a script which receives exec notifications
the admin can easily set up a script which receives exec notifications
and depending on who is launching the browser he can
and depending on who is launching the browser he can


@@ -145,19 +146,19 @@ a separate cgroup for every browser launched and associate it with
appropriate network and other resource class.  This may lead to
appropriate network and other resource class.  This may lead to
proliferation of such cgroups.
proliferation of such cgroups.


Also lets say that the administrator would like to give enhanced network
Also let's say that the administrator would like to give enhanced network
access temporarily to a student's browser (since it is night and the user
access temporarily to a student's browser (since it is night and the user
wants to do online gaming :))  OR give one of the students simulation
wants to do online gaming :))  OR give one of the student's simulation
apps enhanced CPU power,
apps enhanced CPU power.


With ability to write pids directly to resource classes, it's just a
With ability to write PIDs directly to resource classes, it's just a
matter of:
matter of:


       # echo pid > /sys/fs/cgroup/network/<new_class>/tasks
       # echo pid > /sys/fs/cgroup/network/<new_class>/tasks
       (after some time)
       (after some time)
       # echo pid > /sys/fs/cgroup/network/<orig_class>/tasks
       # echo pid > /sys/fs/cgroup/network/<orig_class>/tasks


Without this ability, he would have to split the cgroup into
Without this ability, the administrator would have to split the cgroup into
multiple separate ones and then associate the new cgroups with the
multiple separate ones and then associate the new cgroups with the
new resource classes.
new resource classes.


@@ -187,17 +188,17 @@ Control Groups extends the kernel as follows:
 - A cgroup hierarchy filesystem can be mounted for browsing and
 - A cgroup hierarchy filesystem can be mounted for browsing and
   manipulation from user space.
   manipulation from user space.


 - You can list all the tasks (by pid) attached to any cgroup.
 - You can list all the tasks (by PID) attached to any cgroup.


The implementation of cgroups requires a few, simple hooks
The implementation of cgroups requires a few, simple hooks
into the rest of the kernel, none in performance critical paths:
into the rest of the kernel, none in performance-critical paths:


 - in init/main.c, to initialize the root cgroups and initial
 - in init/main.c, to initialize the root cgroups and initial
   css_set at system boot.
   css_set at system boot.


 - in fork and exit, to attach and detach a task from its css_set.
 - in fork and exit, to attach and detach a task from its css_set.


In addition a new file system, of type "cgroup" may be mounted, to
In addition, a new file system of type "cgroup" may be mounted, to
enable browsing and modifying the cgroups presently known to the
enable browsing and modifying the cgroups presently known to the
kernel.  When mounting a cgroup hierarchy, you may specify a
kernel.  When mounting a cgroup hierarchy, you may specify a
comma-separated list of subsystems to mount as the filesystem mount
comma-separated list of subsystems to mount as the filesystem mount
@@ -230,13 +231,13 @@ as the path relative to the root of the cgroup file system.
Each cgroup is represented by a directory in the cgroup file system
Each cgroup is represented by a directory in the cgroup file system
containing the following files describing that cgroup:
containing the following files describing that cgroup:


 - tasks: list of tasks (by pid) attached to that cgroup.  This list
 - tasks: list of tasks (by PID) attached to that cgroup.  This list
   is not guaranteed to be sorted.  Writing a thread id into this file
   is not guaranteed to be sorted.  Writing a thread ID into this file
   moves the thread into this cgroup.
   moves the thread into this cgroup.
 - cgroup.procs: list of tgids in the cgroup.  This list is not
 - cgroup.procs: list of thread group IDs in the cgroup.  This list is
   guaranteed to be sorted or free of duplicate tgids, and userspace
   not guaranteed to be sorted or free of duplicate TGIDs, and userspace
   should sort/uniquify the list if this property is required.
   should sort/uniquify the list if this property is required.
   Writing a thread group id into this file moves all threads in that
   Writing a thread group ID into this file moves all threads in that
   group into this cgroup.
   group into this cgroup.
 - notify_on_release flag: run the release agent on exit?
 - notify_on_release flag: run the release agent on exit?
 - release_agent: the path to use for release notifications (this file
 - release_agent: the path to use for release notifications (this file
@@ -261,7 +262,7 @@ cgroup file system directories.


When a task is moved from one cgroup to another, it gets a new
When a task is moved from one cgroup to another, it gets a new
css_set pointer - if there's an already existing css_set with the
css_set pointer - if there's an already existing css_set with the
desired collection of cgroups then that group is reused, else a new
desired collection of cgroups then that group is reused, otherwise a new
css_set is allocated. The appropriate existing css_set is located by
css_set is allocated. The appropriate existing css_set is located by
looking into a hash table.
looking into a hash table.


@@ -292,7 +293,7 @@ file system) of the abandoned cgroup. This enables automatic
removal of abandoned cgroups.  The default value of
removal of abandoned cgroups.  The default value of
notify_on_release in the root cgroup at system boot is disabled
notify_on_release in the root cgroup at system boot is disabled
(0).  The default value of other cgroups at creation is the current
(0).  The default value of other cgroups at creation is the current
value of their parents notify_on_release setting. The default value of
value of their parents' notify_on_release settings. The default value of
a cgroup hierarchy's release_agent path is empty.
a cgroup hierarchy's release_agent path is empty.


1.5 What does clone_children do ?
1.5 What does clone_children do ?
@@ -316,7 +317,7 @@ the "cpuset" cgroup subsystem, the steps are something like:
 4) Create the new cgroup by doing mkdir's and write's (or echo's) in
 4) Create the new cgroup by doing mkdir's and write's (or echo's) in
    the /sys/fs/cgroup virtual file system.
    the /sys/fs/cgroup virtual file system.
 5) Start a task that will be the "founding father" of the new job.
 5) Start a task that will be the "founding father" of the new job.
 6) Attach that task to the new cgroup by writing its pid to the
 6) Attach that task to the new cgroup by writing its PID to the
    /sys/fs/cgroup/cpuset/tasks file for that cgroup.
    /sys/fs/cgroup/cpuset/tasks file for that cgroup.
 7) fork, exec or clone the job tasks from this founding father task.
 7) fork, exec or clone the job tasks from this founding father task.


@@ -344,7 +345,7 @@ and then start a subshell 'sh' in that cgroup:
2.1 Basic Usage
2.1 Basic Usage
---------------
---------------


Creating, modifying, using the cgroups can be done through the cgroup
Creating, modifying, using cgroups can be done through the cgroup
virtual filesystem.
virtual filesystem.


To mount a cgroup hierarchy with all available subsystems, type:
To mount a cgroup hierarchy with all available subsystems, type:
@@ -441,7 +442,7 @@ You can attach the current shell task by echoing 0:
# echo 0 > tasks
# echo 0 > tasks


You can use the cgroup.procs file instead of the tasks file to move all
You can use the cgroup.procs file instead of the tasks file to move all
threads in a threadgroup at once. Echoing the pid of any task in a
threads in a threadgroup at once. Echoing the PID of any task in a
threadgroup to cgroup.procs causes all tasks in that threadgroup to be
threadgroup to cgroup.procs causes all tasks in that threadgroup to be
be attached to the cgroup. Writing 0 to cgroup.procs moves all tasks
be attached to the cgroup. Writing 0 to cgroup.procs moves all tasks
in the writing task's threadgroup.
in the writing task's threadgroup.
@@ -479,7 +480,7 @@ in /proc/mounts and /proc/<pid>/cgroups.
There is mechanism which allows to get notifications about changing
There is mechanism which allows to get notifications about changing
status of a cgroup.
status of a cgroup.


To register new notification handler you need:
To register a new notification handler you need to:
 - create a file descriptor for event notification using eventfd(2);
 - create a file descriptor for event notification using eventfd(2);
 - open a control file to be monitored (e.g. memory.usage_in_bytes);
 - open a control file to be monitored (e.g. memory.usage_in_bytes);
 - write "<event_fd> <control_fd> <args>" to cgroup.event_control.
 - write "<event_fd> <control_fd> <args>" to cgroup.event_control.
@@ -488,7 +489,7 @@ To register new notification handler you need:
eventfd will be woken up by control file implementation or when the
eventfd will be woken up by control file implementation or when the
cgroup is removed.
cgroup is removed.


To unregister notification handler just close eventfd.
To unregister a notification handler just close eventfd.


NOTE: Support of notifications should be implemented for the control
NOTE: Support of notifications should be implemented for the control
file. See documentation for the subsystem.
file. See documentation for the subsystem.
@@ -502,7 +503,7 @@ file. See documentation for the subsystem.
Each kernel subsystem that wants to hook into the generic cgroup
Each kernel subsystem that wants to hook into the generic cgroup
system needs to create a cgroup_subsys object. This contains
system needs to create a cgroup_subsys object. This contains
various methods, which are callbacks from the cgroup system, along
various methods, which are callbacks from the cgroup system, along
with a subsystem id which will be assigned by the cgroup system.
with a subsystem ID which will be assigned by the cgroup system.


Other fields in the cgroup_subsys object include:
Other fields in the cgroup_subsys object include:


@@ -516,7 +517,7 @@ Other fields in the cgroup_subsys object include:
  at system boot.
  at system boot.


Each cgroup object created by the system has an array of pointers,
Each cgroup object created by the system has an array of pointers,
indexed by subsystem id; this pointer is entirely managed by the
indexed by subsystem ID; this pointer is entirely managed by the
subsystem; the generic cgroup code will never touch this pointer.
subsystem; the generic cgroup code will never touch this pointer.


3.2 Synchronization
3.2 Synchronization
@@ -639,7 +640,7 @@ void post_clone(struct cgroup *cgrp)


Called during cgroup_create() to do any parameter
Called during cgroup_create() to do any parameter
initialization which might be required before a task could attach.  For
initialization which might be required before a task could attach.  For
example in cpusets, no task may attach before 'cpus' and 'mems' are set
example, in cpusets, no task may attach before 'cpus' and 'mems' are set
up.
up.


void bind(struct cgroup *root)
void bind(struct cgroup *root)
@@ -650,7 +651,26 @@ and root cgroup. Currently this will only involve movement between
the default hierarchy (which never has sub-cgroups) and a hierarchy
the default hierarchy (which never has sub-cgroups) and a hierarchy
that is being created/destroyed (and hence has no sub-cgroups).
that is being created/destroyed (and hence has no sub-cgroups).


4. Questions
4. Extended attribute usage
===========================

cgroup filesystem supports certain types of extended attributes in its
directories and files.  The current supported types are:
	- Trusted (XATTR_TRUSTED)
	- Security (XATTR_SECURITY)

Both require CAP_SYS_ADMIN capability to set.

Like in tmpfs, the extended attributes in cgroup filesystem are stored
using kernel memory and it's advised to keep the usage at minimum.  This
is the reason why user defined extended attributes are not supported, since
any user can do it and there's no limit in the value size.

The current known users for this feature are SELinux to limit cgroup usage
in containers and systemd for assorted meta data like main PID in a cgroup
(systemd creates a cgroup per service).

5. Questions
============
============


Q: what's up with this '/bin/echo' ?
Q: what's up with this '/bin/echo' ?
@@ -660,5 +680,5 @@ A: bash's builtin 'echo' command does not check calls to write() against


Q: When I attach processes, only the first of the line gets really attached !
Q: When I attach processes, only the first of the line gets really attached !
A: We can only return one error code per call to write(). So you should also
A: We can only return one error code per call to write(). So you should also
   put only ONE pid.
   put only ONE PID.
+1 −0
Original line number Original line Diff line number Diff line
@@ -68,6 +68,7 @@
#include <net/netns/generic.h>
#include <net/netns/generic.h>
#include <net/rtnetlink.h>
#include <net/rtnetlink.h>
#include <net/sock.h>
#include <net/sock.h>
#include <net/cls_cgroup.h>


#include <asm/uaccess.h>
#include <asm/uaccess.h>


+180 −0
Original line number Original line Diff line number Diff line
@@ -791,3 +791,183 @@ EXPORT_SYMBOL(generic_getxattr);
EXPORT_SYMBOL(generic_listxattr);
EXPORT_SYMBOL(generic_listxattr);
EXPORT_SYMBOL(generic_setxattr);
EXPORT_SYMBOL(generic_setxattr);
EXPORT_SYMBOL(generic_removexattr);
EXPORT_SYMBOL(generic_removexattr);

/*
 * Allocate new xattr and copy in the value; but leave the name to callers.
 */
struct simple_xattr *simple_xattr_alloc(const void *value, size_t size)
{
	struct simple_xattr *new_xattr;
	size_t len;

	/* wrap around? */
	len = sizeof(*new_xattr) + size;
	if (len <= sizeof(*new_xattr))
		return NULL;

	new_xattr = kmalloc(len, GFP_KERNEL);
	if (!new_xattr)
		return NULL;

	new_xattr->size = size;
	memcpy(new_xattr->value, value, size);
	return new_xattr;
}

/*
 * xattr GET operation for in-memory/pseudo filesystems
 */
int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
		     void *buffer, size_t size)
{
	struct simple_xattr *xattr;
	int ret = -ENODATA;

	spin_lock(&xattrs->lock);
	list_for_each_entry(xattr, &xattrs->head, list) {
		if (strcmp(name, xattr->name))
			continue;

		ret = xattr->size;
		if (buffer) {
			if (size < xattr->size)
				ret = -ERANGE;
			else
				memcpy(buffer, xattr->value, xattr->size);
		}
		break;
	}
	spin_unlock(&xattrs->lock);
	return ret;
}

static int __simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
			      const void *value, size_t size, int flags)
{
	struct simple_xattr *xattr;
	struct simple_xattr *uninitialized_var(new_xattr);
	int err = 0;

	/* value == NULL means remove */
	if (value) {
		new_xattr = simple_xattr_alloc(value, size);
		if (!new_xattr)
			return -ENOMEM;

		new_xattr->name = kstrdup(name, GFP_KERNEL);
		if (!new_xattr->name) {
			kfree(new_xattr);
			return -ENOMEM;
		}
	}

	spin_lock(&xattrs->lock);
	list_for_each_entry(xattr, &xattrs->head, list) {
		if (!strcmp(name, xattr->name)) {
			if (flags & XATTR_CREATE) {
				xattr = new_xattr;
				err = -EEXIST;
			} else if (new_xattr) {
				list_replace(&xattr->list, &new_xattr->list);
			} else {
				list_del(&xattr->list);
			}
			goto out;
		}
	}
	if (flags & XATTR_REPLACE) {
		xattr = new_xattr;
		err = -ENODATA;
	} else {
		list_add(&new_xattr->list, &xattrs->head);
		xattr = NULL;
	}
out:
	spin_unlock(&xattrs->lock);
	if (xattr) {
		kfree(xattr->name);
		kfree(xattr);
	}
	return err;

}

/**
 * simple_xattr_set - xattr SET operation for in-memory/pseudo filesystems
 * @xattrs: target simple_xattr list
 * @name: name of the new extended attribute
 * @value: value of the new xattr. If %NULL, will remove the attribute
 * @size: size of the new xattr
 * @flags: %XATTR_{CREATE|REPLACE}
 *
 * %XATTR_CREATE is set, the xattr shouldn't exist already; otherwise fails
 * with -EEXIST.  If %XATTR_REPLACE is set, the xattr should exist;
 * otherwise, fails with -ENODATA.
 *
 * Returns 0 on success, -errno on failure.
 */
int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
		     const void *value, size_t size, int flags)
{
	if (size == 0)
		value = ""; /* empty EA, do not remove */
	return __simple_xattr_set(xattrs, name, value, size, flags);
}

/*
 * xattr REMOVE operation for in-memory/pseudo filesystems
 */
int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name)
{
	return __simple_xattr_set(xattrs, name, NULL, 0, XATTR_REPLACE);
}

static bool xattr_is_trusted(const char *name)
{
	return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
}

/*
 * xattr LIST operation for in-memory/pseudo filesystems
 */
ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer,
			  size_t size)
{
	bool trusted = capable(CAP_SYS_ADMIN);
	struct simple_xattr *xattr;
	size_t used = 0;

	spin_lock(&xattrs->lock);
	list_for_each_entry(xattr, &xattrs->head, list) {
		size_t len;

		/* skip "trusted." attributes for unprivileged callers */
		if (!trusted && xattr_is_trusted(xattr->name))
			continue;

		len = strlen(xattr->name) + 1;
		used += len;
		if (buffer) {
			if (size < used) {
				used = -ERANGE;
				break;
			}
			memcpy(buffer, xattr->name, len);
			buffer += len;
		}
	}
	spin_unlock(&xattrs->lock);

	return used;
}

/*
 * Adds an extended attribute to the list
 */
void simple_xattr_list_add(struct simple_xattrs *xattrs,
			   struct simple_xattr *new_xattr)
{
	spin_lock(&xattrs->lock);
	list_add(&new_xattr->list, &xattrs->head);
	spin_unlock(&xattrs->lock);
}
+15 −10
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/rwsem.h>
#include <linux/rwsem.h>
#include <linux/idr.h>
#include <linux/idr.h>
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/xattr.h>


#ifdef CONFIG_CGROUPS
#ifdef CONFIG_CGROUPS


@@ -45,17 +46,13 @@ extern const struct file_operations proc_cgroup_operations;


/* Define the enumeration of all builtin cgroup subsystems */
/* Define the enumeration of all builtin cgroup subsystems */
#define SUBSYS(_x) _x ## _subsys_id,
#define SUBSYS(_x) _x ## _subsys_id,
#define IS_SUBSYS_ENABLED(option) IS_ENABLED(option)
enum cgroup_subsys_id {
enum cgroup_subsys_id {
#include <linux/cgroup_subsys.h>
#include <linux/cgroup_subsys.h>
	CGROUP_BUILTIN_SUBSYS_COUNT
	CGROUP_SUBSYS_COUNT,
};
};
#undef IS_SUBSYS_ENABLED
#undef SUBSYS
#undef SUBSYS
/*
 * This define indicates the maximum number of subsystems that can be loaded
 * at once. We limit to this many since cgroupfs_root has subsys_bits to keep
 * track of all of them.
 */
#define CGROUP_SUBSYS_COUNT (BITS_PER_BYTE*sizeof(unsigned long))


/* Per-subsystem/per-cgroup state maintained by the system. */
/* Per-subsystem/per-cgroup state maintained by the system. */
struct cgroup_subsys_state {
struct cgroup_subsys_state {
@@ -216,6 +213,9 @@ struct cgroup {
	/* List of events which userspace want to receive */
	/* List of events which userspace want to receive */
	struct list_head event_list;
	struct list_head event_list;
	spinlock_t event_list_lock;
	spinlock_t event_list_lock;

	/* directory xattrs */
	struct simple_xattrs xattrs;
};
};


/*
/*
@@ -309,6 +309,9 @@ struct cftype {
	/* CFTYPE_* flags */
	/* CFTYPE_* flags */
	unsigned int flags;
	unsigned int flags;


	/* file xattrs */
	struct simple_xattrs xattrs;

	int (*open)(struct inode *inode, struct file *file);
	int (*open)(struct inode *inode, struct file *file);
	ssize_t (*read)(struct cgroup *cgrp, struct cftype *cft,
	ssize_t (*read)(struct cgroup *cgrp, struct cftype *cft,
			struct file *file,
			struct file *file,
@@ -394,7 +397,7 @@ struct cftype {
 */
 */
struct cftype_set {
struct cftype_set {
	struct list_head		node;	/* chained at subsys->cftsets */
	struct list_head		node;	/* chained at subsys->cftsets */
	const struct cftype		*cfts;
	struct cftype			*cfts;
};
};


struct cgroup_scanner {
struct cgroup_scanner {
@@ -406,8 +409,8 @@ struct cgroup_scanner {
	void *data;
	void *data;
};
};


int cgroup_add_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts);
int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
int cgroup_rm_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts);
int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);


int cgroup_is_removed(const struct cgroup *cgrp);
int cgroup_is_removed(const struct cgroup *cgrp);


@@ -521,7 +524,9 @@ struct cgroup_subsys {
};
};


#define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys;
#define SUBSYS(_x) extern struct cgroup_subsys _x ## _subsys;
#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option)
#include <linux/cgroup_subsys.h>
#include <linux/cgroup_subsys.h>
#undef IS_SUBSYS_ENABLED
#undef SUBSYS
#undef SUBSYS


static inline struct cgroup_subsys_state *cgroup_subsys_state(
static inline struct cgroup_subsys_state *cgroup_subsys_state(
+12 −12
Original line number Original line Diff line number Diff line
@@ -7,73 +7,73 @@


/* */
/* */


#ifdef CONFIG_CPUSETS
#if IS_SUBSYS_ENABLED(CONFIG_CPUSETS)
SUBSYS(cpuset)
SUBSYS(cpuset)
#endif
#endif


/* */
/* */


#ifdef CONFIG_CGROUP_DEBUG
#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_DEBUG)
SUBSYS(debug)
SUBSYS(debug)
#endif
#endif


/* */
/* */


#ifdef CONFIG_CGROUP_SCHED
#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_SCHED)
SUBSYS(cpu_cgroup)
SUBSYS(cpu_cgroup)
#endif
#endif


/* */
/* */


#ifdef CONFIG_CGROUP_CPUACCT
#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_CPUACCT)
SUBSYS(cpuacct)
SUBSYS(cpuacct)
#endif
#endif


/* */
/* */


#ifdef CONFIG_MEMCG
#if IS_SUBSYS_ENABLED(CONFIG_MEMCG)
SUBSYS(mem_cgroup)
SUBSYS(mem_cgroup)
#endif
#endif


/* */
/* */


#ifdef CONFIG_CGROUP_DEVICE
#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_DEVICE)
SUBSYS(devices)
SUBSYS(devices)
#endif
#endif


/* */
/* */


#ifdef CONFIG_CGROUP_FREEZER
#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_FREEZER)
SUBSYS(freezer)
SUBSYS(freezer)
#endif
#endif


/* */
/* */


#ifdef CONFIG_NET_CLS_CGROUP
#if IS_SUBSYS_ENABLED(CONFIG_NET_CLS_CGROUP)
SUBSYS(net_cls)
SUBSYS(net_cls)
#endif
#endif


/* */
/* */


#ifdef CONFIG_BLK_CGROUP
#if IS_SUBSYS_ENABLED(CONFIG_BLK_CGROUP)
SUBSYS(blkio)
SUBSYS(blkio)
#endif
#endif


/* */
/* */


#ifdef CONFIG_CGROUP_PERF
#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_PERF)
SUBSYS(perf)
SUBSYS(perf)
#endif
#endif


/* */
/* */


#ifdef CONFIG_NETPRIO_CGROUP
#if IS_SUBSYS_ENABLED(CONFIG_NETPRIO_CGROUP)
SUBSYS(net_prio)
SUBSYS(net_prio)
#endif
#endif


/* */
/* */


#ifdef CONFIG_CGROUP_HUGETLB
#if IS_SUBSYS_ENABLED(CONFIG_CGROUP_HUGETLB)
SUBSYS(hugetlb)
SUBSYS(hugetlb)
#endif
#endif


Loading