Merge branch 'for-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
Pull cgroup updates from Tejun Heo: "A lot of activities on cgroup side. Heavy restructuring including locking simplification took place to improve the code base and enable implementation of the unified hierarchy, which currently exists behind a __DEVEL__ mount option. The core support is mostly complete but individual controllers need further work. To explain the design and rationales of the the unified hierarchy Documentation/cgroups/unified-hierarchy.txt is added. Another notable change is css (cgroup_subsys_state - what each controller uses to identify and interact with a cgroup) iteration update. This is part of continuing updates on css object lifetime and visibility. cgroup started with reference count draining on removal way back and is now reaching a point where csses behave and are iterated like normal refcnted objects albeit with some complexities to allow distinguishing the state where they're being deleted. The css iteration update isn't taken advantage of yet but is planned to be used to simplify memcg significantly" * 'for-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: (77 commits) cgroup: disallow disabled controllers on the default hierarchy cgroup: don't destroy the default root cgroup: disallow debug controller on the default hierarchy cgroup: clean up MAINTAINERS entries cgroup: implement css_tryget() device_cgroup: use css_has_online_children() instead of has_children() cgroup: convert cgroup_has_live_children() into css_has_online_children() cgroup: use CSS_ONLINE instead of CGRP_DEAD cgroup: iterate cgroup_subsys_states directly cgroup: introduce CSS_RELEASED and reduce css iteration fallback window cgroup: move cgroup->serial_nr into cgroup_subsys_state cgroup: link all cgroup_subsys_states in their sibling lists cgroup: move cgroup->sibling and ->children into cgroup_subsys_state cgroup: remove cgroup->parent device_cgroup: remove direct access to cgroup->children memcg: update memcg_has_children() to use css_next_child() memcg: remove tasks/children test from mem_cgroup_force_empty() cgroup: remove css_parent() cgroup: skip refcnting on normal root csses and cgrp_dfl_root self css cgroup: use cgroup->self.refcnt for cgroup refcnting ...
This commit is contained in:
Коммит
14208b0ec5
|
@ -458,15 +458,11 @@ About use_hierarchy, see Section 6.
|
|||
|
||||
5.1 force_empty
|
||||
memory.force_empty interface is provided to make cgroup's memory usage empty.
|
||||
You can use this interface only when the cgroup has no tasks.
|
||||
When writing anything to this
|
||||
|
||||
# echo 0 > memory.force_empty
|
||||
|
||||
Almost all pages tracked by this memory cgroup will be unmapped and freed.
|
||||
Some pages cannot be freed because they are locked or in-use. Such pages are
|
||||
moved to parent (if use_hierarchy==1) or root (if use_hierarchy==0) and this
|
||||
cgroup will be empty.
|
||||
the cgroup will be reclaimed and as many pages reclaimed as possible.
|
||||
|
||||
The typical use case for this interface is before calling rmdir().
|
||||
Because rmdir() moves all pages to parent, some out-of-use page caches can be
|
||||
|
|
|
@ -0,0 +1,359 @@
|
|||
|
||||
Cgroup unified hierarchy
|
||||
|
||||
April, 2014 Tejun Heo <tj@kernel.org>
|
||||
|
||||
This document describes the changes made by unified hierarchy and
|
||||
their rationales. It will eventually be merged into the main cgroup
|
||||
documentation.
|
||||
|
||||
CONTENTS
|
||||
|
||||
1. Background
|
||||
2. Basic Operation
|
||||
2-1. Mounting
|
||||
2-2. cgroup.subtree_control
|
||||
2-3. cgroup.controllers
|
||||
3. Structural Constraints
|
||||
3-1. Top-down
|
||||
3-2. No internal tasks
|
||||
4. Other Changes
|
||||
4-1. [Un]populated Notification
|
||||
4-2. Other Core Changes
|
||||
4-3. Per-Controller Changes
|
||||
4-3-1. blkio
|
||||
4-3-2. cpuset
|
||||
4-3-3. memory
|
||||
5. Planned Changes
|
||||
5-1. CAP for resource control
|
||||
|
||||
|
||||
1. Background
|
||||
|
||||
cgroup allows an arbitrary number of hierarchies and each hierarchy
|
||||
can host any number of controllers. While this seems to provide a
|
||||
high level of flexibility, it isn't quite useful in practice.
|
||||
|
||||
For example, as there is only one instance of each controller, utility
|
||||
type controllers such as freezer which can be useful in all
|
||||
hierarchies can only be used in one. The issue is exacerbated by the
|
||||
fact that controllers can't be moved around once hierarchies are
|
||||
populated. Another issue is that all controllers bound to a hierarchy
|
||||
are forced to have exactly the same view of the hierarchy. It isn't
|
||||
possible to vary the granularity depending on the specific controller.
|
||||
|
||||
In practice, these issues heavily limit which controllers can be put
|
||||
on the same hierarchy and most configurations resort to putting each
|
||||
controller on its own hierarchy. Only closely related ones, such as
|
||||
the cpu and cpuacct controllers, make sense to put on the same
|
||||
hierarchy. This often means that userland ends up managing multiple
|
||||
similar hierarchies repeating the same steps on each hierarchy
|
||||
whenever a hierarchy management operation is necessary.
|
||||
|
||||
Unfortunately, support for multiple hierarchies comes at a steep cost.
|
||||
Internal implementation in cgroup core proper is dazzlingly
|
||||
complicated but more importantly the support for multiple hierarchies
|
||||
restricts how cgroup is used in general and what controllers can do.
|
||||
|
||||
There's no limit on how many hierarchies there may be, which means
|
||||
that a task's cgroup membership can't be described in finite length.
|
||||
The key may contain any varying number of entries and is unlimited in
|
||||
length, which makes it highly awkward to handle and leads to addition
|
||||
of controllers which exist only to identify membership, which in turn
|
||||
exacerbates the original problem.
|
||||
|
||||
Also, as a controller can't have any expectation regarding what shape
|
||||
of hierarchies other controllers would be on, each controller has to
|
||||
assume that all other controllers are operating on completely
|
||||
orthogonal hierarchies. This makes it impossible, or at least very
|
||||
cumbersome, for controllers to cooperate with each other.
|
||||
|
||||
In most use cases, putting controllers on hierarchies which are
|
||||
completely orthogonal to each other isn't necessary. What usually is
|
||||
called for is the ability to have differing levels of granularity
|
||||
depending on the specific controller. In other words, hierarchy may
|
||||
be collapsed from leaf towards root when viewed from specific
|
||||
controllers. For example, a given configuration might not care about
|
||||
how memory is distributed beyond a certain level while still wanting
|
||||
to control how CPU cycles are distributed.
|
||||
|
||||
Unified hierarchy is the next version of cgroup interface. It aims to
|
||||
address the aforementioned issues by having more structure while
|
||||
retaining enough flexibility for most use cases. Various other
|
||||
general and controller-specific interface issues are also addressed in
|
||||
the process.
|
||||
|
||||
|
||||
2. Basic Operation
|
||||
|
||||
2-1. Mounting
|
||||
|
||||
Currently, unified hierarchy can be mounted with the following mount
|
||||
command. Note that this is still under development and scheduled to
|
||||
change soon.
|
||||
|
||||
mount -t cgroup -o __DEVEL__sane_behavior cgroup $MOUNT_POINT
|
||||
|
||||
All controllers which are not bound to other hierarchies are
|
||||
automatically bound to unified hierarchy and show up at the root of
|
||||
it. Controllers which are enabled only in the root of unified
|
||||
hierarchy can be bound to other hierarchies at any time. This allows
|
||||
mixing unified hierarchy with the traditional multiple hierarchies in
|
||||
a fully backward compatible way.
|
||||
|
||||
|
||||
2-2. cgroup.subtree_control
|
||||
|
||||
All cgroups on unified hierarchy have a "cgroup.subtree_control" file
|
||||
which governs which controllers are enabled on the children of the
|
||||
cgroup. Let's assume a hierarchy like the following.
|
||||
|
||||
root - A - B - C
|
||||
\ D
|
||||
|
||||
root's "cgroup.subtree_control" file determines which controllers are
|
||||
enabled on A. A's on B. B's on C and D. This coincides with the
|
||||
fact that controllers on the immediate sub-level are used to
|
||||
distribute the resources of the parent. In fact, it's natural to
|
||||
assume that resource control knobs of a child belong to its parent.
|
||||
Enabling a controller in a "cgroup.subtree_control" file declares that
|
||||
distribution of the respective resources of the cgroup will be
|
||||
controlled. Note that this means that controller enable states are
|
||||
shared among siblings.
|
||||
|
||||
When read, the file contains a space-separated list of currently
|
||||
enabled controllers. A write to the file should contain a
|
||||
space-separated list of controllers with '+' or '-' prefixed (without
|
||||
the quotes). Controllers prefixed with '+' are enabled and '-'
|
||||
disabled. If a controller is listed multiple times, the last entry
|
||||
wins. The specific operations are executed atomically - either all
|
||||
succeed or fail.
|
||||
|
||||
|
||||
2-3. cgroup.controllers
|
||||
|
||||
Read-only "cgroup.controllers" file contains a space-separated list of
|
||||
controllers which can be enabled in the cgroup's
|
||||
"cgroup.subtree_control" file.
|
||||
|
||||
In the root cgroup, this lists controllers which are not bound to
|
||||
other hierarchies and the content changes as controllers are bound to
|
||||
and unbound from other hierarchies.
|
||||
|
||||
In non-root cgroups, the content of this file equals that of the
|
||||
parent's "cgroup.subtree_control" file as only controllers enabled
|
||||
from the parent can be used in its children.
|
||||
|
||||
|
||||
3. Structural Constraints
|
||||
|
||||
3-1. Top-down
|
||||
|
||||
As it doesn't make sense to nest control of an uncontrolled resource,
|
||||
all non-root "cgroup.subtree_control" files can only contain
|
||||
controllers which are enabled in the parent's "cgroup.subtree_control"
|
||||
file. A controller can be enabled only if the parent has the
|
||||
controller enabled and a controller can't be disabled if one or more
|
||||
children have it enabled.
|
||||
|
||||
|
||||
3-2. No internal tasks
|
||||
|
||||
One long-standing issue that cgroup faces is the competition between
|
||||
tasks belonging to the parent cgroup and its children cgroups. This
|
||||
is inherently nasty as two different types of entities compete and
|
||||
there is no agreed-upon obvious way to handle it. Different
|
||||
controllers are doing different things.
|
||||
|
||||
The cpu controller considers tasks and cgroups as equivalents and maps
|
||||
nice levels to cgroup weights. This works for some cases but falls
|
||||
flat when children should be allocated specific ratios of CPU cycles
|
||||
and the number of internal tasks fluctuates - the ratios constantly
|
||||
change as the number of competing entities fluctuates. There also are
|
||||
other issues. The mapping from nice level to weight isn't obvious or
|
||||
universal, and there are various other knobs which simply aren't
|
||||
available for tasks.
|
||||
|
||||
The blkio controller implicitly creates a hidden leaf node for each
|
||||
cgroup to host the tasks. The hidden leaf has its own copies of all
|
||||
the knobs with "leaf_" prefixed. While this allows equivalent control
|
||||
over internal tasks, it's with serious drawbacks. It always adds an
|
||||
extra layer of nesting which may not be necessary, makes the interface
|
||||
messy and significantly complicates the implementation.
|
||||
|
||||
The memory controller currently doesn't have a way to control what
|
||||
happens between internal tasks and child cgroups and the behavior is
|
||||
not clearly defined. There have been attempts to add ad-hoc behaviors
|
||||
and knobs to tailor the behavior to specific workloads. Continuing
|
||||
this direction will lead to problems which will be extremely difficult
|
||||
to resolve in the long term.
|
||||
|
||||
Multiple controllers struggle with internal tasks and came up with
|
||||
different ways to deal with it; unfortunately, all the approaches in
|
||||
use now are severely flawed and, furthermore, the widely different
|
||||
behaviors make cgroup as whole highly inconsistent.
|
||||
|
||||
It is clear that this is something which needs to be addressed from
|
||||
cgroup core proper in a uniform way so that controllers don't need to
|
||||
worry about it and cgroup as a whole shows a consistent and logical
|
||||
behavior. To achieve that, unified hierarchy enforces the following
|
||||
structural constraint:
|
||||
|
||||
Except for the root, only cgroups which don't contain any task may
|
||||
have controllers enabled in their "cgroup.subtree_control" files.
|
||||
|
||||
Combined with other properties, this guarantees that, when a
|
||||
controller is looking at the part of the hierarchy which has it
|
||||
enabled, tasks are always only on the leaves. This rules out
|
||||
situations where child cgroups compete against internal tasks of the
|
||||
parent.
|
||||
|
||||
There are two things to note. Firstly, the root cgroup is exempt from
|
||||
the restriction. Root contains tasks and anonymous resource
|
||||
consumption which can't be associated with any other cgroup and
|
||||
requires special treatment from most controllers. How resource
|
||||
consumption in the root cgroup is governed is up to each controller.
|
||||
|
||||
Secondly, the restriction doesn't take effect if there is no enabled
|
||||
controller in the cgroup's "cgroup.subtree_control" file. This is
|
||||
important as otherwise it wouldn't be possible to create children of a
|
||||
populated cgroup. To control resource distribution of a cgroup, the
|
||||
cgroup must create children and transfer all its tasks to the children
|
||||
before enabling controllers in its "cgroup.subtree_control" file.
|
||||
|
||||
|
||||
4. Other Changes
|
||||
|
||||
4-1. [Un]populated Notification
|
||||
|
||||
cgroup users often need a way to determine when a cgroup's
|
||||
subhierarchy becomes empty so that it can be cleaned up. cgroup
|
||||
currently provides release_agent for it; unfortunately, this mechanism
|
||||
is riddled with issues.
|
||||
|
||||
- It delivers events by forking and execing a userland binary
|
||||
specified as the release_agent. This is a long deprecated method of
|
||||
notification delivery. It's extremely heavy, slow and cumbersome to
|
||||
integrate with larger infrastructure.
|
||||
|
||||
- There is single monitoring point at the root. There's no way to
|
||||
delegate management of a subtree.
|
||||
|
||||
- The event isn't recursive. It triggers when a cgroup doesn't have
|
||||
any tasks or child cgroups. Events for internal nodes trigger only
|
||||
after all children are removed. This again makes it impossible to
|
||||
delegate management of a subtree.
|
||||
|
||||
- Events are filtered from the kernel side. A "notify_on_release"
|
||||
file is used to subscribe to or suppress release events. This is
|
||||
unnecessarily complicated and probably done this way because event
|
||||
delivery itself was expensive.
|
||||
|
||||
Unified hierarchy implements an interface file "cgroup.populated"
|
||||
which can be used to monitor whether the cgroup's subhierarchy has
|
||||
tasks in it or not. Its value is 0 if there is no task in the cgroup
|
||||
and its descendants; otherwise, 1. poll and [id]notify events are
|
||||
triggered when the value changes.
|
||||
|
||||
This is significantly lighter and simpler and trivially allows
|
||||
delegating management of subhierarchy - subhierarchy monitoring can
|
||||
block further propagation simply by putting itself or another process
|
||||
in the subhierarchy and monitor events that it's interested in from
|
||||
there without interfering with monitoring higher in the tree.
|
||||
|
||||
In unified hierarchy, the release_agent mechanism is no longer
|
||||
supported and the interface files "release_agent" and
|
||||
"notify_on_release" do not exist.
|
||||
|
||||
|
||||
4-2. Other Core Changes
|
||||
|
||||
- None of the mount options is allowed.
|
||||
|
||||
- remount is disallowed.
|
||||
|
||||
- rename(2) is disallowed.
|
||||
|
||||
- The "tasks" file is removed. Everything should at process
|
||||
granularity. Use the "cgroup.procs" file instead.
|
||||
|
||||
- The "cgroup.procs" file is not sorted. pids will be unique unless
|
||||
they got recycled in-between reads.
|
||||
|
||||
- The "cgroup.clone_children" file is removed.
|
||||
|
||||
|
||||
4-3. Per-Controller Changes
|
||||
|
||||
4-3-1. blkio
|
||||
|
||||
- blk-throttle becomes properly hierarchical.
|
||||
|
||||
|
||||
4-3-2. cpuset
|
||||
|
||||
- Tasks are kept in empty cpusets after hotplug and take on the masks
|
||||
of the nearest non-empty ancestor, instead of being moved to it.
|
||||
|
||||
- A task can be moved into an empty cpuset, and again it takes on the
|
||||
masks of the nearest non-empty ancestor.
|
||||
|
||||
|
||||
4-3-3. memory
|
||||
|
||||
- use_hierarchy is on by default and the cgroup file for the flag is
|
||||
not created.
|
||||
|
||||
|
||||
5. Planned Changes
|
||||
|
||||
5-1. CAP for resource control
|
||||
|
||||
Unified hierarchy will require one of the capabilities(7), which is
|
||||
yet to be decided, for all resource control related knobs. Process
|
||||
organization operations - creation of sub-cgroups and migration of
|
||||
processes in sub-hierarchies may be delegated by changing the
|
||||
ownership and/or permissions on the cgroup directory and
|
||||
"cgroup.procs" interface file; however, all operations which affect
|
||||
resource control - writes to a "cgroup.subtree_control" file or any
|
||||
controller-specific knobs - will require an explicit CAP privilege.
|
||||
|
||||
This, in part, is to prevent the cgroup interface from being
|
||||
inadvertently promoted to programmable API used by non-privileged
|
||||
binaries. cgroup exposes various aspects of the system in ways which
|
||||
aren't properly abstracted for direct consumption by regular programs.
|
||||
This is an administration interface much closer to sysctl knobs than
|
||||
system calls. Even the basic access model, being filesystem path
|
||||
based, isn't suitable for direct consumption. There's no way to
|
||||
access "my cgroup" in a race-free way or make multiple operations
|
||||
atomic against migration to another cgroup.
|
||||
|
||||
Another aspect is that, for better or for worse, the cgroup interface
|
||||
goes through far less scrutiny than regular interfaces for
|
||||
unprivileged userland. The upside is that cgroup is able to expose
|
||||
useful features which may not be suitable for general consumption in a
|
||||
reasonable time frame. It provides a relatively short path between
|
||||
internal details and userland-visible interface. Of course, this
|
||||
shortcut comes with high risk. We go through what we go through for
|
||||
general kernel APIs for good reasons. It may end up leaking internal
|
||||
details in a way which can exert significant pain by locking the
|
||||
kernel into a contract that can't be maintained in a reasonable
|
||||
manner.
|
||||
|
||||
Also, due to the specific nature, cgroup and its controllers don't
|
||||
tend to attract attention from a wide scope of developers. cgroup's
|
||||
short history is already fraught with severely mis-designed
|
||||
interfaces, unnecessary commitments to and exposing of internal
|
||||
details, broken and dangerous implementations of various features.
|
||||
|
||||
Keeping cgroup as an administration interface is both advantageous for
|
||||
its role and imperative given its nature. Some of the cgroup features
|
||||
may make sense for unprivileged access. If deemed justified, those
|
||||
must be further abstracted and implemented as a different interface,
|
||||
be it a system call or process-private filesystem, and survive through
|
||||
the scrutiny that any interface for general consumption is required to
|
||||
go through.
|
||||
|
||||
Requiring CAP is not a complete solution but should serve as a
|
||||
significant deterrent against spraying cgroup usages in non-privileged
|
||||
programs.
|
47
MAINTAINERS
47
MAINTAINERS
|
@ -2384,16 +2384,35 @@ L: netdev@vger.kernel.org
|
|||
S: Maintained
|
||||
F: drivers/connector/
|
||||
|
||||
CONTROL GROUPS (CGROUPS)
|
||||
CONTROL GROUP (CGROUP)
|
||||
M: Tejun Heo <tj@kernel.org>
|
||||
M: Li Zefan <lizefan@huawei.com>
|
||||
L: containers@lists.linux-foundation.org
|
||||
L: cgroups@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
|
||||
S: Maintained
|
||||
F: Documentation/cgroups/
|
||||
F: include/linux/cgroup*
|
||||
F: kernel/cgroup*
|
||||
F: mm/*cgroup*
|
||||
|
||||
CONTROL GROUP - CPUSET
|
||||
M: Li Zefan <lizefan@huawei.com>
|
||||
L: cgroups@vger.kernel.org
|
||||
W: http://www.bullopensource.org/cpuset/
|
||||
W: http://oss.sgi.com/projects/cpusets/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
|
||||
S: Maintained
|
||||
F: Documentation/cgroups/cpusets.txt
|
||||
F: include/linux/cpuset.h
|
||||
F: kernel/cpuset.c
|
||||
|
||||
CONTROL GROUP - MEMORY RESOURCE CONTROLLER (MEMCG)
|
||||
M: Johannes Weiner <hannes@cmpxchg.org>
|
||||
M: Michal Hocko <mhocko@suse.cz>
|
||||
L: cgroups@vger.kernel.org
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
F: mm/memcontrol.c
|
||||
F: mm/page_cgroup.c
|
||||
|
||||
CORETEMP HARDWARE MONITORING DRIVER
|
||||
M: Fenghua Yu <fenghua.yu@intel.com>
|
||||
|
@ -2464,17 +2483,6 @@ M: Thomas Renninger <trenn@suse.de>
|
|||
S: Maintained
|
||||
F: tools/power/cpupower/
|
||||
|
||||
CPUSETS
|
||||
M: Li Zefan <lizefan@huawei.com>
|
||||
L: cgroups@vger.kernel.org
|
||||
W: http://www.bullopensource.org/cpuset/
|
||||
W: http://oss.sgi.com/projects/cpusets/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
|
||||
S: Maintained
|
||||
F: Documentation/cgroups/cpusets.txt
|
||||
F: include/linux/cpuset.h
|
||||
F: kernel/cpuset.c
|
||||
|
||||
CRAMFS FILESYSTEM
|
||||
W: http://sourceforge.net/projects/cramfs/
|
||||
S: Orphan / Obsolete
|
||||
|
@ -5757,17 +5765,6 @@ F: include/linux/memory_hotplug.h
|
|||
F: include/linux/vmalloc.h
|
||||
F: mm/
|
||||
|
||||
MEMORY RESOURCE CONTROLLER
|
||||
M: Johannes Weiner <hannes@cmpxchg.org>
|
||||
M: Michal Hocko <mhocko@suse.cz>
|
||||
M: Balbir Singh <bsingharora@gmail.com>
|
||||
M: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
|
||||
L: cgroups@vger.kernel.org
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
F: mm/memcontrol.c
|
||||
F: mm/page_cgroup.c
|
||||
|
||||
MEMORY TECHNOLOGY DEVICES (MTD)
|
||||
M: David Woodhouse <dwmw2@infradead.org>
|
||||
M: Brian Norris <computersforpeace@gmail.com>
|
||||
|
|
|
@ -1971,7 +1971,7 @@ int bio_associate_current(struct bio *bio)
|
|||
/* associate blkcg if exists */
|
||||
rcu_read_lock();
|
||||
css = task_css(current, blkio_cgrp_id);
|
||||
if (css && css_tryget(css))
|
||||
if (css && css_tryget_online(css))
|
||||
bio->bi_css = css;
|
||||
rcu_read_unlock();
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
|
|||
lockdep_assert_held(q->queue_lock);
|
||||
|
||||
/* blkg holds a reference to blkcg */
|
||||
if (!css_tryget(&blkcg->css)) {
|
||||
if (!css_tryget_online(&blkcg->css)) {
|
||||
ret = -EINVAL;
|
||||
goto err_free_blkg;
|
||||
}
|
||||
|
|
|
@ -204,7 +204,7 @@ static inline struct blkcg *bio_blkcg(struct bio *bio)
|
|||
*/
|
||||
static inline struct blkcg *blkcg_parent(struct blkcg *blkcg)
|
||||
{
|
||||
return css_to_blkcg(css_parent(&blkcg->css));
|
||||
return css_to_blkcg(blkcg->css.parent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1346,10 +1346,10 @@ static int tg_print_conf_uint(struct seq_file *sf, void *v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tg_set_conf(struct cgroup_subsys_state *css, struct cftype *cft,
|
||||
const char *buf, bool is_u64)
|
||||
static ssize_t tg_set_conf(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off, bool is_u64)
|
||||
{
|
||||
struct blkcg *blkcg = css_to_blkcg(css);
|
||||
struct blkcg *blkcg = css_to_blkcg(of_css(of));
|
||||
struct blkg_conf_ctx ctx;
|
||||
struct throtl_grp *tg;
|
||||
struct throtl_service_queue *sq;
|
||||
|
@ -1368,9 +1368,9 @@ static int tg_set_conf(struct cgroup_subsys_state *css, struct cftype *cft,
|
|||
ctx.v = -1;
|
||||
|
||||
if (is_u64)
|
||||
*(u64 *)((void *)tg + cft->private) = ctx.v;
|
||||
*(u64 *)((void *)tg + of_cft(of)->private) = ctx.v;
|
||||
else
|
||||
*(unsigned int *)((void *)tg + cft->private) = ctx.v;
|
||||
*(unsigned int *)((void *)tg + of_cft(of)->private) = ctx.v;
|
||||
|
||||
throtl_log(&tg->service_queue,
|
||||
"limit change rbps=%llu wbps=%llu riops=%u wiops=%u",
|
||||
|
@ -1404,19 +1404,19 @@ static int tg_set_conf(struct cgroup_subsys_state *css, struct cftype *cft,
|
|||
}
|
||||
|
||||
blkg_conf_finish(&ctx);
|
||||
return 0;
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static int tg_set_conf_u64(struct cgroup_subsys_state *css, struct cftype *cft,
|
||||
char *buf)
|
||||
static ssize_t tg_set_conf_u64(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
return tg_set_conf(css, cft, buf, true);
|
||||
return tg_set_conf(of, buf, nbytes, off, true);
|
||||
}
|
||||
|
||||
static int tg_set_conf_uint(struct cgroup_subsys_state *css, struct cftype *cft,
|
||||
char *buf)
|
||||
static ssize_t tg_set_conf_uint(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
return tg_set_conf(css, cft, buf, false);
|
||||
return tg_set_conf(of, buf, nbytes, off, false);
|
||||
}
|
||||
|
||||
static struct cftype throtl_files[] = {
|
||||
|
@ -1424,25 +1424,25 @@ static struct cftype throtl_files[] = {
|
|||
.name = "throttle.read_bps_device",
|
||||
.private = offsetof(struct throtl_grp, bps[READ]),
|
||||
.seq_show = tg_print_conf_u64,
|
||||
.write_string = tg_set_conf_u64,
|
||||
.write = tg_set_conf_u64,
|
||||
},
|
||||
{
|
||||
.name = "throttle.write_bps_device",
|
||||
.private = offsetof(struct throtl_grp, bps[WRITE]),
|
||||
.seq_show = tg_print_conf_u64,
|
||||
.write_string = tg_set_conf_u64,
|
||||
.write = tg_set_conf_u64,
|
||||
},
|
||||
{
|
||||
.name = "throttle.read_iops_device",
|
||||
.private = offsetof(struct throtl_grp, iops[READ]),
|
||||
.seq_show = tg_print_conf_uint,
|
||||
.write_string = tg_set_conf_uint,
|
||||
.write = tg_set_conf_uint,
|
||||
},
|
||||
{
|
||||
.name = "throttle.write_iops_device",
|
||||
.private = offsetof(struct throtl_grp, iops[WRITE]),
|
||||
.seq_show = tg_print_conf_uint,
|
||||
.write_string = tg_set_conf_uint,
|
||||
.write = tg_set_conf_uint,
|
||||
},
|
||||
{
|
||||
.name = "throttle.io_service_bytes",
|
||||
|
|
|
@ -1670,11 +1670,11 @@ static int cfq_print_leaf_weight(struct seq_file *sf, void *v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __cfqg_set_weight_device(struct cgroup_subsys_state *css,
|
||||
struct cftype *cft, const char *buf,
|
||||
bool is_leaf_weight)
|
||||
static ssize_t __cfqg_set_weight_device(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off,
|
||||
bool is_leaf_weight)
|
||||
{
|
||||
struct blkcg *blkcg = css_to_blkcg(css);
|
||||
struct blkcg *blkcg = css_to_blkcg(of_css(of));
|
||||
struct blkg_conf_ctx ctx;
|
||||
struct cfq_group *cfqg;
|
||||
int ret;
|
||||
|
@ -1697,19 +1697,19 @@ static int __cfqg_set_weight_device(struct cgroup_subsys_state *css,
|
|||
}
|
||||
|
||||
blkg_conf_finish(&ctx);
|
||||
return ret;
|
||||
return ret ?: nbytes;
|
||||
}
|
||||
|
||||
static int cfqg_set_weight_device(struct cgroup_subsys_state *css,
|
||||
struct cftype *cft, char *buf)
|
||||
static ssize_t cfqg_set_weight_device(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
return __cfqg_set_weight_device(css, cft, buf, false);
|
||||
return __cfqg_set_weight_device(of, buf, nbytes, off, false);
|
||||
}
|
||||
|
||||
static int cfqg_set_leaf_weight_device(struct cgroup_subsys_state *css,
|
||||
struct cftype *cft, char *buf)
|
||||
static ssize_t cfqg_set_leaf_weight_device(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
return __cfqg_set_weight_device(css, cft, buf, true);
|
||||
return __cfqg_set_weight_device(of, buf, nbytes, off, true);
|
||||
}
|
||||
|
||||
static int __cfq_set_weight(struct cgroup_subsys_state *css, struct cftype *cft,
|
||||
|
@ -1837,7 +1837,7 @@ static struct cftype cfq_blkcg_files[] = {
|
|||
.name = "weight_device",
|
||||
.flags = CFTYPE_ONLY_ON_ROOT,
|
||||
.seq_show = cfqg_print_leaf_weight_device,
|
||||
.write_string = cfqg_set_leaf_weight_device,
|
||||
.write = cfqg_set_leaf_weight_device,
|
||||
},
|
||||
{
|
||||
.name = "weight",
|
||||
|
@ -1851,7 +1851,7 @@ static struct cftype cfq_blkcg_files[] = {
|
|||
.name = "weight_device",
|
||||
.flags = CFTYPE_NOT_ON_ROOT,
|
||||
.seq_show = cfqg_print_weight_device,
|
||||
.write_string = cfqg_set_weight_device,
|
||||
.write = cfqg_set_weight_device,
|
||||
},
|
||||
{
|
||||
.name = "weight",
|
||||
|
@ -1863,7 +1863,7 @@ static struct cftype cfq_blkcg_files[] = {
|
|||
{
|
||||
.name = "leaf_weight_device",
|
||||
.seq_show = cfqg_print_leaf_weight_device,
|
||||
.write_string = cfqg_set_leaf_weight_device,
|
||||
.write = cfqg_set_leaf_weight_device,
|
||||
},
|
||||
{
|
||||
.name = "leaf_weight",
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/percpu-refcount.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/kernfs.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#ifdef CONFIG_CGROUPS
|
||||
|
||||
|
@ -47,21 +48,45 @@ enum cgroup_subsys_id {
|
|||
};
|
||||
#undef SUBSYS
|
||||
|
||||
/* Per-subsystem/per-cgroup state maintained by the system. */
|
||||
/*
|
||||
* Per-subsystem/per-cgroup state maintained by the system. This is the
|
||||
* fundamental structural building block that controllers deal with.
|
||||
*
|
||||
* Fields marked with "PI:" are public and immutable and may be accessed
|
||||
* directly without synchronization.
|
||||
*/
|
||||
struct cgroup_subsys_state {
|
||||
/* the cgroup that this css is attached to */
|
||||
/* PI: the cgroup that this css is attached to */
|
||||
struct cgroup *cgroup;
|
||||
|
||||
/* the cgroup subsystem that this css is attached to */
|
||||
/* PI: the cgroup subsystem that this css is attached to */
|
||||
struct cgroup_subsys *ss;
|
||||
|
||||
/* reference count - access via css_[try]get() and css_put() */
|
||||
struct percpu_ref refcnt;
|
||||
|
||||
/* the parent css */
|
||||
/* PI: the parent css */
|
||||
struct cgroup_subsys_state *parent;
|
||||
|
||||
unsigned long flags;
|
||||
/* siblings list anchored at the parent's ->children */
|
||||
struct list_head sibling;
|
||||
struct list_head children;
|
||||
|
||||
/*
|
||||
* PI: Subsys-unique ID. 0 is unused and root is always 1. The
|
||||
* matching css can be looked up using css_from_id().
|
||||
*/
|
||||
int id;
|
||||
|
||||
unsigned int flags;
|
||||
|
||||
/*
|
||||
* Monotonically increasing unique serial number which defines a
|
||||
* uniform order among all csses. It's guaranteed that all
|
||||
* ->children lists are in the ascending order of ->serial_nr and
|
||||
* used to allow interrupting and resuming iterations.
|
||||
*/
|
||||
u64 serial_nr;
|
||||
|
||||
/* percpu_ref killing and RCU release */
|
||||
struct rcu_head rcu_head;
|
||||
|
@ -70,8 +95,9 @@ struct cgroup_subsys_state {
|
|||
|
||||
/* bits in struct cgroup_subsys_state flags field */
|
||||
enum {
|
||||
CSS_ROOT = (1 << 0), /* this CSS is the root of the subsystem */
|
||||
CSS_NO_REF = (1 << 0), /* no reference counting for this css */
|
||||
CSS_ONLINE = (1 << 1), /* between ->css_online() and ->css_offline() */
|
||||
CSS_RELEASED = (1 << 2), /* refcnt reached zero, released */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -82,8 +108,7 @@ enum {
|
|||
*/
|
||||
static inline void css_get(struct cgroup_subsys_state *css)
|
||||
{
|
||||
/* We don't need to reference count the root state */
|
||||
if (!(css->flags & CSS_ROOT))
|
||||
if (!(css->flags & CSS_NO_REF))
|
||||
percpu_ref_get(&css->refcnt);
|
||||
}
|
||||
|
||||
|
@ -91,35 +116,51 @@ static inline void css_get(struct cgroup_subsys_state *css)
|
|||
* css_tryget - try to obtain a reference on the specified css
|
||||
* @css: target css
|
||||
*
|
||||
* Obtain a reference on @css if it's alive. The caller naturally needs to
|
||||
* ensure that @css is accessible but doesn't have to be holding a
|
||||
* Obtain a reference on @css unless it already has reached zero and is
|
||||
* being released. This function doesn't care whether @css is on or
|
||||
* offline. The caller naturally needs to ensure that @css is accessible
|
||||
* but doesn't have to be holding a reference on it - IOW, RCU protected
|
||||
* access is good enough for this function. Returns %true if a reference
|
||||
* count was successfully obtained; %false otherwise.
|
||||
*/
|
||||
static inline bool css_tryget(struct cgroup_subsys_state *css)
|
||||
{
|
||||
if (!(css->flags & CSS_NO_REF))
|
||||
return percpu_ref_tryget(&css->refcnt);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* css_tryget_online - try to obtain a reference on the specified css if online
|
||||
* @css: target css
|
||||
*
|
||||
* Obtain a reference on @css if it's online. The caller naturally needs
|
||||
* to ensure that @css is accessible but doesn't have to be holding a
|
||||
* reference on it - IOW, RCU protected access is good enough for this
|
||||
* function. Returns %true if a reference count was successfully obtained;
|
||||
* %false otherwise.
|
||||
*/
|
||||
static inline bool css_tryget(struct cgroup_subsys_state *css)
|
||||
static inline bool css_tryget_online(struct cgroup_subsys_state *css)
|
||||
{
|
||||
if (css->flags & CSS_ROOT)
|
||||
return true;
|
||||
return percpu_ref_tryget_live(&css->refcnt);
|
||||
if (!(css->flags & CSS_NO_REF))
|
||||
return percpu_ref_tryget_live(&css->refcnt);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* css_put - put a css reference
|
||||
* @css: target css
|
||||
*
|
||||
* Put a reference obtained via css_get() and css_tryget().
|
||||
* Put a reference obtained via css_get() and css_tryget_online().
|
||||
*/
|
||||
static inline void css_put(struct cgroup_subsys_state *css)
|
||||
{
|
||||
if (!(css->flags & CSS_ROOT))
|
||||
if (!(css->flags & CSS_NO_REF))
|
||||
percpu_ref_put(&css->refcnt);
|
||||
}
|
||||
|
||||
/* bits in struct cgroup flags field */
|
||||
enum {
|
||||
/* Control Group is dead */
|
||||
CGRP_DEAD,
|
||||
/*
|
||||
* Control Group has previously had a child cgroup or a task,
|
||||
* but no longer (only if CGRP_NOTIFY_ON_RELEASE is set)
|
||||
|
@ -133,48 +174,37 @@ 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 {
|
||||
/* self css with NULL ->ss, points back to this cgroup */
|
||||
struct cgroup_subsys_state self;
|
||||
|
||||
unsigned long flags; /* "unsigned long" so bitops work */
|
||||
|
||||
/*
|
||||
* idr allocated in-hierarchy ID.
|
||||
*
|
||||
* The ID of the root cgroup is always 0, and a new cgroup
|
||||
* will be assigned with a smallest available ID.
|
||||
* ID 0 is not used, the ID of the root cgroup is always 1, and a
|
||||
* new cgroup will be assigned with a smallest available ID.
|
||||
*
|
||||
* Allocating/Removing ID must be protected by cgroup_mutex.
|
||||
*/
|
||||
int id;
|
||||
|
||||
/* the number of attached css's */
|
||||
int nr_css;
|
||||
|
||||
atomic_t refcnt;
|
||||
|
||||
/*
|
||||
* We link our 'sibling' struct into our parent's 'children'.
|
||||
* Our children link their 'sibling' into our 'children'.
|
||||
* If this cgroup contains any tasks, it contributes one to
|
||||
* populated_cnt. All children with non-zero popuplated_cnt of
|
||||
* their own contribute one. The count is zero iff there's no task
|
||||
* in this cgroup or its subtree.
|
||||
*/
|
||||
struct list_head sibling; /* my parent's children */
|
||||
struct list_head children; /* my children */
|
||||
int populated_cnt;
|
||||
|
||||
struct cgroup *parent; /* my parent */
|
||||
struct kernfs_node *kn; /* cgroup kernfs entry */
|
||||
struct kernfs_node *populated_kn; /* kn for "cgroup.subtree_populated" */
|
||||
|
||||
/*
|
||||
* Monotonically increasing unique serial number which defines a
|
||||
* uniform order among all cgroups. It's guaranteed that all
|
||||
* ->children lists are in the ascending order of ->serial_nr.
|
||||
* It's used to allow interrupting and resuming iterations.
|
||||
*/
|
||||
u64 serial_nr;
|
||||
|
||||
/* The bitmask of subsystems attached to this cgroup */
|
||||
unsigned long subsys_mask;
|
||||
/* the bitmask of subsystems enabled on the child cgroups */
|
||||
unsigned int child_subsys_mask;
|
||||
|
||||
/* Private pointers for each registered subsystem */
|
||||
struct cgroup_subsys_state __rcu *subsys[CGROUP_SUBSYS_COUNT];
|
||||
|
@ -187,6 +217,15 @@ struct cgroup {
|
|||
*/
|
||||
struct list_head cset_links;
|
||||
|
||||
/*
|
||||
* On the default hierarchy, a css_set for a cgroup with some
|
||||
* susbsys disabled will point to css's which are associated with
|
||||
* the closest ancestor which has the subsys enabled. The
|
||||
* following lists all css_sets which point to this cgroup's css
|
||||
* for the given subsystem.
|
||||
*/
|
||||
struct list_head e_csets[CGROUP_SUBSYS_COUNT];
|
||||
|
||||
/*
|
||||
* Linked list running through all cgroups that can
|
||||
* potentially be reaped by the release agent. Protected by
|
||||
|
@ -201,12 +240,8 @@ struct cgroup {
|
|||
struct list_head pidlists;
|
||||
struct mutex pidlist_mutex;
|
||||
|
||||
/* dummy css with NULL ->ss, points back to this cgroup */
|
||||
struct cgroup_subsys_state dummy_css;
|
||||
|
||||
/* For css percpu_ref killing and RCU-protected deletion */
|
||||
struct rcu_head rcu_head;
|
||||
struct work_struct destroy_work;
|
||||
/* used to wait for offlining of csses */
|
||||
wait_queue_head_t offline_waitq;
|
||||
};
|
||||
|
||||
#define MAX_CGROUP_ROOT_NAMELEN 64
|
||||
|
@ -250,6 +285,12 @@ enum {
|
|||
*
|
||||
* - "cgroup.clone_children" is removed.
|
||||
*
|
||||
* - "cgroup.subtree_populated" is available. Its value is 0 if
|
||||
* the cgroup and its descendants contain no task; otherwise, 1.
|
||||
* The file also generates kernfs notification which can be
|
||||
* monitored through poll and [di]notify when the value of the
|
||||
* file changes.
|
||||
*
|
||||
* - If mount is requested with sane_behavior but without any
|
||||
* subsystem, the default unified hierarchy is mounted.
|
||||
*
|
||||
|
@ -264,6 +305,8 @@ enum {
|
|||
* the flag is not created.
|
||||
*
|
||||
* - blkcg: blk-throttle becomes properly hierarchical.
|
||||
*
|
||||
* - debug: disallowed on the default hierarchy.
|
||||
*/
|
||||
CGRP_ROOT_SANE_BEHAVIOR = (1 << 0),
|
||||
|
||||
|
@ -282,6 +325,9 @@ enum {
|
|||
struct cgroup_root {
|
||||
struct kernfs_root *kf_root;
|
||||
|
||||
/* The bitmask of subsystems attached to this hierarchy */
|
||||
unsigned int subsys_mask;
|
||||
|
||||
/* Unique id for this hierarchy. */
|
||||
int hierarchy_id;
|
||||
|
||||
|
@ -295,7 +341,7 @@ struct cgroup_root {
|
|||
struct list_head root_list;
|
||||
|
||||
/* Hierarchy-specific flags */
|
||||
unsigned long flags;
|
||||
unsigned int flags;
|
||||
|
||||
/* IDs for cgroups in this hierarchy */
|
||||
struct idr cgroup_idr;
|
||||
|
@ -342,6 +388,9 @@ struct css_set {
|
|||
*/
|
||||
struct list_head cgrp_links;
|
||||
|
||||
/* the default cgroup associated with this css_set */
|
||||
struct cgroup *dfl_cgrp;
|
||||
|
||||
/*
|
||||
* Set of subsystem states, one for each subsystem. This array is
|
||||
* immutable after creation apart from the init_css_set during
|
||||
|
@ -366,6 +415,15 @@ struct css_set {
|
|||
struct cgroup *mg_src_cgrp;
|
||||
struct css_set *mg_dst_cset;
|
||||
|
||||
/*
|
||||
* On the default hierarhcy, ->subsys[ssid] may point to a css
|
||||
* attached to an ancestor instead of the cgroup this css_set is
|
||||
* associated with. The following node is anchored at
|
||||
* ->subsys[ssid]->cgroup->e_csets[ssid] and provides a way to
|
||||
* iterate through all css's attached to a given cgroup.
|
||||
*/
|
||||
struct list_head e_cset_node[CGROUP_SUBSYS_COUNT];
|
||||
|
||||
/* For RCU-protected deletion */
|
||||
struct rcu_head rcu_head;
|
||||
};
|
||||
|
@ -405,8 +463,7 @@ struct cftype {
|
|||
|
||||
/*
|
||||
* The maximum length of string, excluding trailing nul, that can
|
||||
* be passed to write_string. If < PAGE_SIZE-1, PAGE_SIZE-1 is
|
||||
* assumed.
|
||||
* be passed to write. If < PAGE_SIZE-1, PAGE_SIZE-1 is assumed.
|
||||
*/
|
||||
size_t max_write_len;
|
||||
|
||||
|
@ -453,19 +510,13 @@ struct cftype {
|
|||
s64 val);
|
||||
|
||||
/*
|
||||
* write_string() is passed a nul-terminated kernelspace
|
||||
* buffer of maximum length determined by max_write_len.
|
||||
* Returns 0 or -ve error code.
|
||||
* write() is the generic write callback which maps directly to
|
||||
* kernfs write operation and overrides all other operations.
|
||||
* Maximum write size is determined by ->max_write_len. Use
|
||||
* of_css/cft() to access the associated css and cft.
|
||||
*/
|
||||
int (*write_string)(struct cgroup_subsys_state *css, struct cftype *cft,
|
||||
char *buffer);
|
||||
/*
|
||||
* trigger() callback can be used to get some kick from the
|
||||
* userspace, when the actual string written is not important
|
||||
* at all. The private field can be used to determine the
|
||||
* kick type for multiplexing.
|
||||
*/
|
||||
int (*trigger)(struct cgroup_subsys_state *css, unsigned int event);
|
||||
ssize_t (*write)(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off);
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
struct lock_class_key lockdep_key;
|
||||
|
@ -504,14 +555,24 @@ static inline ino_t cgroup_ino(struct cgroup *cgrp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline struct cftype *seq_cft(struct seq_file *seq)
|
||||
/* cft/css accessors for cftype->write() operation */
|
||||
static inline struct cftype *of_cft(struct kernfs_open_file *of)
|
||||
{
|
||||
struct kernfs_open_file *of = seq->private;
|
||||
|
||||
return of->kn->priv;
|
||||
}
|
||||
|
||||
struct cgroup_subsys_state *seq_css(struct seq_file *seq);
|
||||
struct cgroup_subsys_state *of_css(struct kernfs_open_file *of);
|
||||
|
||||
/* cft/css accessors for cftype->seq_*() operations */
|
||||
static inline struct cftype *seq_cft(struct seq_file *seq)
|
||||
{
|
||||
return of_cft(seq->private);
|
||||
}
|
||||
|
||||
static inline struct cgroup_subsys_state *seq_css(struct seq_file *seq)
|
||||
{
|
||||
return of_css(seq->private);
|
||||
}
|
||||
|
||||
/*
|
||||
* Name / path handling functions. All are thin wrappers around the kernfs
|
||||
|
@ -612,6 +673,9 @@ struct cgroup_subsys {
|
|||
/* link to parent, protected by cgroup_lock() */
|
||||
struct cgroup_root *root;
|
||||
|
||||
/* idr for css->id */
|
||||
struct idr css_idr;
|
||||
|
||||
/*
|
||||
* List of cftypes. Each entry is the first entry of an array
|
||||
* terminated by zero length name.
|
||||
|
@ -626,19 +690,6 @@ struct cgroup_subsys {
|
|||
#include <linux/cgroup_subsys.h>
|
||||
#undef SUBSYS
|
||||
|
||||
/**
|
||||
* css_parent - find the parent css
|
||||
* @css: the target cgroup_subsys_state
|
||||
*
|
||||
* Return the parent css of @css. This function is guaranteed to return
|
||||
* non-NULL parent as long as @css isn't the root.
|
||||
*/
|
||||
static inline
|
||||
struct cgroup_subsys_state *css_parent(struct cgroup_subsys_state *css)
|
||||
{
|
||||
return css->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* task_css_set_check - obtain a task's css_set with extra access conditions
|
||||
* @task: the task to obtain css_set for
|
||||
|
@ -731,14 +782,14 @@ struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss);
|
|||
* @pos: the css * to use as the loop cursor
|
||||
* @parent: css whose children to walk
|
||||
*
|
||||
* Walk @parent's children. Must be called under rcu_read_lock(). A child
|
||||
* css which hasn't finished ->css_online() or already has finished
|
||||
* ->css_offline() may show up during traversal and it's each subsystem's
|
||||
* responsibility to verify that each @pos is alive.
|
||||
* Walk @parent's children. Must be called under rcu_read_lock().
|
||||
*
|
||||
* If a subsystem synchronizes against the parent in its ->css_online() and
|
||||
* before starting iterating, a css which finished ->css_online() is
|
||||
* guaranteed to be visible in the future iterations.
|
||||
* If a subsystem synchronizes ->css_online() and the start of iteration, a
|
||||
* css which finished ->css_online() is guaranteed to be visible in the
|
||||
* future iterations and will stay visible until the last reference is put.
|
||||
* A css which hasn't finished ->css_online() or already finished
|
||||
* ->css_offline() may show up during traversal. It's each subsystem's
|
||||
* responsibility to synchronize against on/offlining.
|
||||
*
|
||||
* It is allowed to temporarily drop RCU read lock during iteration. The
|
||||
* caller is responsible for ensuring that @pos remains accessible until
|
||||
|
@ -761,17 +812,16 @@ css_rightmost_descendant(struct cgroup_subsys_state *pos);
|
|||
* @root: css whose descendants to walk
|
||||
*
|
||||
* Walk @root's descendants. @root is included in the iteration and the
|
||||
* first node to be visited. Must be called under rcu_read_lock(). A
|
||||
* descendant css which hasn't finished ->css_online() or already has
|
||||
* finished ->css_offline() may show up during traversal and it's each
|
||||
* subsystem's responsibility to verify that each @pos is alive.
|
||||
* first node to be visited. Must be called under rcu_read_lock().
|
||||
*
|
||||
* If a subsystem synchronizes against the parent in its ->css_online() and
|
||||
* before starting iterating, and synchronizes against @pos on each
|
||||
* iteration, any descendant css which finished ->css_online() is
|
||||
* guaranteed to be visible in the future iterations.
|
||||
* If a subsystem synchronizes ->css_online() and the start of iteration, a
|
||||
* css which finished ->css_online() is guaranteed to be visible in the
|
||||
* future iterations and will stay visible until the last reference is put.
|
||||
* A css which hasn't finished ->css_online() or already finished
|
||||
* ->css_offline() may show up during traversal. It's each subsystem's
|
||||
* responsibility to synchronize against on/offlining.
|
||||
*
|
||||
* In other words, the following guarantees that a descendant can't escape
|
||||
* For example, the following guarantees that a descendant can't escape
|
||||
* state updates of its ancestors.
|
||||
*
|
||||
* my_online(@css)
|
||||
|
@ -827,18 +877,34 @@ css_next_descendant_post(struct cgroup_subsys_state *pos,
|
|||
*
|
||||
* Similar to css_for_each_descendant_pre() but performs post-order
|
||||
* traversal instead. @root is included in the iteration and the last
|
||||
* node to be visited. Note that the walk visibility guarantee described
|
||||
* in pre-order walk doesn't apply the same to post-order walks.
|
||||
* node to be visited.
|
||||
*
|
||||
* If a subsystem synchronizes ->css_online() and the start of iteration, a
|
||||
* css which finished ->css_online() is guaranteed to be visible in the
|
||||
* future iterations and will stay visible until the last reference is put.
|
||||
* A css which hasn't finished ->css_online() or already finished
|
||||
* ->css_offline() may show up during traversal. It's each subsystem's
|
||||
* responsibility to synchronize against on/offlining.
|
||||
*
|
||||
* Note that the walk visibility guarantee example described in pre-order
|
||||
* walk doesn't apply the same to post-order walks.
|
||||
*/
|
||||
#define css_for_each_descendant_post(pos, css) \
|
||||
for ((pos) = css_next_descendant_post(NULL, (css)); (pos); \
|
||||
(pos) = css_next_descendant_post((pos), (css)))
|
||||
|
||||
bool css_has_online_children(struct cgroup_subsys_state *css);
|
||||
|
||||
/* A css_task_iter should be treated as an opaque object */
|
||||
struct css_task_iter {
|
||||
struct cgroup_subsys_state *origin_css;
|
||||
struct list_head *cset_link;
|
||||
struct list_head *task;
|
||||
struct cgroup_subsys *ss;
|
||||
|
||||
struct list_head *cset_pos;
|
||||
struct list_head *cset_head;
|
||||
|
||||
struct list_head *task_pos;
|
||||
struct list_head *tasks_head;
|
||||
struct list_head *mg_tasks_head;
|
||||
};
|
||||
|
||||
void css_task_iter_start(struct cgroup_subsys_state *css,
|
||||
|
@ -849,8 +915,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 *css_tryget_from_dir(struct dentry *dentry,
|
||||
struct cgroup_subsys *ss);
|
||||
struct cgroup_subsys_state *css_tryget_online_from_dir(struct dentry *dentry,
|
||||
struct cgroup_subsys *ss);
|
||||
|
||||
#else /* !CONFIG_CGROUPS */
|
||||
|
||||
|
|
|
@ -7,10 +7,6 @@
|
|||
SUBSYS(cpuset)
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_CGROUP_DEBUG)
|
||||
SUBSYS(debug)
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_CGROUP_SCHED)
|
||||
SUBSYS(cpu)
|
||||
#endif
|
||||
|
@ -50,6 +46,13 @@ SUBSYS(net_prio)
|
|||
#if IS_ENABLED(CONFIG_CGROUP_HUGETLB)
|
||||
SUBSYS(hugetlb)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following subsystems are not supported on the default hierarchy.
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_CGROUP_DEBUG)
|
||||
SUBSYS(debug)
|
||||
#endif
|
||||
/*
|
||||
* DO NOT ADD ANY SUBSYSTEM WITHOUT EXPLICIT ACKS FROM CGROUP MAINTAINERS.
|
||||
*/
|
||||
|
|
1835
kernel/cgroup.c
1835
kernel/cgroup.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -59,7 +59,7 @@ static inline struct freezer *task_freezer(struct task_struct *task)
|
|||
|
||||
static struct freezer *parent_freezer(struct freezer *freezer)
|
||||
{
|
||||
return css_freezer(css_parent(&freezer->css));
|
||||
return css_freezer(freezer->css.parent);
|
||||
}
|
||||
|
||||
bool cgroup_freezing(struct task_struct *task)
|
||||
|
@ -73,10 +73,6 @@ bool cgroup_freezing(struct task_struct *task)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* cgroups_write_string() limits the size of freezer state strings to
|
||||
* CGROUP_LOCAL_BUFFER_SIZE
|
||||
*/
|
||||
static const char *freezer_state_strs(unsigned int state)
|
||||
{
|
||||
if (state & CGROUP_FROZEN)
|
||||
|
@ -304,7 +300,7 @@ static int freezer_read(struct seq_file *m, void *v)
|
|||
|
||||
/* update states bottom-up */
|
||||
css_for_each_descendant_post(pos, css) {
|
||||
if (!css_tryget(pos))
|
||||
if (!css_tryget_online(pos))
|
||||
continue;
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -404,7 +400,7 @@ static void freezer_change_state(struct freezer *freezer, bool freeze)
|
|||
struct freezer *pos_f = css_freezer(pos);
|
||||
struct freezer *parent = parent_freezer(pos_f);
|
||||
|
||||
if (!css_tryget(pos))
|
||||
if (!css_tryget_online(pos))
|
||||
continue;
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -423,20 +419,22 @@ static void freezer_change_state(struct freezer *freezer, bool freeze)
|
|||
mutex_unlock(&freezer_mutex);
|
||||
}
|
||||
|
||||
static int freezer_write(struct cgroup_subsys_state *css, struct cftype *cft,
|
||||
char *buffer)
|
||||
static ssize_t freezer_write(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
bool freeze;
|
||||
|
||||
if (strcmp(buffer, freezer_state_strs(0)) == 0)
|
||||
buf = strstrip(buf);
|
||||
|
||||
if (strcmp(buf, freezer_state_strs(0)) == 0)
|
||||
freeze = false;
|
||||
else if (strcmp(buffer, freezer_state_strs(CGROUP_FROZEN)) == 0)
|
||||
else if (strcmp(buf, freezer_state_strs(CGROUP_FROZEN)) == 0)
|
||||
freeze = true;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
freezer_change_state(css_freezer(css), freeze);
|
||||
return 0;
|
||||
freezer_change_state(css_freezer(of_css(of)), freeze);
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static u64 freezer_self_freezing_read(struct cgroup_subsys_state *css,
|
||||
|
@ -460,7 +458,7 @@ static struct cftype files[] = {
|
|||
.name = "state",
|
||||
.flags = CFTYPE_NOT_ON_ROOT,
|
||||
.seq_show = freezer_read,
|
||||
.write_string = freezer_write,
|
||||
.write = freezer_write,
|
||||
},
|
||||
{
|
||||
.name = "self_freezing",
|
||||
|
|
|
@ -119,7 +119,7 @@ static inline struct cpuset *task_cs(struct task_struct *task)
|
|||
|
||||
static inline struct cpuset *parent_cs(struct cpuset *cs)
|
||||
{
|
||||
return css_cs(css_parent(&cs->css));
|
||||
return css_cs(cs->css.parent);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
|
@ -691,11 +691,8 @@ restart:
|
|||
if (nslot == ndoms) {
|
||||
static int warnings = 10;
|
||||
if (warnings) {
|
||||
printk(KERN_WARNING
|
||||
"rebuild_sched_domains confused:"
|
||||
" nslot %d, ndoms %d, csn %d, i %d,"
|
||||
" apn %d\n",
|
||||
nslot, ndoms, csn, i, apn);
|
||||
pr_warn("rebuild_sched_domains confused: nslot %d, ndoms %d, csn %d, i %d, apn %d\n",
|
||||
nslot, ndoms, csn, i, apn);
|
||||
warnings--;
|
||||
}
|
||||
continue;
|
||||
|
@ -870,7 +867,7 @@ static void update_tasks_cpumask_hier(struct cpuset *root_cs, bool update_root)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if (!css_tryget(&cp->css))
|
||||
if (!css_tryget_online(&cp->css))
|
||||
continue;
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -885,6 +882,7 @@ static void update_tasks_cpumask_hier(struct cpuset *root_cs, bool update_root)
|
|||
/**
|
||||
* update_cpumask - update the cpus_allowed mask of a cpuset and all tasks in it
|
||||
* @cs: the cpuset to consider
|
||||
* @trialcs: trial cpuset
|
||||
* @buf: buffer of cpu numbers written to this cpuset
|
||||
*/
|
||||
static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
|
||||
|
@ -1105,7 +1103,7 @@ static void update_tasks_nodemask_hier(struct cpuset *root_cs, bool update_root)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if (!css_tryget(&cp->css))
|
||||
if (!css_tryget_online(&cp->css))
|
||||
continue;
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -1600,13 +1598,15 @@ out_unlock:
|
|||
/*
|
||||
* Common handling for a write to a "cpus" or "mems" file.
|
||||
*/
|
||||
static int cpuset_write_resmask(struct cgroup_subsys_state *css,
|
||||
struct cftype *cft, char *buf)
|
||||
static ssize_t cpuset_write_resmask(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
struct cpuset *cs = css_cs(css);
|
||||
struct cpuset *cs = css_cs(of_css(of));
|
||||
struct cpuset *trialcs;
|
||||
int retval = -ENODEV;
|
||||
|
||||
buf = strstrip(buf);
|
||||
|
||||
/*
|
||||
* CPU or memory hotunplug may leave @cs w/o any execution
|
||||
* resources, in which case the hotplug code asynchronously updates
|
||||
|
@ -1630,7 +1630,7 @@ static int cpuset_write_resmask(struct cgroup_subsys_state *css,
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
switch (cft->private) {
|
||||
switch (of_cft(of)->private) {
|
||||
case FILE_CPULIST:
|
||||
retval = update_cpumask(cs, trialcs, buf);
|
||||
break;
|
||||
|
@ -1645,7 +1645,7 @@ static int cpuset_write_resmask(struct cgroup_subsys_state *css,
|
|||
free_trial_cpuset(trialcs);
|
||||
out_unlock:
|
||||
mutex_unlock(&cpuset_mutex);
|
||||
return retval;
|
||||
return retval ?: nbytes;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1747,7 +1747,7 @@ static struct cftype files[] = {
|
|||
{
|
||||
.name = "cpus",
|
||||
.seq_show = cpuset_common_seq_show,
|
||||
.write_string = cpuset_write_resmask,
|
||||
.write = cpuset_write_resmask,
|
||||
.max_write_len = (100U + 6 * NR_CPUS),
|
||||
.private = FILE_CPULIST,
|
||||
},
|
||||
|
@ -1755,7 +1755,7 @@ static struct cftype files[] = {
|
|||
{
|
||||
.name = "mems",
|
||||
.seq_show = cpuset_common_seq_show,
|
||||
.write_string = cpuset_write_resmask,
|
||||
.write = cpuset_write_resmask,
|
||||
.max_write_len = (100U + 6 * MAX_NUMNODES),
|
||||
.private = FILE_MEMLIST,
|
||||
},
|
||||
|
@ -2011,7 +2011,7 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
|
|||
parent = parent_cs(parent);
|
||||
|
||||
if (cgroup_transfer_tasks(parent->css.cgroup, cs->css.cgroup)) {
|
||||
printk(KERN_ERR "cpuset: failed to transfer tasks out of empty cpuset ");
|
||||
pr_err("cpuset: failed to transfer tasks out of empty cpuset ");
|
||||
pr_cont_cgroup_name(cs->css.cgroup);
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
@ -2149,7 +2149,7 @@ static void cpuset_hotplug_workfn(struct work_struct *work)
|
|||
|
||||
rcu_read_lock();
|
||||
cpuset_for_each_descendant_pre(cs, pos_css, &top_cpuset) {
|
||||
if (cs == &top_cpuset || !css_tryget(&cs->css))
|
||||
if (cs == &top_cpuset || !css_tryget_online(&cs->css))
|
||||
continue;
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -2530,7 +2530,7 @@ int cpuset_mems_allowed_intersects(const struct task_struct *tsk1,
|
|||
|
||||
/**
|
||||
* cpuset_print_task_mems_allowed - prints task's cpuset and mems_allowed
|
||||
* @task: pointer to task_struct of some task.
|
||||
* @tsk: pointer to task_struct of some task.
|
||||
*
|
||||
* Description: Prints @task's name, cpuset name, and cached copy of its
|
||||
* mems_allowed to the kernel log.
|
||||
|
@ -2548,7 +2548,7 @@ void cpuset_print_task_mems_allowed(struct task_struct *tsk)
|
|||
cgrp = task_cs(tsk)->css.cgroup;
|
||||
nodelist_scnprintf(cpuset_nodelist, CPUSET_NODELIST_LEN,
|
||||
tsk->mems_allowed);
|
||||
printk(KERN_INFO "%s cpuset=", tsk->comm);
|
||||
pr_info("%s cpuset=", tsk->comm);
|
||||
pr_cont_cgroup_name(cgrp);
|
||||
pr_cont(" mems_allowed=%s\n", cpuset_nodelist);
|
||||
|
||||
|
@ -2640,10 +2640,10 @@ out:
|
|||
/* Display task mems_allowed in /proc/<pid>/status file. */
|
||||
void cpuset_task_status_allowed(struct seq_file *m, struct task_struct *task)
|
||||
{
|
||||
seq_printf(m, "Mems_allowed:\t");
|
||||
seq_puts(m, "Mems_allowed:\t");
|
||||
seq_nodemask(m, &task->mems_allowed);
|
||||
seq_printf(m, "\n");
|
||||
seq_printf(m, "Mems_allowed_list:\t");
|
||||
seq_puts(m, "\n");
|
||||
seq_puts(m, "Mems_allowed_list:\t");
|
||||
seq_nodemask_list(m, &task->mems_allowed);
|
||||
seq_printf(m, "\n");
|
||||
seq_puts(m, "\n");
|
||||
}
|
||||
|
|
|
@ -608,7 +608,8 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
|
|||
if (!f.file)
|
||||
return -EBADF;
|
||||
|
||||
css = css_tryget_from_dir(f.file->f_dentry, &perf_event_cgrp_subsys);
|
||||
css = css_tryget_online_from_dir(f.file->f_dentry,
|
||||
&perf_event_cgrp_subsys);
|
||||
if (IS_ERR(css)) {
|
||||
ret = PTR_ERR(css);
|
||||
goto out;
|
||||
|
|
|
@ -7669,7 +7669,7 @@ cpu_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
|
|||
static int cpu_cgroup_css_online(struct cgroup_subsys_state *css)
|
||||
{
|
||||
struct task_group *tg = css_tg(css);
|
||||
struct task_group *parent = css_tg(css_parent(css));
|
||||
struct task_group *parent = css_tg(css->parent);
|
||||
|
||||
if (parent)
|
||||
sched_online_group(tg, parent);
|
||||
|
|
|
@ -46,7 +46,7 @@ static inline struct cpuacct *task_ca(struct task_struct *tsk)
|
|||
|
||||
static inline struct cpuacct *parent_ca(struct cpuacct *ca)
|
||||
{
|
||||
return css_ca(css_parent(&ca->css));
|
||||
return css_ca(ca->css.parent);
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(u64, root_cpuacct_cpuusage);
|
||||
|
|
|
@ -52,7 +52,7 @@ static inline bool hugetlb_cgroup_is_root(struct hugetlb_cgroup *h_cg)
|
|||
static inline struct hugetlb_cgroup *
|
||||
parent_hugetlb_cgroup(struct hugetlb_cgroup *h_cg)
|
||||
{
|
||||
return hugetlb_cgroup_from_css(css_parent(&h_cg->css));
|
||||
return hugetlb_cgroup_from_css(h_cg->css.parent);
|
||||
}
|
||||
|
||||
static inline bool hugetlb_cgroup_have_usage(struct hugetlb_cgroup *h_cg)
|
||||
|
@ -181,7 +181,7 @@ int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages,
|
|||
again:
|
||||
rcu_read_lock();
|
||||
h_cg = hugetlb_cgroup_from_task(current);
|
||||
if (!css_tryget(&h_cg->css)) {
|
||||
if (!css_tryget_online(&h_cg->css)) {
|
||||
rcu_read_unlock();
|
||||
goto again;
|
||||
}
|
||||
|
@ -253,15 +253,16 @@ static u64 hugetlb_cgroup_read_u64(struct cgroup_subsys_state *css,
|
|||
return res_counter_read_u64(&h_cg->hugepage[idx], name);
|
||||
}
|
||||
|
||||
static int hugetlb_cgroup_write(struct cgroup_subsys_state *css,
|
||||
struct cftype *cft, char *buffer)
|
||||
static ssize_t hugetlb_cgroup_write(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
int idx, name, ret;
|
||||
unsigned long long val;
|
||||
struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css);
|
||||
struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(of_css(of));
|
||||
|
||||
idx = MEMFILE_IDX(cft->private);
|
||||
name = MEMFILE_ATTR(cft->private);
|
||||
buf = strstrip(buf);
|
||||
idx = MEMFILE_IDX(of_cft(of)->private);
|
||||
name = MEMFILE_ATTR(of_cft(of)->private);
|
||||
|
||||
switch (name) {
|
||||
case RES_LIMIT:
|
||||
|
@ -271,7 +272,7 @@ static int hugetlb_cgroup_write(struct cgroup_subsys_state *css,
|
|||
break;
|
||||
}
|
||||
/* This function does all necessary parse...reuse it */
|
||||
ret = res_counter_memparse_write_strategy(buffer, &val);
|
||||
ret = res_counter_memparse_write_strategy(buf, &val);
|
||||
if (ret)
|
||||
break;
|
||||
ret = res_counter_set_limit(&h_cg->hugepage[idx], val);
|
||||
|
@ -280,17 +281,17 @@ static int hugetlb_cgroup_write(struct cgroup_subsys_state *css,
|
|||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return ret ?: nbytes;
|
||||
}
|
||||
|
||||
static int hugetlb_cgroup_reset(struct cgroup_subsys_state *css,
|
||||
unsigned int event)
|
||||
static ssize_t hugetlb_cgroup_reset(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
int idx, name, ret = 0;
|
||||
struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css);
|
||||
struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(of_css(of));
|
||||
|
||||
idx = MEMFILE_IDX(event);
|
||||
name = MEMFILE_ATTR(event);
|
||||
idx = MEMFILE_IDX(of_cft(of)->private);
|
||||
name = MEMFILE_ATTR(of_cft(of)->private);
|
||||
|
||||
switch (name) {
|
||||
case RES_MAX_USAGE:
|
||||
|
@ -303,7 +304,7 @@ static int hugetlb_cgroup_reset(struct cgroup_subsys_state *css,
|
|||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return ret ?: nbytes;
|
||||
}
|
||||
|
||||
static char *mem_fmt(char *buf, int size, unsigned long hsize)
|
||||
|
@ -331,7 +332,7 @@ static void __init __hugetlb_cgroup_file_init(int idx)
|
|||
snprintf(cft->name, MAX_CFTYPE_NAME, "%s.limit_in_bytes", buf);
|
||||
cft->private = MEMFILE_PRIVATE(idx, RES_LIMIT);
|
||||
cft->read_u64 = hugetlb_cgroup_read_u64;
|
||||
cft->write_string = hugetlb_cgroup_write;
|
||||
cft->write = hugetlb_cgroup_write;
|
||||
|
||||
/* Add the usage file */
|
||||
cft = &h->cgroup_files[1];
|
||||
|
@ -343,14 +344,14 @@ static void __init __hugetlb_cgroup_file_init(int idx)
|
|||
cft = &h->cgroup_files[2];
|
||||
snprintf(cft->name, MAX_CFTYPE_NAME, "%s.max_usage_in_bytes", buf);
|
||||
cft->private = MEMFILE_PRIVATE(idx, RES_MAX_USAGE);
|
||||
cft->trigger = hugetlb_cgroup_reset;
|
||||
cft->write = hugetlb_cgroup_reset;
|
||||
cft->read_u64 = hugetlb_cgroup_read_u64;
|
||||
|
||||
/* Add the failcntfile */
|
||||
cft = &h->cgroup_files[3];
|
||||
snprintf(cft->name, MAX_CFTYPE_NAME, "%s.failcnt", buf);
|
||||
cft->private = MEMFILE_PRIVATE(idx, RES_FAILCNT);
|
||||
cft->trigger = hugetlb_cgroup_reset;
|
||||
cft->write = hugetlb_cgroup_reset;
|
||||
cft->read_u64 = hugetlb_cgroup_read_u64;
|
||||
|
||||
/* NULL terminate the last cft */
|
||||
|
|
188
mm/memcontrol.c
188
mm/memcontrol.c
|
@ -526,18 +526,14 @@ static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg)
|
|||
|
||||
static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg)
|
||||
{
|
||||
/*
|
||||
* The ID of the root cgroup is 0, but memcg treat 0 as an
|
||||
* invalid ID, so we return (cgroup_id + 1).
|
||||
*/
|
||||
return memcg->css.cgroup->id + 1;
|
||||
return memcg->css.id;
|
||||
}
|
||||
|
||||
static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
|
||||
{
|
||||
struct cgroup_subsys_state *css;
|
||||
|
||||
css = css_from_id(id - 1, &memory_cgrp_subsys);
|
||||
css = css_from_id(id, &memory_cgrp_subsys);
|
||||
return mem_cgroup_from_css(css);
|
||||
}
|
||||
|
||||
|
@ -570,7 +566,8 @@ void sock_update_memcg(struct sock *sk)
|
|||
memcg = mem_cgroup_from_task(current);
|
||||
cg_proto = sk->sk_prot->proto_cgroup(memcg);
|
||||
if (!mem_cgroup_is_root(memcg) &&
|
||||
memcg_proto_active(cg_proto) && css_tryget(&memcg->css)) {
|
||||
memcg_proto_active(cg_proto) &&
|
||||
css_tryget_online(&memcg->css)) {
|
||||
sk->sk_cgrp = cg_proto;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
@ -831,7 +828,7 @@ retry:
|
|||
*/
|
||||
__mem_cgroup_remove_exceeded(mz, mctz);
|
||||
if (!res_counter_soft_limit_excess(&mz->memcg->res) ||
|
||||
!css_tryget(&mz->memcg->css))
|
||||
!css_tryget_online(&mz->memcg->css))
|
||||
goto retry;
|
||||
done:
|
||||
return mz;
|
||||
|
@ -1073,7 +1070,7 @@ static struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
|
|||
if (unlikely(!memcg))
|
||||
memcg = root_mem_cgroup;
|
||||
}
|
||||
} while (!css_tryget(&memcg->css));
|
||||
} while (!css_tryget_online(&memcg->css));
|
||||
rcu_read_unlock();
|
||||
return memcg;
|
||||
}
|
||||
|
@ -1110,7 +1107,8 @@ skip_node:
|
|||
*/
|
||||
if (next_css) {
|
||||
if ((next_css == &root->css) ||
|
||||
((next_css->flags & CSS_ONLINE) && css_tryget(next_css)))
|
||||
((next_css->flags & CSS_ONLINE) &&
|
||||
css_tryget_online(next_css)))
|
||||
return mem_cgroup_from_css(next_css);
|
||||
|
||||
prev_css = next_css;
|
||||
|
@ -1156,7 +1154,7 @@ mem_cgroup_iter_load(struct mem_cgroup_reclaim_iter *iter,
|
|||
* would be returned all the time.
|
||||
*/
|
||||
if (position && position != root &&
|
||||
!css_tryget(&position->css))
|
||||
!css_tryget_online(&position->css))
|
||||
position = NULL;
|
||||
}
|
||||
return position;
|
||||
|
@ -1533,7 +1531,7 @@ static unsigned long mem_cgroup_margin(struct mem_cgroup *memcg)
|
|||
int mem_cgroup_swappiness(struct mem_cgroup *memcg)
|
||||
{
|
||||
/* root ? */
|
||||
if (mem_cgroup_disabled() || !css_parent(&memcg->css))
|
||||
if (mem_cgroup_disabled() || !memcg->css.parent)
|
||||
return vm_swappiness;
|
||||
|
||||
return memcg->swappiness;
|
||||
|
@ -2769,9 +2767,9 @@ static void __mem_cgroup_cancel_local_charge(struct mem_cgroup *memcg,
|
|||
|
||||
/*
|
||||
* A helper function to get mem_cgroup from ID. must be called under
|
||||
* rcu_read_lock(). The caller is responsible for calling css_tryget if
|
||||
* the mem_cgroup is used for charging. (dropping refcnt from swap can be
|
||||
* called against removed memcg.)
|
||||
* rcu_read_lock(). The caller is responsible for calling
|
||||
* css_tryget_online() if the mem_cgroup is used for charging. (dropping
|
||||
* refcnt from swap can be called against removed memcg.)
|
||||
*/
|
||||
static struct mem_cgroup *mem_cgroup_lookup(unsigned short id)
|
||||
{
|
||||
|
@ -2794,14 +2792,14 @@ struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
|
|||
lock_page_cgroup(pc);
|
||||
if (PageCgroupUsed(pc)) {
|
||||
memcg = pc->mem_cgroup;
|
||||
if (memcg && !css_tryget(&memcg->css))
|
||||
if (memcg && !css_tryget_online(&memcg->css))
|
||||
memcg = NULL;
|
||||
} else if (PageSwapCache(page)) {
|
||||
ent.val = page_private(page);
|
||||
id = lookup_swap_cgroup_id(ent);
|
||||
rcu_read_lock();
|
||||
memcg = mem_cgroup_lookup(id);
|
||||
if (memcg && !css_tryget(&memcg->css))
|
||||
if (memcg && !css_tryget_online(&memcg->css))
|
||||
memcg = NULL;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
@ -3365,7 +3363,7 @@ struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep,
|
|||
}
|
||||
|
||||
/* The corresponding put will be done in the workqueue. */
|
||||
if (!css_tryget(&memcg->css))
|
||||
if (!css_tryget_online(&memcg->css))
|
||||
goto out;
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -4125,8 +4123,8 @@ void mem_cgroup_uncharge_swap(swp_entry_t ent)
|
|||
memcg = mem_cgroup_lookup(id);
|
||||
if (memcg) {
|
||||
/*
|
||||
* We uncharge this because swap is freed.
|
||||
* This memcg can be obsolete one. We avoid calling css_tryget
|
||||
* We uncharge this because swap is freed. This memcg can
|
||||
* be obsolete one. We avoid calling css_tryget_online().
|
||||
*/
|
||||
if (!mem_cgroup_is_root(memcg))
|
||||
res_counter_uncharge(&memcg->memsw, PAGE_SIZE);
|
||||
|
@ -4711,18 +4709,28 @@ static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
|
|||
} while (usage > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test whether @memcg has children, dead or alive. Note that this
|
||||
* function doesn't care whether @memcg has use_hierarchy enabled and
|
||||
* returns %true if there are child csses according to the cgroup
|
||||
* hierarchy. Testing use_hierarchy is the caller's responsiblity.
|
||||
*/
|
||||
static inline bool memcg_has_children(struct mem_cgroup *memcg)
|
||||
{
|
||||
lockdep_assert_held(&memcg_create_mutex);
|
||||
bool ret;
|
||||
|
||||
/*
|
||||
* The lock does not prevent addition or deletion to the list
|
||||
* of children, but it prevents a new child from being
|
||||
* initialized based on this parent in css_online(), so it's
|
||||
* enough to decide whether hierarchically inherited
|
||||
* attributes can still be changed or not.
|
||||
* The lock does not prevent addition or deletion of children, but
|
||||
* it prevents a new child from being initialized based on this
|
||||
* parent in css_online(), so it's enough to decide whether
|
||||
* hierarchically inherited attributes can still be changed or not.
|
||||
*/
|
||||
return memcg->use_hierarchy &&
|
||||
!list_empty(&memcg->css.cgroup->children);
|
||||
lockdep_assert_held(&memcg_create_mutex);
|
||||
|
||||
rcu_read_lock();
|
||||
ret = css_next_child(NULL, &memcg->css);
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4734,11 +4742,6 @@ static inline bool memcg_has_children(struct mem_cgroup *memcg)
|
|||
static int mem_cgroup_force_empty(struct mem_cgroup *memcg)
|
||||
{
|
||||
int nr_retries = MEM_CGROUP_RECLAIM_RETRIES;
|
||||
struct cgroup *cgrp = memcg->css.cgroup;
|
||||
|
||||
/* returns EBUSY if there is a task or if we come here twice. */
|
||||
if (cgroup_has_tasks(cgrp) || !list_empty(&cgrp->children))
|
||||
return -EBUSY;
|
||||
|
||||
/* we call try-to-free pages for make this cgroup empty */
|
||||
lru_add_drain_all();
|
||||
|
@ -4758,20 +4761,19 @@ static int mem_cgroup_force_empty(struct mem_cgroup *memcg)
|
|||
}
|
||||
|
||||
}
|
||||
lru_add_drain();
|
||||
mem_cgroup_reparent_charges(memcg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mem_cgroup_force_empty_write(struct cgroup_subsys_state *css,
|
||||
unsigned int event)
|
||||
static ssize_t mem_cgroup_force_empty_write(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes,
|
||||
loff_t off)
|
||||
{
|
||||
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
|
||||
struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
|
||||
|
||||
if (mem_cgroup_is_root(memcg))
|
||||
return -EINVAL;
|
||||
return mem_cgroup_force_empty(memcg);
|
||||
return mem_cgroup_force_empty(memcg) ?: nbytes;
|
||||
}
|
||||
|
||||
static u64 mem_cgroup_hierarchy_read(struct cgroup_subsys_state *css,
|
||||
|
@ -4785,7 +4787,7 @@ static int mem_cgroup_hierarchy_write(struct cgroup_subsys_state *css,
|
|||
{
|
||||
int retval = 0;
|
||||
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
|
||||
struct mem_cgroup *parent_memcg = mem_cgroup_from_css(css_parent(&memcg->css));
|
||||
struct mem_cgroup *parent_memcg = mem_cgroup_from_css(memcg->css.parent);
|
||||
|
||||
mutex_lock(&memcg_create_mutex);
|
||||
|
||||
|
@ -4802,7 +4804,7 @@ static int mem_cgroup_hierarchy_write(struct cgroup_subsys_state *css,
|
|||
*/
|
||||
if ((!parent_memcg || !parent_memcg->use_hierarchy) &&
|
||||
(val == 1 || val == 0)) {
|
||||
if (list_empty(&memcg->css.cgroup->children))
|
||||
if (!memcg_has_children(memcg))
|
||||
memcg->use_hierarchy = val;
|
||||
else
|
||||
retval = -EBUSY;
|
||||
|
@ -4919,7 +4921,8 @@ static int __memcg_activate_kmem(struct mem_cgroup *memcg,
|
|||
* of course permitted.
|
||||
*/
|
||||
mutex_lock(&memcg_create_mutex);
|
||||
if (cgroup_has_tasks(memcg->css.cgroup) || memcg_has_children(memcg))
|
||||
if (cgroup_has_tasks(memcg->css.cgroup) ||
|
||||
(memcg->use_hierarchy && memcg_has_children(memcg)))
|
||||
err = -EBUSY;
|
||||
mutex_unlock(&memcg_create_mutex);
|
||||
if (err)
|
||||
|
@ -5021,17 +5024,18 @@ static int memcg_update_kmem_limit(struct mem_cgroup *memcg,
|
|||
* The user of this function is...
|
||||
* RES_LIMIT.
|
||||
*/
|
||||
static int mem_cgroup_write(struct cgroup_subsys_state *css, struct cftype *cft,
|
||||
char *buffer)
|
||||
static ssize_t mem_cgroup_write(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
|
||||
struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
|
||||
enum res_type type;
|
||||
int name;
|
||||
unsigned long long val;
|
||||
int ret;
|
||||
|
||||
type = MEMFILE_TYPE(cft->private);
|
||||
name = MEMFILE_ATTR(cft->private);
|
||||
buf = strstrip(buf);
|
||||
type = MEMFILE_TYPE(of_cft(of)->private);
|
||||
name = MEMFILE_ATTR(of_cft(of)->private);
|
||||
|
||||
switch (name) {
|
||||
case RES_LIMIT:
|
||||
|
@ -5040,7 +5044,7 @@ static int mem_cgroup_write(struct cgroup_subsys_state *css, struct cftype *cft,
|
|||
break;
|
||||
}
|
||||
/* This function does all necessary parse...reuse it */
|
||||
ret = res_counter_memparse_write_strategy(buffer, &val);
|
||||
ret = res_counter_memparse_write_strategy(buf, &val);
|
||||
if (ret)
|
||||
break;
|
||||
if (type == _MEM)
|
||||
|
@ -5053,7 +5057,7 @@ static int mem_cgroup_write(struct cgroup_subsys_state *css, struct cftype *cft,
|
|||
return -EINVAL;
|
||||
break;
|
||||
case RES_SOFT_LIMIT:
|
||||
ret = res_counter_memparse_write_strategy(buffer, &val);
|
||||
ret = res_counter_memparse_write_strategy(buf, &val);
|
||||
if (ret)
|
||||
break;
|
||||
/*
|
||||
|
@ -5070,7 +5074,7 @@ static int mem_cgroup_write(struct cgroup_subsys_state *css, struct cftype *cft,
|
|||
ret = -EINVAL; /* should be BUG() ? */
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return ret ?: nbytes;
|
||||
}
|
||||
|
||||
static void memcg_get_hierarchical_limit(struct mem_cgroup *memcg,
|
||||
|
@ -5083,8 +5087,8 @@ static void memcg_get_hierarchical_limit(struct mem_cgroup *memcg,
|
|||
if (!memcg->use_hierarchy)
|
||||
goto out;
|
||||
|
||||
while (css_parent(&memcg->css)) {
|
||||
memcg = mem_cgroup_from_css(css_parent(&memcg->css));
|
||||
while (memcg->css.parent) {
|
||||
memcg = mem_cgroup_from_css(memcg->css.parent);
|
||||
if (!memcg->use_hierarchy)
|
||||
break;
|
||||
tmp = res_counter_read_u64(&memcg->res, RES_LIMIT);
|
||||
|
@ -5097,14 +5101,15 @@ out:
|
|||
*memsw_limit = min_memsw_limit;
|
||||
}
|
||||
|
||||
static int mem_cgroup_reset(struct cgroup_subsys_state *css, unsigned int event)
|
||||
static ssize_t mem_cgroup_reset(struct kernfs_open_file *of, char *buf,
|
||||
size_t nbytes, loff_t off)
|
||||
{
|
||||
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
|
||||
struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
|
||||
int name;
|
||||
enum res_type type;
|
||||
|
||||
type = MEMFILE_TYPE(event);
|
||||
name = MEMFILE_ATTR(event);
|
||||
type = MEMFILE_TYPE(of_cft(of)->private);
|
||||
name = MEMFILE_ATTR(of_cft(of)->private);
|
||||
|
||||
switch (name) {
|
||||
case RES_MAX_USAGE:
|
||||
|
@ -5129,7 +5134,7 @@ static int mem_cgroup_reset(struct cgroup_subsys_state *css, unsigned int event)
|
|||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static u64 mem_cgroup_move_charge_read(struct cgroup_subsys_state *css,
|
||||
|
@ -5322,7 +5327,7 @@ static int mem_cgroup_swappiness_write(struct cgroup_subsys_state *css,
|
|||
if (val > 100)
|
||||
return -EINVAL;
|
||||
|
||||
if (css_parent(css))
|
||||
if (css->parent)
|
||||
memcg->swappiness = val;
|
||||
else
|
||||
vm_swappiness = val;
|
||||
|
@ -5659,7 +5664,7 @@ static int mem_cgroup_oom_control_write(struct cgroup_subsys_state *css,
|
|||
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
|
||||
|
||||
/* cannot set to root cgroup and only 0 and 1 are allowed */
|
||||
if (!css_parent(css) || !((val == 0) || (val == 1)))
|
||||
if (!css->parent || !((val == 0) || (val == 1)))
|
||||
return -EINVAL;
|
||||
|
||||
memcg->oom_kill_disable = val;
|
||||
|
@ -5705,10 +5710,10 @@ static void kmem_cgroup_css_offline(struct mem_cgroup *memcg)
|
|||
* which is then paired with css_put during uncharge resp. here.
|
||||
*
|
||||
* Although this might sound strange as this path is called from
|
||||
* css_offline() when the referencemight have dropped down to 0
|
||||
* and shouldn't be incremented anymore (css_tryget would fail)
|
||||
* we do not have other options because of the kmem allocations
|
||||
* lifetime.
|
||||
* css_offline() when the referencemight have dropped down to 0 and
|
||||
* shouldn't be incremented anymore (css_tryget_online() would
|
||||
* fail) we do not have other options because of the kmem
|
||||
* allocations lifetime.
|
||||
*/
|
||||
css_get(&memcg->css);
|
||||
|
||||
|
@ -5827,9 +5832,10 @@ static void memcg_event_ptable_queue_proc(struct file *file,
|
|||
* Input must be in format '<event_fd> <control_fd> <args>'.
|
||||
* Interpretation of args is defined by control file implementation.
|
||||
*/
|
||||
static int memcg_write_event_control(struct cgroup_subsys_state *css,
|
||||
struct cftype *cft, char *buffer)
|
||||
static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
struct cgroup_subsys_state *css = of_css(of);
|
||||
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
|
||||
struct mem_cgroup_event *event;
|
||||
struct cgroup_subsys_state *cfile_css;
|
||||
|
@ -5840,15 +5846,17 @@ static int memcg_write_event_control(struct cgroup_subsys_state *css,
|
|||
char *endp;
|
||||
int ret;
|
||||
|
||||
efd = simple_strtoul(buffer, &endp, 10);
|
||||
buf = strstrip(buf);
|
||||
|
||||
efd = simple_strtoul(buf, &endp, 10);
|
||||
if (*endp != ' ')
|
||||
return -EINVAL;
|
||||
buffer = endp + 1;
|
||||
buf = endp + 1;
|
||||
|
||||
cfd = simple_strtoul(buffer, &endp, 10);
|
||||
cfd = simple_strtoul(buf, &endp, 10);
|
||||
if ((*endp != ' ') && (*endp != '\0'))
|
||||
return -EINVAL;
|
||||
buffer = endp + 1;
|
||||
buf = endp + 1;
|
||||
|
||||
event = kzalloc(sizeof(*event), GFP_KERNEL);
|
||||
if (!event)
|
||||
|
@ -5916,8 +5924,8 @@ static int memcg_write_event_control(struct cgroup_subsys_state *css,
|
|||
* automatically removed on cgroup destruction but the removal is
|
||||
* asynchronous, so take an extra ref on @css.
|
||||
*/
|
||||
cfile_css = css_tryget_from_dir(cfile.file->f_dentry->d_parent,
|
||||
&memory_cgrp_subsys);
|
||||
cfile_css = css_tryget_online_from_dir(cfile.file->f_dentry->d_parent,
|
||||
&memory_cgrp_subsys);
|
||||
ret = -EINVAL;
|
||||
if (IS_ERR(cfile_css))
|
||||
goto out_put_cfile;
|
||||
|
@ -5926,7 +5934,7 @@ static int memcg_write_event_control(struct cgroup_subsys_state *css,
|
|||
goto out_put_cfile;
|
||||
}
|
||||
|
||||
ret = event->register_event(memcg, event->eventfd, buffer);
|
||||
ret = event->register_event(memcg, event->eventfd, buf);
|
||||
if (ret)
|
||||
goto out_put_css;
|
||||
|
||||
|
@ -5939,7 +5947,7 @@ static int memcg_write_event_control(struct cgroup_subsys_state *css,
|
|||
fdput(cfile);
|
||||
fdput(efile);
|
||||
|
||||
return 0;
|
||||
return nbytes;
|
||||
|
||||
out_put_css:
|
||||
css_put(css);
|
||||
|
@ -5964,25 +5972,25 @@ static struct cftype mem_cgroup_files[] = {
|
|||
{
|
||||
.name = "max_usage_in_bytes",
|
||||
.private = MEMFILE_PRIVATE(_MEM, RES_MAX_USAGE),
|
||||
.trigger = mem_cgroup_reset,
|
||||
.write = mem_cgroup_reset,
|
||||
.read_u64 = mem_cgroup_read_u64,
|
||||
},
|
||||
{
|
||||
.name = "limit_in_bytes",
|
||||
.private = MEMFILE_PRIVATE(_MEM, RES_LIMIT),
|
||||
.write_string = mem_cgroup_write,
|
||||
.write = mem_cgroup_write,
|
||||
.read_u64 = mem_cgroup_read_u64,
|
||||
},
|
||||
{
|
||||
.name = "soft_limit_in_bytes",
|
||||
.private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT),
|
||||
.write_string = mem_cgroup_write,
|
||||
.write = mem_cgroup_write,
|
||||
.read_u64 = mem_cgroup_read_u64,
|
||||
},
|
||||
{
|
||||
.name = "failcnt",
|
||||
.private = MEMFILE_PRIVATE(_MEM, RES_FAILCNT),
|
||||
.trigger = mem_cgroup_reset,
|
||||
.write = mem_cgroup_reset,
|
||||
.read_u64 = mem_cgroup_read_u64,
|
||||
},
|
||||
{
|
||||
|
@ -5991,7 +5999,7 @@ static struct cftype mem_cgroup_files[] = {
|
|||
},
|
||||
{
|
||||
.name = "force_empty",
|
||||
.trigger = mem_cgroup_force_empty_write,
|
||||
.write = mem_cgroup_force_empty_write,
|
||||
},
|
||||
{
|
||||
.name = "use_hierarchy",
|
||||
|
@ -6001,7 +6009,7 @@ static struct cftype mem_cgroup_files[] = {
|
|||
},
|
||||
{
|
||||
.name = "cgroup.event_control", /* XXX: for compat */
|
||||
.write_string = memcg_write_event_control,
|
||||
.write = memcg_write_event_control,
|
||||
.flags = CFTYPE_NO_PREFIX,
|
||||
.mode = S_IWUGO,
|
||||
},
|
||||
|
@ -6034,7 +6042,7 @@ static struct cftype mem_cgroup_files[] = {
|
|||
{
|
||||
.name = "kmem.limit_in_bytes",
|
||||
.private = MEMFILE_PRIVATE(_KMEM, RES_LIMIT),
|
||||
.write_string = mem_cgroup_write,
|
||||
.write = mem_cgroup_write,
|
||||
.read_u64 = mem_cgroup_read_u64,
|
||||
},
|
||||
{
|
||||
|
@ -6045,13 +6053,13 @@ static struct cftype mem_cgroup_files[] = {
|
|||
{
|
||||
.name = "kmem.failcnt",
|
||||
.private = MEMFILE_PRIVATE(_KMEM, RES_FAILCNT),
|
||||
.trigger = mem_cgroup_reset,
|
||||
.write = mem_cgroup_reset,
|
||||
.read_u64 = mem_cgroup_read_u64,
|
||||
},
|
||||
{
|
||||
.name = "kmem.max_usage_in_bytes",
|
||||
.private = MEMFILE_PRIVATE(_KMEM, RES_MAX_USAGE),
|
||||
.trigger = mem_cgroup_reset,
|
||||
.write = mem_cgroup_reset,
|
||||
.read_u64 = mem_cgroup_read_u64,
|
||||
},
|
||||
#ifdef CONFIG_SLABINFO
|
||||
|
@ -6074,19 +6082,19 @@ static struct cftype memsw_cgroup_files[] = {
|
|||
{
|
||||
.name = "memsw.max_usage_in_bytes",
|
||||
.private = MEMFILE_PRIVATE(_MEMSWAP, RES_MAX_USAGE),
|
||||
.trigger = mem_cgroup_reset,
|
||||
.write = mem_cgroup_reset,
|
||||
.read_u64 = mem_cgroup_read_u64,
|
||||
},
|
||||
{
|
||||
.name = "memsw.limit_in_bytes",
|
||||
.private = MEMFILE_PRIVATE(_MEMSWAP, RES_LIMIT),
|
||||
.write_string = mem_cgroup_write,
|
||||
.write = mem_cgroup_write,
|
||||
.read_u64 = mem_cgroup_read_u64,
|
||||
},
|
||||
{
|
||||
.name = "memsw.failcnt",
|
||||
.private = MEMFILE_PRIVATE(_MEMSWAP, RES_FAILCNT),
|
||||
.trigger = mem_cgroup_reset,
|
||||
.write = mem_cgroup_reset,
|
||||
.read_u64 = mem_cgroup_read_u64,
|
||||
},
|
||||
{ }, /* terminate */
|
||||
|
@ -6264,9 +6272,9 @@ static int
|
|||
mem_cgroup_css_online(struct cgroup_subsys_state *css)
|
||||
{
|
||||
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
|
||||
struct mem_cgroup *parent = mem_cgroup_from_css(css_parent(css));
|
||||
struct mem_cgroup *parent = mem_cgroup_from_css(css->parent);
|
||||
|
||||
if (css->cgroup->id > MEM_CGROUP_ID_MAX)
|
||||
if (css->id > MEM_CGROUP_ID_MAX)
|
||||
return -ENOSPC;
|
||||
|
||||
if (!parent)
|
||||
|
@ -6361,7 +6369,7 @@ static void mem_cgroup_css_free(struct cgroup_subsys_state *css)
|
|||
/*
|
||||
* XXX: css_offline() would be where we should reparent all
|
||||
* memory to prepare the cgroup for destruction. However,
|
||||
* memcg does not do css_tryget() and res_counter charging
|
||||
* memcg does not do css_tryget_online() and res_counter charging
|
||||
* under the same RCU lock region, which means that charging
|
||||
* could race with offlining. Offlining only happens to
|
||||
* cgroups with no tasks in them but charges can show up
|
||||
|
@ -6375,9 +6383,9 @@ static void mem_cgroup_css_free(struct cgroup_subsys_state *css)
|
|||
* lookup_swap_cgroup_id()
|
||||
* rcu_read_lock()
|
||||
* mem_cgroup_lookup()
|
||||
* css_tryget()
|
||||
* css_tryget_online()
|
||||
* rcu_read_unlock()
|
||||
* disable css_tryget()
|
||||
* disable css_tryget_online()
|
||||
* call_rcu()
|
||||
* offline_css()
|
||||
* reparent_charges()
|
||||
|
|
|
@ -42,7 +42,7 @@ cgrp_css_alloc(struct cgroup_subsys_state *parent_css)
|
|||
static int cgrp_css_online(struct cgroup_subsys_state *css)
|
||||
{
|
||||
struct cgroup_cls_state *cs = css_cls_state(css);
|
||||
struct cgroup_cls_state *parent = css_cls_state(css_parent(css));
|
||||
struct cgroup_cls_state *parent = css_cls_state(css->parent);
|
||||
|
||||
if (parent)
|
||||
cs->classid = parent->classid;
|
||||
|
|
|
@ -140,7 +140,7 @@ cgrp_css_alloc(struct cgroup_subsys_state *parent_css)
|
|||
|
||||
static int cgrp_css_online(struct cgroup_subsys_state *css)
|
||||
{
|
||||
struct cgroup_subsys_state *parent_css = css_parent(css);
|
||||
struct cgroup_subsys_state *parent_css = css->parent;
|
||||
struct net_device *dev;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -185,15 +185,15 @@ static int read_priomap(struct seq_file *sf, void *v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int write_priomap(struct cgroup_subsys_state *css, struct cftype *cft,
|
||||
char *buffer)
|
||||
static ssize_t write_priomap(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
char devname[IFNAMSIZ + 1];
|
||||
struct net_device *dev;
|
||||
u32 prio;
|
||||
int ret;
|
||||
|
||||
if (sscanf(buffer, "%"__stringify(IFNAMSIZ)"s %u", devname, &prio) != 2)
|
||||
if (sscanf(buf, "%"__stringify(IFNAMSIZ)"s %u", devname, &prio) != 2)
|
||||
return -EINVAL;
|
||||
|
||||
dev = dev_get_by_name(&init_net, devname);
|
||||
|
@ -202,11 +202,11 @@ static int write_priomap(struct cgroup_subsys_state *css, struct cftype *cft,
|
|||
|
||||
rtnl_lock();
|
||||
|
||||
ret = netprio_set_prio(css, dev, prio);
|
||||
ret = netprio_set_prio(of_css(of), dev, prio);
|
||||
|
||||
rtnl_unlock();
|
||||
dev_put(dev);
|
||||
return ret;
|
||||
return ret ?: nbytes;
|
||||
}
|
||||
|
||||
static int update_netprio(const void *v, struct file *file, unsigned n)
|
||||
|
@ -239,7 +239,7 @@ static struct cftype ss_files[] = {
|
|||
{
|
||||
.name = "ifpriomap",
|
||||
.seq_show = read_priomap,
|
||||
.write_string = write_priomap,
|
||||
.write = write_priomap,
|
||||
},
|
||||
{ } /* terminate */
|
||||
};
|
||||
|
|
|
@ -102,17 +102,19 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tcp_cgroup_write(struct cgroup_subsys_state *css, struct cftype *cft,
|
||||
char *buffer)
|
||||
static ssize_t tcp_cgroup_write(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
|
||||
struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
|
||||
unsigned long long val;
|
||||
int ret = 0;
|
||||
|
||||
switch (cft->private) {
|
||||
buf = strstrip(buf);
|
||||
|
||||
switch (of_cft(of)->private) {
|
||||
case RES_LIMIT:
|
||||
/* see memcontrol.c */
|
||||
ret = res_counter_memparse_write_strategy(buffer, &val);
|
||||
ret = res_counter_memparse_write_strategy(buf, &val);
|
||||
if (ret)
|
||||
break;
|
||||
ret = tcp_update_limit(memcg, val);
|
||||
|
@ -121,7 +123,7 @@ static int tcp_cgroup_write(struct cgroup_subsys_state *css, struct cftype *cft,
|
|||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return ret ?: nbytes;
|
||||
}
|
||||
|
||||
static u64 tcp_read_stat(struct mem_cgroup *memcg, int type, u64 default_val)
|
||||
|
@ -168,17 +170,18 @@ static u64 tcp_cgroup_read(struct cgroup_subsys_state *css, struct cftype *cft)
|
|||
return val;
|
||||
}
|
||||
|
||||
static int tcp_cgroup_reset(struct cgroup_subsys_state *css, unsigned int event)
|
||||
static ssize_t tcp_cgroup_reset(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
struct mem_cgroup *memcg;
|
||||
struct cg_proto *cg_proto;
|
||||
|
||||
memcg = mem_cgroup_from_css(css);
|
||||
memcg = mem_cgroup_from_css(of_css(of));
|
||||
cg_proto = tcp_prot.proto_cgroup(memcg);
|
||||
if (!cg_proto)
|
||||
return 0;
|
||||
return nbytes;
|
||||
|
||||
switch (event) {
|
||||
switch (of_cft(of)->private) {
|
||||
case RES_MAX_USAGE:
|
||||
res_counter_reset_max(&cg_proto->memory_allocated);
|
||||
break;
|
||||
|
@ -187,13 +190,13 @@ static int tcp_cgroup_reset(struct cgroup_subsys_state *css, unsigned int event)
|
|||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static struct cftype tcp_files[] = {
|
||||
{
|
||||
.name = "kmem.tcp.limit_in_bytes",
|
||||
.write_string = tcp_cgroup_write,
|
||||
.write = tcp_cgroup_write,
|
||||
.read_u64 = tcp_cgroup_read,
|
||||
.private = RES_LIMIT,
|
||||
},
|
||||
|
@ -205,13 +208,13 @@ static struct cftype tcp_files[] = {
|
|||
{
|
||||
.name = "kmem.tcp.failcnt",
|
||||
.private = RES_FAILCNT,
|
||||
.trigger = tcp_cgroup_reset,
|
||||
.write = tcp_cgroup_reset,
|
||||
.read_u64 = tcp_cgroup_read,
|
||||
},
|
||||
{
|
||||
.name = "kmem.tcp.max_usage_in_bytes",
|
||||
.private = RES_MAX_USAGE,
|
||||
.trigger = tcp_cgroup_reset,
|
||||
.write = tcp_cgroup_reset,
|
||||
.read_u64 = tcp_cgroup_read,
|
||||
},
|
||||
{ } /* terminate */
|
||||
|
|
|
@ -182,7 +182,7 @@ static inline bool is_devcg_online(const struct dev_cgroup *devcg)
|
|||
static int devcgroup_online(struct cgroup_subsys_state *css)
|
||||
{
|
||||
struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
|
||||
struct dev_cgroup *parent_dev_cgroup = css_to_devcgroup(css_parent(css));
|
||||
struct dev_cgroup *parent_dev_cgroup = css_to_devcgroup(css->parent);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&devcgroup_mutex);
|
||||
|
@ -455,7 +455,7 @@ static bool verify_new_ex(struct dev_cgroup *dev_cgroup,
|
|||
static int parent_has_perm(struct dev_cgroup *childcg,
|
||||
struct dev_exception_item *ex)
|
||||
{
|
||||
struct dev_cgroup *parent = css_to_devcgroup(css_parent(&childcg->css));
|
||||
struct dev_cgroup *parent = css_to_devcgroup(childcg->css.parent);
|
||||
|
||||
if (!parent)
|
||||
return 1;
|
||||
|
@ -476,7 +476,7 @@ static int parent_has_perm(struct dev_cgroup *childcg,
|
|||
static bool parent_allows_removal(struct dev_cgroup *childcg,
|
||||
struct dev_exception_item *ex)
|
||||
{
|
||||
struct dev_cgroup *parent = css_to_devcgroup(css_parent(&childcg->css));
|
||||
struct dev_cgroup *parent = css_to_devcgroup(childcg->css.parent);
|
||||
|
||||
if (!parent)
|
||||
return true;
|
||||
|
@ -587,13 +587,6 @@ static int propagate_exception(struct dev_cgroup *devcg_root,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static inline bool has_children(struct dev_cgroup *devcgroup)
|
||||
{
|
||||
struct cgroup *cgrp = devcgroup->css.cgroup;
|
||||
|
||||
return !list_empty(&cgrp->children);
|
||||
}
|
||||
|
||||
/*
|
||||
* Modify the exception list using allow/deny rules.
|
||||
* CAP_SYS_ADMIN is needed for this. It's at least separate from CAP_MKNOD
|
||||
|
@ -614,7 +607,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
|
|||
char temp[12]; /* 11 + 1 characters needed for a u32 */
|
||||
int count, rc = 0;
|
||||
struct dev_exception_item ex;
|
||||
struct dev_cgroup *parent = css_to_devcgroup(css_parent(&devcgroup->css));
|
||||
struct dev_cgroup *parent = css_to_devcgroup(devcgroup->css.parent);
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
@ -626,7 +619,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
|
|||
case 'a':
|
||||
switch (filetype) {
|
||||
case DEVCG_ALLOW:
|
||||
if (has_children(devcgroup))
|
||||
if (css_has_online_children(&devcgroup->css))
|
||||
return -EINVAL;
|
||||
|
||||
if (!may_allow_all(parent))
|
||||
|
@ -642,7 +635,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
|
|||
return rc;
|
||||
break;
|
||||
case DEVCG_DENY:
|
||||
if (has_children(devcgroup))
|
||||
if (css_has_online_children(&devcgroup->css))
|
||||
return -EINVAL;
|
||||
|
||||
dev_exception_clean(devcgroup);
|
||||
|
@ -767,27 +760,27 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int devcgroup_access_write(struct cgroup_subsys_state *css,
|
||||
struct cftype *cft, char *buffer)
|
||||
static ssize_t devcgroup_access_write(struct kernfs_open_file *of,
|
||||
char *buf, size_t nbytes, loff_t off)
|
||||
{
|
||||
int retval;
|
||||
|
||||
mutex_lock(&devcgroup_mutex);
|
||||
retval = devcgroup_update_access(css_to_devcgroup(css),
|
||||
cft->private, buffer);
|
||||
retval = devcgroup_update_access(css_to_devcgroup(of_css(of)),
|
||||
of_cft(of)->private, strstrip(buf));
|
||||
mutex_unlock(&devcgroup_mutex);
|
||||
return retval;
|
||||
return retval ?: nbytes;
|
||||
}
|
||||
|
||||
static struct cftype dev_cgroup_files[] = {
|
||||
{
|
||||
.name = "allow",
|
||||
.write_string = devcgroup_access_write,
|
||||
.write = devcgroup_access_write,
|
||||
.private = DEVCG_ALLOW,
|
||||
},
|
||||
{
|
||||
.name = "deny",
|
||||
.write_string = devcgroup_access_write,
|
||||
.write = devcgroup_access_write,
|
||||
.private = DEVCG_DENY,
|
||||
},
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче