Skip to content

Commit

Permalink
Merge branch 'for-3.19' 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 update from Tejun Heo:
 "cpuset got simplified a bit.  cgroup core got a fix on unified
  hierarchy and grew some effective css related interfaces which will be
  used for blkio support for writeback IO traffic which is currently
  being worked on"

* 'for-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup:
  cgroup: implement cgroup_get_e_css()
  cgroup: add cgroup_subsys->css_e_css_changed()
  cgroup: add cgroup_subsys->css_released()
  cgroup: fix the async css offline wait logic in cgroup_subtree_control_write()
  cgroup: restructure child_subsys_mask handling in cgroup_subtree_control_write()
  cgroup: separate out cgroup_calc_child_subsys_mask() from cgroup_refresh_child_subsys_mask()
  cpuset: lock vs unlock typo
  cpuset: simplify cpuset_node_allowed API
  cpuset: convert callback_mutex to a spinlock
  • Loading branch information
Linus Torvalds committed Dec 12, 2014
2 parents 4e8790f + eeecbd1 commit 2756d37
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 198 deletions.
4 changes: 4 additions & 0 deletions include/linux/cgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -638,8 +638,10 @@ struct cgroup_subsys {
struct cgroup_subsys_state *(*css_alloc)(struct cgroup_subsys_state *parent_css);
int (*css_online)(struct cgroup_subsys_state *css);
void (*css_offline)(struct cgroup_subsys_state *css);
void (*css_released)(struct cgroup_subsys_state *css);
void (*css_free)(struct cgroup_subsys_state *css);
void (*css_reset)(struct cgroup_subsys_state *css);
void (*css_e_css_changed)(struct cgroup_subsys_state *css);

int (*can_attach)(struct cgroup_subsys_state *css,
struct cgroup_taskset *tset);
Expand Down Expand Up @@ -934,6 +936,8 @@ void css_task_iter_end(struct css_task_iter *it);
int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);

struct cgroup_subsys_state *cgroup_get_e_css(struct cgroup *cgroup,
struct cgroup_subsys *ss);
struct cgroup_subsys_state *css_tryget_online_from_dir(struct dentry *dentry,
struct cgroup_subsys *ss);

Expand Down
37 changes: 7 additions & 30 deletions include/linux/cpuset.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,29 +48,16 @@ extern nodemask_t cpuset_mems_allowed(struct task_struct *p);
void cpuset_init_current_mems_allowed(void);
int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask);

extern int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask);
extern int __cpuset_node_allowed_hardwall(int node, gfp_t gfp_mask);
extern int __cpuset_node_allowed(int node, gfp_t gfp_mask);

static inline int cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
static inline int cpuset_node_allowed(int node, gfp_t gfp_mask)
{
return nr_cpusets() <= 1 ||
__cpuset_node_allowed_softwall(node, gfp_mask);
return nr_cpusets() <= 1 || __cpuset_node_allowed(node, gfp_mask);
}

static inline int cpuset_node_allowed_hardwall(int node, gfp_t gfp_mask)
static inline int cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
{
return nr_cpusets() <= 1 ||
__cpuset_node_allowed_hardwall(node, gfp_mask);
}

static inline int cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
{
return cpuset_node_allowed_softwall(zone_to_nid(z), gfp_mask);
}

static inline int cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
{
return cpuset_node_allowed_hardwall(zone_to_nid(z), gfp_mask);
return cpuset_node_allowed(zone_to_nid(z), gfp_mask);
}

extern int cpuset_mems_allowed_intersects(const struct task_struct *tsk1,
Expand Down Expand Up @@ -179,22 +166,12 @@ static inline int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask)
return 1;
}

static inline int cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
{
return 1;
}

static inline int cpuset_node_allowed_hardwall(int node, gfp_t gfp_mask)
{
return 1;
}

static inline int cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
static inline int cpuset_node_allowed(int node, gfp_t gfp_mask)
{
return 1;
}

static inline int cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
static inline int cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
{
return 1;
}
Expand Down
175 changes: 121 additions & 54 deletions kernel/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,13 +277,50 @@ static struct cgroup_subsys_state *cgroup_e_css(struct cgroup *cgrp,
if (!(cgrp->root->subsys_mask & (1 << ss->id)))
return NULL;

/*
* This function is used while updating css associations and thus
* can't test the csses directly. Use ->child_subsys_mask.
*/
while (cgroup_parent(cgrp) &&
!(cgroup_parent(cgrp)->child_subsys_mask & (1 << ss->id)))
cgrp = cgroup_parent(cgrp);

return cgroup_css(cgrp, ss);
}

/**
* cgroup_get_e_css - get a cgroup's effective css for the specified subsystem
* @cgrp: the cgroup of interest
* @ss: the subsystem of interest
*
* Find and get the effective css of @cgrp for @ss. The effective css is
* defined as the matching css of the nearest ancestor including self which
* has @ss enabled. If @ss is not mounted on the hierarchy @cgrp is on,
* the root css is returned, so this function always returns a valid css.
* The returned css must be put using css_put().
*/
struct cgroup_subsys_state *cgroup_get_e_css(struct cgroup *cgrp,
struct cgroup_subsys *ss)
{
struct cgroup_subsys_state *css;

rcu_read_lock();

do {
css = cgroup_css(cgrp, ss);

if (css && css_tryget_online(css))
goto out_unlock;
cgrp = cgroup_parent(cgrp);
} while (cgrp);

css = init_css_set.subsys[ss->id];
css_get(css);
out_unlock:
rcu_read_unlock();
return css;
}

/* convenient tests for these bits */
static inline bool cgroup_is_dead(const struct cgroup *cgrp)
{
Expand Down Expand Up @@ -1019,31 +1056,30 @@ static void cgroup_put(struct cgroup *cgrp)
}

/**
* cgroup_refresh_child_subsys_mask - update child_subsys_mask
* cgroup_calc_child_subsys_mask - calculate child_subsys_mask
* @cgrp: the target cgroup
* @subtree_control: the new subtree_control mask to consider
*
* On the default hierarchy, a subsystem may request other subsystems to be
* enabled together through its ->depends_on mask. In such cases, more
* subsystems than specified in "cgroup.subtree_control" may be enabled.
*
* This function determines which subsystems need to be enabled given the
* current @cgrp->subtree_control and records it in
* @cgrp->child_subsys_mask. The resulting mask is always a superset of
* @cgrp->subtree_control and follows the usual hierarchy rules.
* This function calculates which subsystems need to be enabled if
* @subtree_control is to be applied to @cgrp. The returned mask is always
* a superset of @subtree_control and follows the usual hierarchy rules.
*/
static void cgroup_refresh_child_subsys_mask(struct cgroup *cgrp)
static unsigned int cgroup_calc_child_subsys_mask(struct cgroup *cgrp,
unsigned int subtree_control)
{
struct cgroup *parent = cgroup_parent(cgrp);
unsigned int cur_ss_mask = cgrp->subtree_control;
unsigned int cur_ss_mask = subtree_control;
struct cgroup_subsys *ss;
int ssid;

lockdep_assert_held(&cgroup_mutex);

if (!cgroup_on_dfl(cgrp)) {
cgrp->child_subsys_mask = cur_ss_mask;
return;
}
if (!cgroup_on_dfl(cgrp))
return cur_ss_mask;

while (true) {
unsigned int new_ss_mask = cur_ss_mask;
Expand All @@ -1067,7 +1103,20 @@ static void cgroup_refresh_child_subsys_mask(struct cgroup *cgrp)
cur_ss_mask = new_ss_mask;
}

cgrp->child_subsys_mask = cur_ss_mask;
return cur_ss_mask;
}

/**
* cgroup_refresh_child_subsys_mask - update child_subsys_mask
* @cgrp: the target cgroup
*
* Update @cgrp->child_subsys_mask according to the current
* @cgrp->subtree_control using cgroup_calc_child_subsys_mask().
*/
static void cgroup_refresh_child_subsys_mask(struct cgroup *cgrp)
{
cgrp->child_subsys_mask =
cgroup_calc_child_subsys_mask(cgrp, cgrp->subtree_control);
}

/**
Expand Down Expand Up @@ -2641,7 +2690,7 @@ static ssize_t cgroup_subtree_control_write(struct kernfs_open_file *of,
loff_t off)
{
unsigned int enable = 0, disable = 0;
unsigned int css_enable, css_disable, old_ctrl, new_ctrl;
unsigned int css_enable, css_disable, old_sc, new_sc, old_ss, new_ss;
struct cgroup *cgrp, *child;
struct cgroup_subsys *ss;
char *tok;
Expand Down Expand Up @@ -2693,36 +2742,6 @@ static ssize_t cgroup_subtree_control_write(struct kernfs_open_file *of,
ret = -ENOENT;
goto out_unlock;
}

/*
* @ss is already enabled through dependency and
* we'll just make it visible. Skip draining.
*/
if (cgrp->child_subsys_mask & (1 << ssid))
continue;

/*
* Because css offlining is asynchronous, userland
* might try to re-enable the same controller while
* the previous instance is still around. In such
* cases, wait till it's gone using offline_waitq.
*/
cgroup_for_each_live_child(child, cgrp) {
DEFINE_WAIT(wait);

if (!cgroup_css(child, ss))
continue;

cgroup_get(child);
prepare_to_wait(&child->offline_waitq, &wait,
TASK_UNINTERRUPTIBLE);
cgroup_kn_unlock(of->kn);
schedule();
finish_wait(&child->offline_waitq, &wait);
cgroup_put(child);

return restart_syscall();
}
} else if (disable & (1 << ssid)) {
if (!(cgrp->subtree_control & (1 << ssid))) {
disable &= ~(1 << ssid);
Expand Down Expand Up @@ -2758,18 +2777,47 @@ static ssize_t cgroup_subtree_control_write(struct kernfs_open_file *of,
* subsystems than specified may need to be enabled or disabled
* depending on subsystem dependencies.
*/
cgrp->subtree_control |= enable;
cgrp->subtree_control &= ~disable;
old_sc = cgrp->subtree_control;
old_ss = cgrp->child_subsys_mask;
new_sc = (old_sc | enable) & ~disable;
new_ss = cgroup_calc_child_subsys_mask(cgrp, new_sc);

old_ctrl = cgrp->child_subsys_mask;
cgroup_refresh_child_subsys_mask(cgrp);
new_ctrl = cgrp->child_subsys_mask;

css_enable = ~old_ctrl & new_ctrl;
css_disable = old_ctrl & ~new_ctrl;
css_enable = ~old_ss & new_ss;
css_disable = old_ss & ~new_ss;
enable |= css_enable;
disable |= css_disable;

/*
* Because css offlining is asynchronous, userland might try to
* re-enable the same controller while the previous instance is
* still around. In such cases, wait till it's gone using
* offline_waitq.
*/
for_each_subsys(ss, ssid) {
if (!(css_enable & (1 << ssid)))
continue;

cgroup_for_each_live_child(child, cgrp) {
DEFINE_WAIT(wait);

if (!cgroup_css(child, ss))
continue;

cgroup_get(child);
prepare_to_wait(&child->offline_waitq, &wait,
TASK_UNINTERRUPTIBLE);
cgroup_kn_unlock(of->kn);
schedule();
finish_wait(&child->offline_waitq, &wait);
cgroup_put(child);

return restart_syscall();
}
}

cgrp->subtree_control = new_sc;
cgrp->child_subsys_mask = new_ss;

/*
* Create new csses or make the existing ones visible. A css is
* created invisible if it's being implicitly enabled through
Expand Down Expand Up @@ -2825,16 +2873,33 @@ static ssize_t cgroup_subtree_control_write(struct kernfs_open_file *of,
}
}

/*
* The effective csses of all the descendants (excluding @cgrp) may
* have changed. Subsystems can optionally subscribe to this event
* by implementing ->css_e_css_changed() which is invoked if any of
* the effective csses seen from the css's cgroup may have changed.
*/
for_each_subsys(ss, ssid) {
struct cgroup_subsys_state *this_css = cgroup_css(cgrp, ss);
struct cgroup_subsys_state *css;

if (!ss->css_e_css_changed || !this_css)
continue;

css_for_each_descendant_pre(css, this_css)
if (css != this_css)
ss->css_e_css_changed(css);
}

kernfs_activate(cgrp->kn);
ret = 0;
out_unlock:
cgroup_kn_unlock(of->kn);
return ret ?: nbytes;

err_undo_css:
cgrp->subtree_control &= ~enable;
cgrp->subtree_control |= disable;
cgroup_refresh_child_subsys_mask(cgrp);
cgrp->subtree_control = old_sc;
cgrp->child_subsys_mask = old_ss;

for_each_subsys(ss, ssid) {
if (!(enable & (1 << ssid)))
Expand Down Expand Up @@ -4370,6 +4435,8 @@ static void css_release_work_fn(struct work_struct *work)
if (ss) {
/* css release path */
cgroup_idr_remove(&ss->css_idr, css->id);
if (ss->css_released)
ss->css_released(css);
} else {
/* cgroup release path */
cgroup_idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
Expand Down
Loading

0 comments on commit 2756d37

Please sign in to comment.