Skip to content

Commit

Permalink
Merge branch 'for-3.10' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/tj/cgroup

Pull cgroup updates from Tejun Heo:

 - Fixes and a lot of cleanups.  Locking cleanup is finally complete.
   cgroup_mutex is no longer exposed to individual controlelrs which
   used to cause nasty deadlock issues.  Li fixed and cleaned up quite a
   bit including long standing ones like racy cgroup_path().

 - device cgroup now supports proper hierarchy thanks to Aristeu.

 - perf_event cgroup now supports proper hierarchy.

 - A new mount option "__DEVEL__sane_behavior" is added.  As indicated
   by the name, this option is to be used for development only at this
   point and generates a warning message when used.  Unfortunately,
   cgroup interface currently has too many brekages and inconsistencies
   to implement a consistent and unified hierarchy on top.  The new flag
   is used to collect the behavior changes which are necessary to
   implement consistent unified hierarchy.  It's likely that this flag
   won't be used verbatim when it becomes ready but will be enabled
   implicitly along with unified hierarchy.

   The option currently disables some of broken behaviors in cgroup core
   and also .use_hierarchy switch in memcg (will be routed through -mm),
   which can be used to make very unusual hierarchy where nesting is
   partially honored.  It will also be used to implement hierarchy
   support for blk-throttle which would be impossible otherwise without
   introducing a full separate set of control knobs.

   This is essentially versioning of interface which isn't very nice but
   at this point I can't see any other options which would allow keeping
   the interface the same while moving towards hierarchy behavior which
   is at least somewhat sane.  The planned unified hierarchy is likely
   to require some level of adaptation from userland anyway, so I think
   it'd be best to take the chance and update the interface such that
   it's supportable in the long term.

   Maintaining the existing interface does complicate cgroup core but
   shouldn't put too much strain on individual controllers and I think
   it'd be manageable for the foreseeable future.  Maybe we'll be able
   to drop it in a decade.

Fix up conflicts (including a semantic one adding a new #include to ppc
that was uncovered by header the file changes) as per Tejun.

* 'for-3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: (45 commits)
  cpuset: fix compile warning when CONFIG_SMP=n
  cpuset: fix cpu hotplug vs rebuild_sched_domains() race
  cpuset: use rebuild_sched_domains() in cpuset_hotplug_workfn()
  cgroup: restore the call to eventfd->poll()
  cgroup: fix use-after-free when umounting cgroupfs
  cgroup: fix broken file xattrs
  devcg: remove parent_cgroup.
  memcg: force use_hierarchy if sane_behavior
  cgroup: remove cgrp->top_cgroup
  cgroup: introduce sane_behavior mount option
  move cgroupfs_root to include/linux/cgroup.h
  cgroup: convert cgroupfs_root flag bits to masks and add CGRP_ prefix
  cgroup: make cgroup_path() not print double slashes
  Revert "cgroup: remove bind() method from cgroup_subsys."
  perf: make perf_event cgroup hierarchical
  cgroup: implement cgroup_is_descendant()
  cgroup: make sure parent won't be destroyed before its children
  cgroup: remove bind() method from cgroup_subsys.
  devcg: remove broken_hierarchy tag
  cgroup: remove cgroup_lock_is_held()
  ...
  • Loading branch information
Linus Torvalds committed Apr 30, 2013
2 parents 46d9be3 + 2a0010a commit 191a712
Show file tree
Hide file tree
Showing 12 changed files with 826 additions and 633 deletions.
3 changes: 2 additions & 1 deletion Documentation/cgroups/cgroups.txt
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ You can attach the current shell task by echoing 0:
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
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
attached to the cgroup. Writing 0 to cgroup.procs moves all tasks
in the writing task's threadgroup.

Note: Since every task is always a member of exactly one cgroup in each
Expand Down Expand Up @@ -580,6 +580,7 @@ propagation along the hierarchy. See the comment on
cgroup_for_each_descendant_pre() for details.

void css_offline(struct cgroup *cgrp);
(cgroup_mutex held by caller)

This is the counterpart of css_online() and called iff css_online()
has succeeded on @cgrp. This signifies the beginning of the end of
Expand Down
70 changes: 67 additions & 3 deletions Documentation/cgroups/devices.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ either an integer or * for all. Access is a composition of r
The root device cgroup starts with rwm to 'all'. A child device
cgroup gets a copy of the parent. Administrators can then remove
devices from the whitelist or add new entries. A child cgroup can
never receive a device access which is denied by its parent. However
when a device access is removed from a parent it will not also be
removed from the child(ren).
never receive a device access which is denied by its parent.

2. User Interface

Expand Down Expand Up @@ -50,3 +48,69 @@ task to a new cgroup. (Again we'll probably want to change that).

A cgroup may not be granted more permissions than the cgroup's
parent has.

4. Hierarchy

device cgroups maintain hierarchy by making sure a cgroup never has more
access permissions than its parent. Every time an entry is written to
a cgroup's devices.deny file, all its children will have that entry removed
from their whitelist and all the locally set whitelist entries will be
re-evaluated. In case one of the locally set whitelist entries would provide
more access than the cgroup's parent, it'll be removed from the whitelist.

Example:
A
/ \
B

group behavior exceptions
A allow "b 8:* rwm", "c 116:1 rw"
B deny "c 1:3 rwm", "c 116:2 rwm", "b 3:* rwm"

If a device is denied in group A:
# echo "c 116:* r" > A/devices.deny
it'll propagate down and after revalidating B's entries, the whitelist entry
"c 116:2 rwm" will be removed:

group whitelist entries denied devices
A all "b 8:* rwm", "c 116:* rw"
B "c 1:3 rwm", "b 3:* rwm" all the rest

In case parent's exceptions change and local exceptions are not allowed
anymore, they'll be deleted.

Notice that new whitelist entries will not be propagated:
A
/ \
B

group whitelist entries denied devices
A "c 1:3 rwm", "c 1:5 r" all the rest
B "c 1:3 rwm", "c 1:5 r" all the rest

when adding "c *:3 rwm":
# echo "c *:3 rwm" >A/devices.allow

the result:
group whitelist entries denied devices
A "c *:3 rwm", "c 1:5 r" all the rest
B "c 1:3 rwm", "c 1:5 r" all the rest

but now it'll be possible to add new entries to B:
# echo "c 2:3 rwm" >B/devices.allow
# echo "c 50:3 r" >B/devices.allow
or even
# echo "c *:3 rwm" >B/devices.allow

Allowing or denying all by writing 'a' to devices.allow or devices.deny will
not be possible once the device cgroups has children.

4.1 Hierarchy (internal implementation)

device cgroups is implemented internally using a behavior (ALLOW, DENY) and a
list of exceptions. The internal state is controlled using the same user
interface to preserve compatibility with the previous whitelist-only
implementation. Removal or addition of exceptions that will reduce the access
to devices will be propagated down the hierarchy.
For every propagated exception, the effective rules will be re-evaluated based
on current parent's access rules.
1 change: 1 addition & 0 deletions arch/powerpc/mm/numa.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <linux/pfn.h>
#include <linux/cpuset.h>
#include <linux/node.h>
#include <linux/slab.h>
#include <asm/sparsemem.h>
#include <asm/prom.h>
#include <asm/smp.h>
Expand Down
2 changes: 0 additions & 2 deletions block/blk-cgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,7 @@ static inline int blkg_path(struct blkcg_gq *blkg, char *buf, int buflen)
{
int ret;

rcu_read_lock();
ret = cgroup_path(blkg->blkcg->css.cgroup, buf, buflen);
rcu_read_unlock();
if (ret)
strncpy(buf, "<unavailable>", buflen);
return ret;
Expand Down
170 changes: 152 additions & 18 deletions include/linux/cgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <linux/idr.h>
#include <linux/workqueue.h>
#include <linux/xattr.h>
#include <linux/fs.h>

#ifdef CONFIG_CGROUPS

Expand All @@ -30,10 +31,6 @@ struct css_id;

extern int cgroup_init_early(void);
extern int cgroup_init(void);
extern void cgroup_lock(void);
extern int cgroup_lock_is_held(void);
extern bool cgroup_lock_live_group(struct cgroup *cgrp);
extern void cgroup_unlock(void);
extern void cgroup_fork(struct task_struct *p);
extern void cgroup_post_fork(struct task_struct *p);
extern void cgroup_exit(struct task_struct *p, int run_callbacks);
Expand All @@ -44,14 +41,25 @@ extern void cgroup_unload_subsys(struct cgroup_subsys *ss);

extern const struct file_operations proc_cgroup_operations;

/* Define the enumeration of all builtin cgroup subsystems */
/*
* Define the enumeration of all cgroup subsystems.
*
* We define ids for builtin subsystems and then modular ones.
*/
#define SUBSYS(_x) _x ## _subsys_id,
#define IS_SUBSYS_ENABLED(option) IS_ENABLED(option)
enum cgroup_subsys_id {
#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option)
#include <linux/cgroup_subsys.h>
#undef IS_SUBSYS_ENABLED
CGROUP_BUILTIN_SUBSYS_COUNT,

__CGROUP_SUBSYS_TEMP_PLACEHOLDER = CGROUP_BUILTIN_SUBSYS_COUNT - 1,

#define IS_SUBSYS_ENABLED(option) IS_MODULE(option)
#include <linux/cgroup_subsys.h>
#undef IS_SUBSYS_ENABLED
CGROUP_SUBSYS_COUNT,
};
#undef IS_SUBSYS_ENABLED
#undef SUBSYS

/* Per-subsystem/per-cgroup state maintained by the system. */
Expand Down Expand Up @@ -148,6 +156,13 @@ enum {
* specified at mount time and thus is implemented here.
*/
CGRP_CPUSET_CLONE_CHILDREN,
/* see the comment above CGRP_ROOT_SANE_BEHAVIOR for details */
CGRP_SANE_BEHAVIOR,
};

struct cgroup_name {
struct rcu_head rcu_head;
char name[];
};

struct cgroup {
Expand All @@ -172,11 +187,23 @@ struct cgroup {
struct cgroup *parent; /* my parent */
struct dentry *dentry; /* cgroup fs entry, RCU protected */

/*
* This is a copy of dentry->d_name, and it's needed because
* we can't use dentry->d_name in cgroup_path().
*
* You must acquire rcu_read_lock() to access cgrp->name, and
* the only place that can change it is rename(), which is
* protected by parent dir's i_mutex.
*
* Normally you should use cgroup_name() wrapper rather than
* access it directly.
*/
struct cgroup_name __rcu *name;

/* Private pointers for each registered subsystem */
struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];

struct cgroupfs_root *root;
struct cgroup *top_cgroup;

/*
* List of cg_cgroup_links pointing at css_sets with
Expand Down Expand Up @@ -213,6 +240,96 @@ struct cgroup {
struct simple_xattrs xattrs;
};

#define MAX_CGROUP_ROOT_NAMELEN 64

/* cgroupfs_root->flags */
enum {
/*
* Unfortunately, cgroup core and various controllers are riddled
* with idiosyncrasies and pointless options. The following flag,
* when set, will force sane behavior - some options are forced on,
* others are disallowed, and some controllers will change their
* hierarchical or other behaviors.
*
* The set of behaviors affected by this flag are still being
* determined and developed and the mount option for this flag is
* prefixed with __DEVEL__. The prefix will be dropped once we
* reach the point where all behaviors are compatible with the
* planned unified hierarchy, which will automatically turn on this
* flag.
*
* The followings are the behaviors currently affected this flag.
*
* - Mount options "noprefix" and "clone_children" are disallowed.
* Also, cgroupfs file cgroup.clone_children is not created.
*
* - When mounting an existing superblock, mount options should
* match.
*
* - Remount is disallowed.
*
* - memcg: use_hierarchy is on by default and the cgroup file for
* the flag is not created.
*
* The followings are planned changes.
*
* - release_agent will be disallowed once replacement notification
* mechanism is implemented.
*/
CGRP_ROOT_SANE_BEHAVIOR = (1 << 0),

CGRP_ROOT_NOPREFIX = (1 << 1), /* mounted subsystems have no named prefix */
CGRP_ROOT_XATTR = (1 << 2), /* supports extended attributes */
};

/*
* A cgroupfs_root represents the root of a cgroup hierarchy, and may be
* associated with a superblock to form an active hierarchy. This is
* internal to cgroup core. Don't access directly from controllers.
*/
struct cgroupfs_root {
struct super_block *sb;

/*
* The bitmask of subsystems intended to be attached to this
* hierarchy
*/
unsigned long subsys_mask;

/* Unique id for this hierarchy. */
int hierarchy_id;

/* The bitmask of subsystems currently attached to this hierarchy */
unsigned long actual_subsys_mask;

/* A list running through the attached subsystems */
struct list_head subsys_list;

/* The root cgroup for this hierarchy */
struct cgroup top_cgroup;

/* Tracks how many cgroups are currently defined in hierarchy.*/
int number_of_cgroups;

/* A list running through the active hierarchies */
struct list_head root_list;

/* All cgroups on this root, cgroup_mutex protected */
struct list_head allcg_list;

/* Hierarchy-specific flags */
unsigned long flags;

/* IDs for cgroups in this hierarchy */
struct ida cgroup_ida;

/* The path to use for release notifications. */
char release_agent_path[PATH_MAX];

/* The name for this hierarchy - may be empty */
char name[MAX_CGROUP_ROOT_NAMELEN];
};

/*
* A css_set is a structure holding pointers to a set of
* cgroup_subsys_state objects. This saves space in the task struct
Expand Down Expand Up @@ -278,6 +395,7 @@ struct cgroup_map_cb {
/* cftype->flags */
#define CFTYPE_ONLY_ON_ROOT (1U << 0) /* only create on root cg */
#define CFTYPE_NOT_ON_ROOT (1U << 1) /* don't create on root cg */
#define CFTYPE_INSANE (1U << 2) /* don't create if sane_behavior */

#define MAX_CFTYPE_NAME 64

Expand All @@ -304,9 +422,6 @@ struct cftype {
/* CFTYPE_* flags */
unsigned int flags;

/* file xattrs */
struct simple_xattrs xattrs;

int (*open)(struct inode *inode, struct file *file);
ssize_t (*read)(struct cgroup *cgrp, struct cftype *cft,
struct file *file,
Expand Down Expand Up @@ -404,18 +519,31 @@ struct cgroup_scanner {
void *data;
};

/*
* See the comment above CGRP_ROOT_SANE_BEHAVIOR for details. This
* function can be called as long as @cgrp is accessible.
*/
static inline bool cgroup_sane_behavior(const struct cgroup *cgrp)
{
return cgrp->root->flags & CGRP_ROOT_SANE_BEHAVIOR;
}

/* Caller should hold rcu_read_lock() */
static inline const char *cgroup_name(const struct cgroup *cgrp)
{
return rcu_dereference(cgrp->name)->name;
}

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

int cgroup_is_removed(const struct cgroup *cgrp);
bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor);

int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen);

int cgroup_task_count(const struct cgroup *cgrp);

/* Return true if cgrp is a descendant of the task's cgroup */
int cgroup_is_descendant(const struct cgroup *cgrp, struct task_struct *task);

/*
* Control Group taskset, used to pass around set of tasks to cgroup_subsys
* methods.
Expand Down Expand Up @@ -523,10 +651,16 @@ static inline struct cgroup_subsys_state *cgroup_subsys_state(
* rcu_dereference_check() conditions, such as locks used during the
* cgroup_subsys::attach() methods.
*/
#ifdef CONFIG_PROVE_RCU
extern struct mutex cgroup_mutex;
#define task_subsys_state_check(task, subsys_id, __c) \
rcu_dereference_check((task)->cgroups->subsys[(subsys_id)], \
lockdep_is_held(&(task)->alloc_lock) || \
lockdep_is_held(&cgroup_mutex) || (__c))
#else
#define task_subsys_state_check(task, subsys_id, __c) \
rcu_dereference_check(task->cgroups->subsys[subsys_id], \
lockdep_is_held(&task->alloc_lock) || \
cgroup_lock_is_held() || (__c))
rcu_dereference((task)->cgroups->subsys[(subsys_id)])
#endif

static inline struct cgroup_subsys_state *
task_subsys_state(struct task_struct *task, int subsys_id)
Expand Down Expand Up @@ -661,8 +795,8 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp,
struct cgroup_iter *it);
void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it);
int cgroup_scan_tasks(struct cgroup_scanner *scan);
int cgroup_attach_task(struct cgroup *, struct task_struct *);
int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);

/*
* CSS ID is ID for cgroup_subsys_state structs under subsys. This only works
Expand Down
1 change: 0 additions & 1 deletion include/linux/cpuset.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include <linux/sched.h>
#include <linux/cpumask.h>
#include <linux/nodemask.h>
#include <linux/cgroup.h>
#include <linux/mm.h>

#ifdef CONFIG_CPUSETS
Expand Down
2 changes: 1 addition & 1 deletion include/linux/res_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* info about what this counter is.
*/

#include <linux/cgroup.h>
#include <linux/spinlock.h>
#include <linux/errno.h>

/*
Expand Down
Loading

0 comments on commit 191a712

Please sign in to comment.