Commit 88d6ae8d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup

Pull cgroup updates from Tejun Heo:
 "cgroup file type addition / removal is updated so that file types are
  added and removed instead of individual files so that dynamic file
  type addition / removal can be implemented by cgroup and used by
  controllers.  blkio controller changes which will come through block
  tree are dependent on this.  Other changes include res_counter cleanup
  and disallowing kthread / PF_THREAD_BOUND threads to be attached to
  non-root cgroups.

  There's a reported bug with the file type addition / removal handling
  which can lead to oops on cgroup umount.  The issue is being looked
  into.  It shouldn't cause problems for most setups and isn't a
  security concern."

Fix up trivial conflict in Documentation/feature-removal-schedule.txt

* 'for-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: (21 commits)
  res_counter: Account max_usage when calling res_counter_charge_nofail()
  res_counter: Merge res_counter_charge and res_counter_charge_nofail
  cgroups: disallow attaching kthreadd or PF_THREAD_BOUND threads
  cgroup: remove cgroup_subsys->populate()
  cgroup: get rid of populate for memcg
  cgroup: pass struct mem_cgroup instead of struct cgroup to socket memcg
  cgroup: make css->refcnt clearing on cgroup removal optional
  cgroup: use negative bias on css->refcnt to block css_tryget()
  cgroup: implement cgroup_rm_cftypes()
  cgroup: introduce struct cfent
  cgroup: relocate __d_cgrp() and __d_cft()
  cgroup: remove cgroup_add_file[s]()
  cgroup: convert memcg controller to the new cftype interface
  memcg: always create memsw files if CONFIG_CGROUP_MEM_RES_CTLR_SWAP
  cgroup: convert all non-memcg controllers to the new cftype interface
  cgroup: relocate cftype and cgroup_subsys definitions in controllers
  cgroup: merge cft_release_agent cftype array into the base files array
  cgroup: implement cgroup_add_cftypes() and friends
  cgroup: build list of all cgroups under a given cgroupfs_root
  cgroup: move cgroup_clear_directory() call out of cgroup_populate_dir()
  ...
parents f5c10189 0d4dde1a
...@@ -77,11 +77,11 @@ to work with it. ...@@ -77,11 +77,11 @@ to work with it.
where the charging failed. where the charging failed.
d. int res_counter_charge_locked d. int res_counter_charge_locked
(struct res_counter *rc, unsigned long val) (struct res_counter *rc, unsigned long val, bool force)
The same as res_counter_charge(), but it must not acquire/release the The same as res_counter_charge(), but it must not acquire/release the
res_counter->lock internally (it must be called with res_counter->lock res_counter->lock internally (it must be called with res_counter->lock
held). held). The force parameter indicates whether we can bypass the limit.
e. void res_counter_uncharge[_locked] e. void res_counter_uncharge[_locked]
(struct res_counter *rc, unsigned long val) (struct res_counter *rc, unsigned long val)
......
...@@ -556,3 +556,14 @@ Why: The V4L2_CID_VCENTER, V4L2_CID_HCENTER controls have been deprecated ...@@ -556,3 +556,14 @@ Why: The V4L2_CID_VCENTER, V4L2_CID_HCENTER controls have been deprecated
There are newer controls (V4L2_CID_PAN*, V4L2_CID_TILT*) that provide There are newer controls (V4L2_CID_PAN*, V4L2_CID_TILT*) that provide
similar functionality. similar functionality.
Who: Sylwester Nawrocki <sylvester.nawrocki@gmail.com> Who: Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
----------------------------
What: cgroup option updates via remount
When: March 2013
Why: Remount currently allows changing bound subsystems and
release_agent. Rebinding is hardly useful as it only works
when the hierarchy is empty and release_agent itself should be
replaced with conventional fsnotify.
----------------------------
...@@ -28,34 +28,12 @@ static LIST_HEAD(blkio_list); ...@@ -28,34 +28,12 @@ static LIST_HEAD(blkio_list);
struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT }; struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT };
EXPORT_SYMBOL_GPL(blkio_root_cgroup); EXPORT_SYMBOL_GPL(blkio_root_cgroup);
static struct cgroup_subsys_state *blkiocg_create(struct cgroup *);
static int blkiocg_can_attach(struct cgroup *, struct cgroup_taskset *);
static void blkiocg_attach(struct cgroup *, struct cgroup_taskset *);
static void blkiocg_destroy(struct cgroup *);
static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
/* for encoding cft->private value on file */ /* for encoding cft->private value on file */
#define BLKIOFILE_PRIVATE(x, val) (((x) << 16) | (val)) #define BLKIOFILE_PRIVATE(x, val) (((x) << 16) | (val))
/* What policy owns the file, proportional or throttle */ /* What policy owns the file, proportional or throttle */
#define BLKIOFILE_POLICY(val) (((val) >> 16) & 0xffff) #define BLKIOFILE_POLICY(val) (((val) >> 16) & 0xffff)
#define BLKIOFILE_ATTR(val) ((val) & 0xffff) #define BLKIOFILE_ATTR(val) ((val) & 0xffff)
struct cgroup_subsys blkio_subsys = {
.name = "blkio",
.create = blkiocg_create,
.can_attach = blkiocg_can_attach,
.attach = blkiocg_attach,
.destroy = blkiocg_destroy,
.populate = blkiocg_populate,
#ifdef CONFIG_BLK_CGROUP
/* note: blkio_subsys_id is otherwise defined in blk-cgroup.h */
.subsys_id = blkio_subsys_id,
#endif
.use_id = 1,
.module = THIS_MODULE,
};
EXPORT_SYMBOL_GPL(blkio_subsys);
static inline void blkio_policy_insert_node(struct blkio_cgroup *blkcg, static inline void blkio_policy_insert_node(struct blkio_cgroup *blkcg,
struct blkio_policy_node *pn) struct blkio_policy_node *pn)
{ {
...@@ -1537,14 +1515,9 @@ struct cftype blkio_files[] = { ...@@ -1537,14 +1515,9 @@ struct cftype blkio_files[] = {
.read_map = blkiocg_file_read_map, .read_map = blkiocg_file_read_map,
}, },
#endif #endif
{ } /* terminate */
}; };
static int blkiocg_populate(struct cgroup_subsys *subsys, struct cgroup *cgroup)
{
return cgroup_add_files(cgroup, subsys, blkio_files,
ARRAY_SIZE(blkio_files));
}
static void blkiocg_destroy(struct cgroup *cgroup) static void blkiocg_destroy(struct cgroup *cgroup)
{ {
struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup); struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup);
...@@ -1658,6 +1631,22 @@ static void blkiocg_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) ...@@ -1658,6 +1631,22 @@ static void blkiocg_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
} }
} }
struct cgroup_subsys blkio_subsys = {
.name = "blkio",
.create = blkiocg_create,
.can_attach = blkiocg_can_attach,
.attach = blkiocg_attach,
.destroy = blkiocg_destroy,
#ifdef CONFIG_BLK_CGROUP
/* note: blkio_subsys_id is otherwise defined in blk-cgroup.h */
.subsys_id = blkio_subsys_id,
#endif
.base_cftypes = blkio_files,
.use_id = 1,
.module = THIS_MODULE,
};
EXPORT_SYMBOL_GPL(blkio_subsys);
void blkio_policy_register(struct blkio_policy_type *blkiop) void blkio_policy_register(struct blkio_policy_type *blkiop)
{ {
spin_lock(&blkio_list_lock); spin_lock(&blkio_list_lock);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/prio_heap.h> #include <linux/prio_heap.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/workqueue.h>
#ifdef CONFIG_CGROUPS #ifdef CONFIG_CGROUPS
...@@ -76,12 +77,16 @@ struct cgroup_subsys_state { ...@@ -76,12 +77,16 @@ struct cgroup_subsys_state {
unsigned long flags; unsigned long flags;
/* ID for this css, if possible */ /* ID for this css, if possible */
struct css_id __rcu *id; struct css_id __rcu *id;
/* Used to put @cgroup->dentry on the last css_put() */
struct work_struct dput_work;
}; };
/* bits in struct cgroup_subsys_state flags field */ /* bits in struct cgroup_subsys_state flags field */
enum { enum {
CSS_ROOT, /* This CSS is the root of the subsystem */ CSS_ROOT, /* This CSS is the root of the subsystem */
CSS_REMOVED, /* This CSS is dead */ CSS_REMOVED, /* This CSS is dead */
CSS_CLEAR_CSS_REFS, /* @ss->__DEPRECATED_clear_css_refs */
}; };
/* Caller must verify that the css is not for root cgroup */ /* Caller must verify that the css is not for root cgroup */
...@@ -115,16 +120,12 @@ static inline bool css_is_removed(struct cgroup_subsys_state *css) ...@@ -115,16 +120,12 @@ static inline bool css_is_removed(struct cgroup_subsys_state *css)
* the css has been destroyed. * the css has been destroyed.
*/ */
extern bool __css_tryget(struct cgroup_subsys_state *css);
static inline bool css_tryget(struct cgroup_subsys_state *css) static inline bool css_tryget(struct cgroup_subsys_state *css)
{ {
if (test_bit(CSS_ROOT, &css->flags)) if (test_bit(CSS_ROOT, &css->flags))
return true; return true;
while (!atomic_inc_not_zero(&css->refcnt)) { return __css_tryget(css);
if (test_bit(CSS_REMOVED, &css->flags))
return false;
cpu_relax();
}
return true;
} }
/* /*
...@@ -132,11 +133,11 @@ static inline bool css_tryget(struct cgroup_subsys_state *css) ...@@ -132,11 +133,11 @@ static inline bool css_tryget(struct cgroup_subsys_state *css)
* css_get() or css_tryget() * css_get() or css_tryget()
*/ */
extern void __css_put(struct cgroup_subsys_state *css, int count); extern void __css_put(struct cgroup_subsys_state *css);
static inline void css_put(struct cgroup_subsys_state *css) static inline void css_put(struct cgroup_subsys_state *css)
{ {
if (!test_bit(CSS_ROOT, &css->flags)) if (!test_bit(CSS_ROOT, &css->flags))
__css_put(css, 1); __css_put(css);
} }
/* bits in struct cgroup flags field */ /* bits in struct cgroup flags field */
...@@ -175,6 +176,7 @@ struct cgroup { ...@@ -175,6 +176,7 @@ struct cgroup {
*/ */
struct list_head sibling; /* my parent's children */ struct list_head sibling; /* my parent's children */
struct list_head children; /* my children */ struct list_head children; /* my children */
struct list_head files; /* my files */
struct cgroup *parent; /* my parent */ struct cgroup *parent; /* my parent */
struct dentry __rcu *dentry; /* cgroup fs entry, RCU protected */ struct dentry __rcu *dentry; /* cgroup fs entry, RCU protected */
...@@ -191,6 +193,9 @@ struct cgroup { ...@@ -191,6 +193,9 @@ struct cgroup {
*/ */
struct list_head css_sets; struct list_head css_sets;
struct list_head allcg_node; /* cgroupfs_root->allcg_list */
struct list_head cft_q_node; /* used during cftype add/rm */
/* /*
* Linked list running through all cgroups that can * Linked list running through all cgroups that can
* potentially be reaped by the release agent. Protected by * potentially be reaped by the release agent. Protected by
...@@ -275,11 +280,17 @@ struct cgroup_map_cb { ...@@ -275,11 +280,17 @@ struct cgroup_map_cb {
* - the 'cftype' of the file is file->f_dentry->d_fsdata * - the 'cftype' of the file is file->f_dentry->d_fsdata
*/ */
#define MAX_CFTYPE_NAME 64 /* cftype->flags */
#define CFTYPE_ONLY_ON_ROOT (1U << 0) /* only create on root cg */
#define CFTYPE_NOT_ON_ROOT (1U << 1) /* don't create onp root cg */
#define MAX_CFTYPE_NAME 64
struct cftype { struct cftype {
/* /*
* By convention, the name should begin with the name of the * By convention, the name should begin with the name of the
* subsystem, followed by a period * subsystem, followed by a period. Zero length string indicates
* end of cftype array.
*/ */
char name[MAX_CFTYPE_NAME]; char name[MAX_CFTYPE_NAME];
int private; int private;
...@@ -295,6 +306,9 @@ struct cftype { ...@@ -295,6 +306,9 @@ struct cftype {
*/ */
size_t max_write_len; size_t max_write_len;
/* CFTYPE_* flags */
unsigned int flags;
int (*open)(struct inode *inode, struct file *file); int (*open)(struct inode *inode, struct file *file);
ssize_t (*read)(struct cgroup *cgrp, struct cftype *cft, ssize_t (*read)(struct cgroup *cgrp, struct cftype *cft,
struct file *file, struct file *file,
...@@ -373,6 +387,16 @@ struct cftype { ...@@ -373,6 +387,16 @@ struct cftype {
struct eventfd_ctx *eventfd); struct eventfd_ctx *eventfd);
}; };
/*
* cftype_sets describe cftypes belonging to a subsystem and are chained at
* cgroup_subsys->cftsets. Each cftset points to an array of cftypes
* terminated by zero length name.
*/
struct cftype_set {
struct list_head node; /* chained at subsys->cftsets */
const struct cftype *cfts;
};
struct cgroup_scanner { struct cgroup_scanner {
struct cgroup *cg; struct cgroup *cg;
int (*test_task)(struct task_struct *p, struct cgroup_scanner *scan); int (*test_task)(struct task_struct *p, struct cgroup_scanner *scan);
...@@ -382,21 +406,8 @@ struct cgroup_scanner { ...@@ -382,21 +406,8 @@ struct cgroup_scanner {
void *data; void *data;
}; };
/* int cgroup_add_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts);
* Add a new file to the given cgroup directory. Should only be int cgroup_rm_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts);
* called by subsystems from within a populate() method
*/
int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
const struct cftype *cft);
/*
* Add a set of new files to the given cgroup directory. Should
* only be called by subsystems from within a populate() method
*/
int cgroup_add_files(struct cgroup *cgrp,
struct cgroup_subsys *subsys,
const struct cftype cft[],
int count);
int cgroup_is_removed(const struct cgroup *cgrp); int cgroup_is_removed(const struct cgroup *cgrp);
...@@ -461,7 +472,6 @@ struct cgroup_subsys { ...@@ -461,7 +472,6 @@ struct cgroup_subsys {
void (*fork)(struct task_struct *task); void (*fork)(struct task_struct *task);
void (*exit)(struct cgroup *cgrp, struct cgroup *old_cgrp, void (*exit)(struct cgroup *cgrp, struct cgroup *old_cgrp,
struct task_struct *task); struct task_struct *task);
int (*populate)(struct cgroup_subsys *ss, struct cgroup *cgrp);
void (*post_clone)(struct cgroup *cgrp); void (*post_clone)(struct cgroup *cgrp);
void (*bind)(struct cgroup *root); void (*bind)(struct cgroup *root);
...@@ -474,6 +484,18 @@ struct cgroup_subsys { ...@@ -474,6 +484,18 @@ struct cgroup_subsys {
* (not available in early_init time.) * (not available in early_init time.)
*/ */
bool use_id; bool use_id;
/*
* If %true, cgroup removal will try to clear css refs by retrying
* ss->pre_destroy() until there's no css ref left. This behavior
* is strictly for backward compatibility and will be removed as
* soon as the current user (memcg) is updated.
*
* If %false, ss->pre_destroy() can't fail and cgroup removal won't
* wait for css refs to drop to zero before proceeding.
*/
bool __DEPRECATED_clear_css_refs;
#define MAX_CGROUP_TYPE_NAMELEN 32 #define MAX_CGROUP_TYPE_NAMELEN 32
const char *name; const char *name;
...@@ -500,6 +522,13 @@ struct cgroup_subsys { ...@@ -500,6 +522,13 @@ struct cgroup_subsys {
struct idr idr; struct idr idr;
spinlock_t id_lock; spinlock_t id_lock;
/* list of cftype_sets */
struct list_head cftsets;
/* base cftypes, automatically [de]registered with subsys itself */
struct cftype *base_cftypes;
struct cftype_set base_cftset;
/* should be defined only by modular subsystems */ /* should be defined only by modular subsystems */
struct module *module; struct module *module;
}; };
......
...@@ -116,7 +116,7 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent); ...@@ -116,7 +116,7 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent);
*/ */
int __must_check res_counter_charge_locked(struct res_counter *counter, int __must_check res_counter_charge_locked(struct res_counter *counter,
unsigned long val); unsigned long val, bool force);
int __must_check res_counter_charge(struct res_counter *counter, int __must_check res_counter_charge(struct res_counter *counter,
unsigned long val, struct res_counter **limit_fail_at); unsigned long val, struct res_counter **limit_fail_at);
int __must_check res_counter_charge_nofail(struct res_counter *counter, int __must_check res_counter_charge_nofail(struct res_counter *counter,
......
...@@ -70,16 +70,16 @@ ...@@ -70,16 +70,16 @@
struct cgroup; struct cgroup;
struct cgroup_subsys; struct cgroup_subsys;
#ifdef CONFIG_NET #ifdef CONFIG_NET
int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss); int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss);
void mem_cgroup_sockets_destroy(struct cgroup *cgrp); void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg);
#else #else
static inline static inline
int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss) int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{ {
return 0; return 0;
} }
static inline static inline
void mem_cgroup_sockets_destroy(struct cgroup *cgrp) void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg)
{ {
} }
#endif #endif
...@@ -914,9 +914,9 @@ struct proto { ...@@ -914,9 +914,9 @@ struct proto {
* This function has to setup any files the protocol want to * This function has to setup any files the protocol want to
* appear in the kmem cgroup filesystem. * appear in the kmem cgroup filesystem.
*/ */
int (*init_cgroup)(struct cgroup *cgrp, int (*init_cgroup)(struct mem_cgroup *memcg,
struct cgroup_subsys *ss); struct cgroup_subsys *ss);
void (*destroy_cgroup)(struct cgroup *cgrp); void (*destroy_cgroup)(struct mem_cgroup *memcg);
struct cg_proto *(*proto_cgroup)(struct mem_cgroup *memcg); struct cg_proto *(*proto_cgroup)(struct mem_cgroup *memcg);
#endif #endif
}; };
......
...@@ -12,8 +12,8 @@ struct tcp_memcontrol { ...@@ -12,8 +12,8 @@ struct tcp_memcontrol {
}; };
struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg); struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg);
int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss); int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss);
void tcp_destroy_cgroup(struct cgroup *cgrp); void tcp_destroy_cgroup(struct mem_cgroup *memcg);
unsigned long long tcp_max_memory(const struct mem_cgroup *memcg); unsigned long long tcp_max_memory(const struct mem_cgroup *memcg);
void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx); void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx);
#endif /* _TCP_MEMCG_H */ #endif /* _TCP_MEMCG_H */
This diff is collapsed.
...@@ -358,24 +358,19 @@ static int freezer_write(struct cgroup *cgroup, ...@@ -358,24 +358,19 @@ static int freezer_write(struct cgroup *cgroup,
static struct cftype files[] = { static struct cftype files[] = {
{ {
.name = "state", .name = "state",
.flags = CFTYPE_NOT_ON_ROOT,
.read_seq_string = freezer_read, .read_seq_string = freezer_read,
.write_string = freezer_write, .write_string = freezer_write,
}, },
{ } /* terminate */
}; };
static int freezer_populate(struct cgroup_subsys *ss, struct cgroup *cgroup)
{
if (!cgroup->parent)
return 0;
return cgroup_add_files(cgroup, ss, files, ARRAY_SIZE(files));
}
struct cgroup_subsys freezer_subsys = { struct cgroup_subsys freezer_subsys = {
.name = "freezer", .name = "freezer",
.create = freezer_create, .create = freezer_create,
.destroy = freezer_destroy, .destroy = freezer_destroy,
.populate = freezer_populate,
.subsys_id = freezer_subsys_id, .subsys_id = freezer_subsys_id,
.can_attach = freezer_can_attach, .can_attach = freezer_can_attach,
.fork = freezer_fork, .fork = freezer_fork,
.base_cftypes = files,
}; };
...@@ -1765,28 +1765,17 @@ static struct cftype files[] = { ...@@ -1765,28 +1765,17 @@ static struct cftype files[] = {
.write_u64 = cpuset_write_u64, .write_u64 = cpuset_write_u64,
.private = FILE_SPREAD_SLAB, .private = FILE_SPREAD_SLAB,
}, },
};
static struct cftype cft_memory_pressure_enabled = {
.name = "memory_pressure_enabled",
.read_u64 = cpuset_read_u64,
.write_u64 = cpuset_write_u64,
.private = FILE_MEMORY_PRESSURE_ENABLED,
};
static int cpuset_populate(struct cgroup_subsys *ss, struct cgroup *cont) {
{ .name = "memory_pressure_enabled",
int err; .flags = CFTYPE_ONLY_ON_ROOT,
.read_u64 = cpuset_read_u64,
.write_u64 = cpuset_write_u64,
.private = FILE_MEMORY_PRESSURE_ENABLED,
},
err = cgroup_add_files(cont, ss, files, ARRAY_SIZE(files)); { } /* terminate */
if (err) };
return err;
/* memory_pressure_enabled is in root cpuset only */
if (!cont->parent)
err = cgroup_add_file(cont, ss,
&cft_memory_pressure_enabled);
return err;
}
/* /*
* post_clone() is called during cgroup_create() when the * post_clone() is called during cgroup_create() when the
...@@ -1887,9 +1876,9 @@ struct cgroup_subsys cpuset_subsys = { ...@@ -1887,9 +1876,9 @@ struct cgroup_subsys cpuset_subsys = {
.destroy = cpuset_destroy, .destroy = cpuset_destroy,
.can_attach = cpuset_can_attach, .can_attach = cpuset_can_attach,
.attach = cpuset_attach, .attach = cpuset_attach,
.populate = cpuset_populate,
.post_clone = cpuset_post_clone, .post_clone = cpuset_post_clone,
.subsys_id = cpuset_subsys_id, .subsys_id = cpuset_subsys_id,
.base_cftypes = files,
.early_init = 1, .early_init = 1,
}; };
......
...@@ -22,75 +22,70 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent) ...@@ -22,75 +22,70 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent)
counter->parent = parent; counter->parent = parent;
} }
int res_counter_charge_locked(struct res_counter *counter, unsigned long val) int res_counter_charge_locked(struct res_counter *counter, unsigned long val,
bool force)
{ {
int ret = 0;
if (counter->usage + val > counter->limit) { if (counter->usage + val > counter->limit) {
counter->failcnt++; counter->failcnt++;
return -ENOMEM; ret = -ENOMEM;
if (!force)
return ret;
} }
counter->usage += val; counter->usage += val;
if (counter->usage > counter->max_usage) if (counter->usage > counter->max_usage)
counter->max_usage = counter->usage; counter->max_usage = counter->usage;
return 0; return ret;
} }
int res_counter_charge(struct res_counter *counter, unsigned long val, static int __res_counter_charge(struct res_counter *counter, unsigned long val,
struct res_counter **limit_fail_at) struct res_counter **limit_fail_at, bool force)
{ {
int ret; int ret, r;
unsigned long flags; unsigned long flags;
struct res_counter *c, *u; struct res_counter *c, *u;
r = ret = 0;
*limit_fail_at = NULL; *limit_fail_at = NULL;
local_irq_save(flags); local_irq_save(flags);
for (c = counter; c != NULL; c = c->parent) { for (c = counter; c != NULL; c = c->parent) {
spin_lock(&c->lock); spin_lock(&c->lock);
ret = res_counter_charge_locked(c, val); r = res_counter_charge_locked(c, val, force);
spin_unlock(&c->lock); spin_unlock(&c->lock);
if (ret < 0) { if (r < 0 && !ret) {
ret = r;
*limit_fail_at = c; *limit_fail_at = c;
goto undo; if (!force)
break;
} }
} }
ret = 0;
goto done; if (ret < 0 && !force) {
undo: for (u = counter; u != c; u = u->parent) {
for (u = counter; u != c; u = u->parent) { spin_lock(&u->lock);
spin_lock(&u->lock); res_counter_uncharge_locked(u, val);
res_counter_uncharge_locked(u, val); spin_unlock(&u->lock);
spin_unlock(&u->lock); }
} }
done:
local_irq_restore(flags); local_irq_restore(flags);
return ret; return ret;
} }
int res_counter_charge(struct res_counter *counter, unsigned long val,
struct res_counter **limit_fail_at)
{
return __res_counter_charge(counter, val, limit_fail_at, false);
}
int res_counter_charge_nofail(struct res_counter *counter, unsigned long val, int res_counter_charge_nofail(struct res_counter *counter, unsigned long val,
struct res_counter **limit_fail_at) struct res_counter **limit_fail_at)
{ {
int ret, r; return __res_counter_charge(counter, val, limit_fail_at, true);
unsigned long flags;
struct res_counter *c;
r = ret = 0;
*limit_fail_at = NULL;
local_irq_save(flags);
for (c = counter; c != NULL; c = c->parent) {
spin_lock(&c->lock);
r = res_counter_charge_locked(c, val);
if (r)
c->usage += val;
spin_unlock(&c->lock);
if (r < 0 && ret == 0) {
*limit_fail_at = c;
ret = r;
}
}
local_irq_restore(flags);
return ret;
} }
void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val) void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
{ {
if (WARN_ON(counter->usage < val)) if (WARN_ON(counter->usage < val))
......
...@@ -7985,13 +7985,9 @@ static struct cftype cpu_files[] = { ...@@ -7985,13 +7985,9 @@ static struct cftype cpu_files[] = {
.write_u64 = cpu_rt_period_write_uint, .write_u64 = cpu_rt_period_write_uint,
}, },
#endif #endif
{ } /* terminate */
}; };
static int cpu_cgroup_populate(struct cgroup_subsys *ss, struct cgroup *cont)
{
return cgroup_add_files(cont, ss, cpu_files, ARRAY_SIZE(cpu_files));
}
struct cgroup_subsys cpu_cgroup_subsys = { struct cgroup_subsys cpu_cgroup_subsys = {
.name = "cpu", .name = "cpu",
.create = cpu_cgroup_create, .create = cpu_cgroup_create,
...@@ -7999,8 +7995,8 @@ struct cgroup_subsys cpu_cgroup_subsys = { ...@@ -7999,8 +7995,8 @@ struct cgroup_subsys cpu_cgroup_subsys = {
.can_attach = cpu_cgroup_can_attach, .can_attach = cpu_cgroup_can_attach,
.attach = cpu_cgroup_attach, .attach = cpu_cgroup_attach,
.exit = cpu_cgroup_exit, .exit = cpu_cgroup_exit,
.populate = cpu_cgroup_populate,
.subsys_id = cpu_cgroup_subsys_id, .subsys_id = cpu_cgroup_subsys_id,
.base_cftypes = cpu_files,
.early_init = 1, .early_init = 1,
}; };
...@@ -8185,13 +8181,9 @@ static struct cftype files[] = { ...@@ -8185,13 +8181,9 @@ static struct cftype files[] = {
.name = "stat", .name = "stat",
.read_map = cpuacct_stats_show, .read_map = cpuacct_stats_show,
}, },
{ } /* terminate */
}; };
static int cpuacct_populate(struct cgroup_subsys *ss, struct cgroup *cgrp)
{
return cgroup_add_files(cgrp, ss, files, ARRAY_SIZE(files));
}
/* /*
* charge this task's execution time to its accounting group. * charge this task's execution time to its accounting group.
* *
...@@ -8223,7 +8215,7 @@ struct cgroup_subsys cpuacct_subsys = { ...@@ -8223,7 +8215,7 @@ struct cgroup_subsys cpuacct_subsys = {
.name = "cpuacct", .name = "cpuacct",
.create = cpuacct_create, .create = cpuacct_create,
.destroy = cpuacct_destroy, .destroy = cpuacct_destroy,
.populate = cpuacct_populate,
.subsys_id = cpuacct_subsys_id, .subsys_id = cpuacct_subsys_id,
.base_cftypes = files,
}; };
#endif /* CONFIG_CGROUP_CPUACCT */ #endif /* CONFIG_CGROUP_CPUACCT */
...@@ -3873,14 +3873,21 @@ static inline u64 mem_cgroup_usage(struct mem_cgroup *memcg, bool swap) ...@@ -3873,14 +3873,21 @@ static inline u64 mem_cgroup_usage(struct mem_cgroup *memcg, bool swap)
return val << PAGE_SHIFT; return val << PAGE_SHIFT;
} }
static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft) static ssize_t mem_cgroup_read(struct cgroup *cont, struct cftype *cft,
struct file *file, char __user *buf,
size_t nbytes, loff_t *ppos)
{ {
struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
char str[64];
u64 val; u64 val;
int type, name; int type, name, len;
type = MEMFILE_TYPE(cft->private); type = MEMFILE_TYPE(cft->private);
name = MEMFILE_ATTR(cft->private); name = MEMFILE_ATTR(cft->private);
if (!do_swap_account && type == _MEMSWAP)
return -EOPNOTSUPP;
switch (type) { switch (type) {
case _MEM: case _MEM:
if (name == RES_USAGE) if (name == RES_USAGE)
...@@ -3897,7 +3904,9 @@ static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft) ...@@ -3897,7 +3904,9 @@ static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft)
default: default:
BUG(); BUG();
} }
return val;
len = scnprintf(str, sizeof(str), "%llu\n", (unsigned long long)val);
return simple_read_from_buffer(buf, nbytes, ppos, str, len);
} }
/* /*
* The user of this function is... * The user of this function is...
...@@ -3913,6 +3922,10 @@ static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft, ...@@ -3913,6 +3922,10 @@ static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft,
type = MEMFILE_TYPE(cft->private); type = MEMFILE_TYPE(cft->private);
name = MEMFILE_ATTR(cft->private); name = MEMFILE_ATTR(cft->private);
if (!do_swap_account && type == _MEMSWAP)
return -EOPNOTSUPP;
switch (name) { switch (name) {
case RES_LIMIT: case RES_LIMIT:
if (mem_cgroup_is_root(memcg)) { /* Can't set limit on root */ if (mem_cgroup_is_root(memcg)) { /* Can't set limit on root */
...@@ -3978,12 +3991,15 @@ static void memcg_get_hierarchical_limit(struct mem_cgroup *memcg, ...@@ -3978,12 +3991,15 @@ static void memcg_get_hierarchical_limit(struct mem_cgroup *memcg,
static int mem_cgroup_reset(struct cgroup *cont, unsigned int event) static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
{ {
struct mem_cgroup *memcg; struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
int type, name; int type, name;
memcg = mem_cgroup_from_cont(cont);
type = MEMFILE_TYPE(event); type = MEMFILE_TYPE(event);
name = MEMFILE_ATTR(event); name = MEMFILE_ATTR(event);
if (!do_swap_account && type == _MEMSWAP)
return -EOPNOTSUPP;
switch (name) { switch (name) {
case RES_MAX_USAGE: case RES_MAX_USAGE:
if (type == _MEM) if (type == _MEM)
...@@ -4624,29 +4640,22 @@ static int mem_control_numa_stat_open(struct inode *unused, struct file *file) ...@@ -4624,29 +4640,22 @@ static int mem_control_numa_stat_open(struct inode *unused, struct file *file)
#endif /* CONFIG_NUMA */ #endif /* CONFIG_NUMA */
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM #ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss) static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{ {
/* return mem_cgroup_sockets_init(memcg, ss);
* Part of this would be better living in a separate allocation
* function, leaving us with just the cgroup tree population work.
* We, however, depend on state such as network's proto_list that
* is only initialized after cgroup creation. I found the less
* cumbersome way to deal with it to defer it all to populate time
*/
return mem_cgroup_sockets_init(cont, ss);
}; };
static void kmem_cgroup_destroy(struct cgroup *cont) static void kmem_cgroup_destroy(struct mem_cgroup *memcg)
{ {
mem_cgroup_sockets_destroy(cont); mem_cgroup_sockets_destroy(memcg);
} }
#else #else
static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss) static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{ {
return 0; return 0;
} }
static void kmem_cgroup_destroy(struct cgroup *cont) static void kmem_cgroup_destroy(struct mem_cgroup *memcg)
{ {
} }
#endif #endif
...@@ -4655,7 +4664,7 @@ static struct cftype mem_cgroup_files[] = { ...@@ -4655,7 +4664,7 @@ static struct cftype mem_cgroup_files[] = {
{ {
.name = "usage_in_bytes", .name = "usage_in_bytes",
.private = MEMFILE_PRIVATE(_MEM, RES_USAGE), .private = MEMFILE_PRIVATE(_MEM, RES_USAGE),
.read_u64 = mem_cgroup_read, .read = mem_cgroup_read,
.register_event = mem_cgroup_usage_register_event, .register_event = mem_cgroup_usage_register_event,
.unregister_event = mem_cgroup_usage_unregister_event, .unregister_event = mem_cgroup_usage_unregister_event,
}, },
...@@ -4663,25 +4672,25 @@ static struct cftype mem_cgroup_files[] = { ...@@ -4663,25 +4672,25 @@ static struct cftype mem_cgroup_files[] = {
.name = "max_usage_in_bytes", .name = "max_usage_in_bytes",
.private = MEMFILE_PRIVATE(_MEM, RES_MAX_USAGE), .private = MEMFILE_PRIVATE(_MEM, RES_MAX_USAGE),
.trigger = mem_cgroup_reset, .trigger = mem_cgroup_reset,
.read_u64 = mem_cgroup_read, .read = mem_cgroup_read,
}, },
{ {
.name = "limit_in_bytes", .name = "limit_in_bytes",
.private = MEMFILE_PRIVATE(_MEM, RES_LIMIT), .private = MEMFILE_PRIVATE(_MEM, RES_LIMIT),
.write_string = mem_cgroup_write, .write_string = mem_cgroup_write,
.read_u64 = mem_cgroup_read, .read = mem_cgroup_read,
}, },
{ {
.name = "soft_limit_in_bytes", .name = "soft_limit_in_bytes",
.private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT), .private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT),
.write_string = mem_cgroup_write, .write_string = mem_cgroup_write,
.read_u64 = mem_cgroup_read, .read = mem_cgroup_read,
}, },
{ {
.name = "failcnt", .name = "failcnt",
.private = MEMFILE_PRIVATE(_MEM, RES_FAILCNT), .private = MEMFILE_PRIVATE(_MEM, RES_FAILCNT),
.trigger = mem_cgroup_reset, .trigger = mem_cgroup_reset,
.read_u64 = mem_cgroup_read, .read = mem_cgroup_read,
}, },
{ {
.name = "stat", .name = "stat",
...@@ -4721,14 +4730,11 @@ static struct cftype mem_cgroup_files[] = { ...@@ -4721,14 +4730,11 @@ static struct cftype mem_cgroup_files[] = {
.mode = S_IRUGO, .mode = S_IRUGO,
}, },
#endif #endif
};
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
static struct cftype memsw_cgroup_files[] = {
{ {
.name = "memsw.usage_in_bytes", .name = "memsw.usage_in_bytes",
.private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE), .private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE),
.read_u64 = mem_cgroup_read, .read = mem_cgroup_read,
.register_event = mem_cgroup_usage_register_event, .register_event = mem_cgroup_usage_register_event,
.unregister_event = mem_cgroup_usage_unregister_event, .unregister_event = mem_cgroup_usage_unregister_event,
}, },
...@@ -4736,35 +4742,23 @@ static struct cftype memsw_cgroup_files[] = { ...@@ -4736,35 +4742,23 @@ static struct cftype memsw_cgroup_files[] = {
.name = "memsw.max_usage_in_bytes", .name = "memsw.max_usage_in_bytes",
.private = MEMFILE_PRIVATE(_MEMSWAP, RES_MAX_USAGE), .private = MEMFILE_PRIVATE(_MEMSWAP, RES_MAX_USAGE),
.trigger = mem_cgroup_reset, .trigger = mem_cgroup_reset,
.read_u64 = mem_cgroup_read, .read = mem_cgroup_read,
}, },
{ {
.name = "memsw.limit_in_bytes", .name = "memsw.limit_in_bytes",
.private = MEMFILE_PRIVATE(_MEMSWAP, RES_LIMIT), .private = MEMFILE_PRIVATE(_MEMSWAP, RES_LIMIT),
.write_string = mem_cgroup_write, .write_string = mem_cgroup_write,
.read_u64 = mem_cgroup_read, .read = mem_cgroup_read,
}, },
{ {
.name = "memsw.failcnt", .name = "memsw.failcnt",
.private = MEMFILE_PRIVATE(_MEMSWAP, RES_FAILCNT), .private = MEMFILE_PRIVATE(_MEMSWAP, RES_FAILCNT),
.trigger = mem_cgroup_reset, .trigger = mem_cgroup_reset,
.read_u64 = mem_cgroup_read, .read = mem_cgroup_read,
}, },
};
static int register_memsw_files(struct cgroup *cont, struct cgroup_subsys *ss)
{
if (!do_swap_account)
return 0;
return cgroup_add_files(cont, ss, memsw_cgroup_files,
ARRAY_SIZE(memsw_cgroup_files));
};
#else
static int register_memsw_files(struct cgroup *cont, struct cgroup_subsys *ss)
{
return 0;
}
#endif #endif
{ }, /* terminate */
};
static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node) static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
{ {
...@@ -5016,6 +5010,17 @@ mem_cgroup_create(struct cgroup *cont) ...@@ -5016,6 +5010,17 @@ mem_cgroup_create(struct cgroup *cont)
memcg->move_charge_at_immigrate = 0; memcg->move_charge_at_immigrate = 0;
mutex_init(&memcg->thresholds_lock); mutex_init(&memcg->thresholds_lock);
spin_lock_init(&memcg->move_lock); spin_lock_init(&memcg->move_lock);
error = memcg_init_kmem(memcg, &mem_cgroup_subsys);
if (error) {
/*
* We call put now because our (and parent's) refcnts
* are already in place. mem_cgroup_put() will internally
* call __mem_cgroup_free, so return directly
*/
mem_cgroup_put(memcg);
return ERR_PTR(error);
}
return &memcg->css; return &memcg->css;
free_out: free_out:
__mem_cgroup_free(memcg); __mem_cgroup_free(memcg);
...@@ -5033,28 +5038,11 @@ static void mem_cgroup_destroy(struct cgroup *cont) ...@@ -5033,28 +5038,11 @@ static void mem_cgroup_destroy(struct cgroup *cont)
{ {
struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
kmem_cgroup_destroy(cont); kmem_cgroup_destroy(memcg);
mem_cgroup_put(memcg); mem_cgroup_put(memcg);
} }
static int mem_cgroup_populate(struct cgroup_subsys *ss,
struct cgroup *cont)
{
int ret;
ret = cgroup_add_files(cont, ss, mem_cgroup_files,
ARRAY_SIZE(mem_cgroup_files));
if (!ret)
ret = register_memsw_files(cont, ss);
if (!ret)
ret = register_kmem_files(cont, ss);
return ret;
}
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
/* Handlers for move charge at task migration. */ /* Handlers for move charge at task migration. */
#define PRECHARGE_COUNT_AT_ONCE 256 #define PRECHARGE_COUNT_AT_ONCE 256
...@@ -5638,12 +5626,13 @@ struct cgroup_subsys mem_cgroup_subsys = { ...@@ -5638,12 +5626,13 @@ struct cgroup_subsys mem_cgroup_subsys = {
.create = mem_cgroup_create, .create = mem_cgroup_create,
.pre_destroy = mem_cgroup_pre_destroy, .pre_destroy = mem_cgroup_pre_destroy,
.destroy = mem_cgroup_destroy, .destroy = mem_cgroup_destroy,
.populate = mem_cgroup_populate,
.can_attach = mem_cgroup_can_attach, .can_attach = mem_cgroup_can_attach,
.cancel_attach = mem_cgroup_cancel_attach, .cancel_attach = mem_cgroup_cancel_attach,
.attach = mem_cgroup_move_task, .attach = mem_cgroup_move_task,
.base_cftypes = mem_cgroup_files,
.early_init = 0, .early_init = 0,
.use_id = 1, .use_id = 1,
.__DEPRECATED_clear_css_refs = true,
}; };
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
......
...@@ -25,21 +25,6 @@ ...@@ -25,21 +25,6 @@
#include <net/sock.h> #include <net/sock.h>
#include <net/netprio_cgroup.h> #include <net/netprio_cgroup.h>
static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp);
static void cgrp_destroy(struct cgroup *cgrp);
static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp);
struct cgroup_subsys net_prio_subsys = {
.name = "net_prio",
.create = cgrp_create,
.destroy = cgrp_destroy,
.populate = cgrp_populate,
#ifdef CONFIG_NETPRIO_CGROUP
.subsys_id = net_prio_subsys_id,
#endif
.module = THIS_MODULE
};
#define PRIOIDX_SZ 128 #define PRIOIDX_SZ 128
static unsigned long prioidx_map[PRIOIDX_SZ]; static unsigned long prioidx_map[PRIOIDX_SZ];
...@@ -259,12 +244,19 @@ static struct cftype ss_files[] = { ...@@ -259,12 +244,19 @@ static struct cftype ss_files[] = {
.read_map = read_priomap, .read_map = read_priomap,
.write_string = write_priomap, .write_string = write_priomap,
}, },
{ } /* terminate */
}; };
static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp) struct cgroup_subsys net_prio_subsys = {
{ .name = "net_prio",
return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files)); .create = cgrp_create,
} .destroy = cgrp_destroy,
#ifdef CONFIG_NETPRIO_CGROUP
.subsys_id = net_prio_subsys_id,
#endif
.base_cftypes = ss_files,
.module = THIS_MODULE
};
static int netprio_device_event(struct notifier_block *unused, static int netprio_device_event(struct notifier_block *unused,
unsigned long event, void *ptr) unsigned long event, void *ptr)
......
...@@ -143,7 +143,7 @@ static DEFINE_MUTEX(proto_list_mutex); ...@@ -143,7 +143,7 @@ static DEFINE_MUTEX(proto_list_mutex);
static LIST_HEAD(proto_list); static LIST_HEAD(proto_list);
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM #ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss) int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{ {
struct proto *proto; struct proto *proto;
int ret = 0; int ret = 0;
...@@ -151,7 +151,7 @@ int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss) ...@@ -151,7 +151,7 @@ int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss)
mutex_lock(&proto_list_mutex); mutex_lock(&proto_list_mutex);
list_for_each_entry(proto, &proto_list, node) { list_for_each_entry(proto, &proto_list, node) {
if (proto->init_cgroup) { if (proto->init_cgroup) {
ret = proto->init_cgroup(cgrp, ss); ret = proto->init_cgroup(memcg, ss);
if (ret) if (ret)
goto out; goto out;
} }
...@@ -162,19 +162,19 @@ int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss) ...@@ -162,19 +162,19 @@ int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss)
out: out:
list_for_each_entry_continue_reverse(proto, &proto_list, node) list_for_each_entry_continue_reverse(proto, &proto_list, node)
if (proto->destroy_cgroup) if (proto->destroy_cgroup)
proto->destroy_cgroup(cgrp); proto->destroy_cgroup(memcg);
mutex_unlock(&proto_list_mutex); mutex_unlock(&proto_list_mutex);
return ret; return ret;
} }
void mem_cgroup_sockets_destroy(struct cgroup *cgrp) void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg)
{ {
struct proto *proto; struct proto *proto;
mutex_lock(&proto_list_mutex); mutex_lock(&proto_list_mutex);
list_for_each_entry_reverse(proto, &proto_list, node) list_for_each_entry_reverse(proto, &proto_list, node)
if (proto->destroy_cgroup) if (proto->destroy_cgroup)
proto->destroy_cgroup(cgrp); proto->destroy_cgroup(memcg);
mutex_unlock(&proto_list_mutex); mutex_unlock(&proto_list_mutex);
} }
#endif #endif
......
...@@ -6,37 +6,6 @@ ...@@ -6,37 +6,6 @@
#include <linux/memcontrol.h> #include <linux/memcontrol.h>
#include <linux/module.h> #include <linux/module.h>
static u64 tcp_cgroup_read(struct cgroup *cont, struct cftype *cft);
static int tcp_cgroup_write(struct cgroup *cont, struct cftype *cft,
const char *buffer);
static int tcp_cgroup_reset(struct cgroup *cont, unsigned int event);
static struct cftype tcp_files[] = {
{
.name = "kmem.tcp.limit_in_bytes",
.write_string = tcp_cgroup_write,
.read_u64 = tcp_cgroup_read,
.private = RES_LIMIT,
},
{
.name = "kmem.tcp.usage_in_bytes",
.read_u64 = tcp_cgroup_read,
.private = RES_USAGE,
},
{
.name = "kmem.tcp.failcnt",
.private = RES_FAILCNT,
.trigger = tcp_cgroup_reset,
.read_u64 = tcp_cgroup_read,
},
{
.name = "kmem.tcp.max_usage_in_bytes",
.private = RES_MAX_USAGE,
.trigger = tcp_cgroup_reset,
.read_u64 = tcp_cgroup_read,
},
};
static inline struct tcp_memcontrol *tcp_from_cgproto(struct cg_proto *cg_proto) static inline struct tcp_memcontrol *tcp_from_cgproto(struct cg_proto *cg_proto)
{ {
return container_of(cg_proto, struct tcp_memcontrol, cg_proto); return container_of(cg_proto, struct tcp_memcontrol, cg_proto);
...@@ -49,7 +18,7 @@ static void memcg_tcp_enter_memory_pressure(struct sock *sk) ...@@ -49,7 +18,7 @@ static void memcg_tcp_enter_memory_pressure(struct sock *sk)
} }
EXPORT_SYMBOL(memcg_tcp_enter_memory_pressure); EXPORT_SYMBOL(memcg_tcp_enter_memory_pressure);
int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss) int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{ {
/* /*
* The root cgroup does not use res_counters, but rather, * The root cgroup does not use res_counters, but rather,
...@@ -59,13 +28,12 @@ int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss) ...@@ -59,13 +28,12 @@ int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
struct res_counter *res_parent = NULL; struct res_counter *res_parent = NULL;
struct cg_proto *cg_proto, *parent_cg; struct cg_proto *cg_proto, *parent_cg;
struct tcp_memcontrol *tcp; struct tcp_memcontrol *tcp;
struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
struct mem_cgroup *parent = parent_mem_cgroup(memcg); struct mem_cgroup *parent = parent_mem_cgroup(memcg);
struct net *net = current->nsproxy->net_ns; struct net *net = current->nsproxy->net_ns;
cg_proto = tcp_prot.proto_cgroup(memcg); cg_proto = tcp_prot.proto_cgroup(memcg);
if (!cg_proto) if (!cg_proto)
goto create_files; return 0;
tcp = tcp_from_cgproto(cg_proto); tcp = tcp_from_cgproto(cg_proto);
...@@ -88,15 +56,12 @@ int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss) ...@@ -88,15 +56,12 @@ int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated; cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated;
cg_proto->memcg = memcg; cg_proto->memcg = memcg;
create_files: return 0;
return cgroup_add_files(cgrp, ss, tcp_files,
ARRAY_SIZE(tcp_files));
} }
EXPORT_SYMBOL(tcp_init_cgroup); EXPORT_SYMBOL(tcp_init_cgroup);
void tcp_destroy_cgroup(struct cgroup *cgrp) void tcp_destroy_cgroup(struct mem_cgroup *memcg)
{ {
struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
struct cg_proto *cg_proto; struct cg_proto *cg_proto;
struct tcp_memcontrol *tcp; struct tcp_memcontrol *tcp;
u64 val; u64 val;
...@@ -270,3 +235,37 @@ void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx) ...@@ -270,3 +235,37 @@ void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx)
tcp->tcp_prot_mem[idx] = val; tcp->tcp_prot_mem[idx] = val;
} }
static struct cftype tcp_files[] = {
{
.name = "kmem.tcp.limit_in_bytes",
.write_string = tcp_cgroup_write,
.read_u64 = tcp_cgroup_read,
.private = RES_LIMIT,
},
{
.name = "kmem.tcp.usage_in_bytes",
.read_u64 = tcp_cgroup_read,
.private = RES_USAGE,
},
{
.name = "kmem.tcp.failcnt",
.private = RES_FAILCNT,
.trigger = tcp_cgroup_reset,
.read_u64 = tcp_cgroup_read,
},
{
.name = "kmem.tcp.max_usage_in_bytes",
.private = RES_MAX_USAGE,
.trigger = tcp_cgroup_reset,
.read_u64 = tcp_cgroup_read,
},
{ } /* terminate */
};
static int __init tcp_memcontrol_init(void)
{
WARN_ON(cgroup_add_cftypes(&mem_cgroup_subsys, tcp_files));
return 0;
}
__initcall(tcp_memcontrol_init);
...@@ -22,22 +22,6 @@ ...@@ -22,22 +22,6 @@
#include <net/sock.h> #include <net/sock.h>
#include <net/cls_cgroup.h> #include <net/cls_cgroup.h>
static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp);
static void cgrp_destroy(struct cgroup *cgrp);
static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp);
struct cgroup_subsys net_cls_subsys = {
.name = "net_cls",
.create = cgrp_create,
.destroy = cgrp_destroy,
.populate = cgrp_populate,
#ifdef CONFIG_NET_CLS_CGROUP
.subsys_id = net_cls_subsys_id,
#endif
.module = THIS_MODULE,
};
static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp) static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp)
{ {
return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id), return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id),
...@@ -86,12 +70,19 @@ static struct cftype ss_files[] = { ...@@ -86,12 +70,19 @@ static struct cftype ss_files[] = {
.read_u64 = read_classid, .read_u64 = read_classid,
.write_u64 = write_classid, .write_u64 = write_classid,
}, },
{ } /* terminate */
}; };
static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp) struct cgroup_subsys net_cls_subsys = {
{ .name = "net_cls",
return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files)); .create = cgrp_create,
} .destroy = cgrp_destroy,
#ifdef CONFIG_NET_CLS_CGROUP
.subsys_id = net_cls_subsys_id,
#endif
.base_cftypes = ss_files,
.module = THIS_MODULE,
};
struct cls_cgroup_head { struct cls_cgroup_head {
u32 handle; u32 handle;
......
...@@ -447,22 +447,16 @@ static struct cftype dev_cgroup_files[] = { ...@@ -447,22 +447,16 @@ static struct cftype dev_cgroup_files[] = {
.read_seq_string = devcgroup_seq_read, .read_seq_string = devcgroup_seq_read,
.private = DEVCG_LIST, .private = DEVCG_LIST,
}, },
{ } /* terminate */
}; };
static int devcgroup_populate(struct cgroup_subsys *ss,
struct cgroup *cgroup)
{
return cgroup_add_files(cgroup, ss, dev_cgroup_files,
ARRAY_SIZE(dev_cgroup_files));
}
struct cgroup_subsys devices_subsys = { struct cgroup_subsys devices_subsys = {
.name = "devices", .name = "devices",
.can_attach = devcgroup_can_attach, .can_attach = devcgroup_can_attach,
.create = devcgroup_create, .create = devcgroup_create,
.destroy = devcgroup_destroy, .destroy = devcgroup_destroy,
.populate = devcgroup_populate,
.subsys_id = devices_subsys_id, .subsys_id = devices_subsys_id,
.base_cftypes = dev_cgroup_files,
}; };
int __devcgroup_inode_permission(struct inode *inode, int mask) int __devcgroup_inode_permission(struct inode *inode, int mask)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment