Skip to contentSkip to conversation

netprio_cgroup: implement hierarchy support

PATCH In review Tejun Heo 10 participants 28 messages Nov 16, 2012 – Nov 20, 2012 5 messages not in the archive

Subsystems (3)
lore
Share & tools
lore

Tejun Heo

author maintainer
#0 lore raw

PATCH 1/1 netprio_cgroup: implement hierarchy support

Hello, guys.

This patchset implements hierarchy support for netprio_cgroup. netprio_cgroup along with netcls_cgroup is a rather weird in that it really isn't about resource control. It just hitches on cgroup as a convenient mechanism to do stuff to groups of tasks. The hierarchy support reflects such nature. There's no limit being imposed from ancestors. It simply propagates configuration downwards until there's a node with its own config. IOW, any given cgroup inherits priorities from its parent for all netdevs which it doesn't have its own config for.

As a parent isn't affected by child inheriting its config, the hierarchy implementation is pretty simple. It's enough to inherit config from ->css_online() and propagate new config downwards from write_priomap(). As each node needs to know which config is its local one and which is inherited, an extra config array is added - netprio_map->aux[]. It's a separate array to avoid disturbing spatial locality of ->priomap[]. While it currently contains single one-bit flag, I still made it a struct so that adding more configuration (e.g. max_prio) is easy.

Note that this does change userland-visible behavior. Now, nesting is allowed and cgroups at the first level inherit priorities from the root cgroup. I can't think of any better way than just biting the bullet here. :(

0001-cgroup-add-cgroup-id.patch 0002-netprio-simplify-write_priomap.patch 0003-netprio_cgroup-shorten-variable-names-in-extend_netd.patch 0004-netprio_cgroup-reimplement-priomap-expansion.patch 0005-netprio_cgroup-use-cgroup-id-instead-of-cgroup_netpr.patch 0006-netprio_cgroup-implement-netprio-_set-_prio-helpers.patch 0007-netprio_cgroup-keep-track-of-whether-prio-is-set-or-.patch 0008-netprio_cgroup-implement-hierarchy-support.patch

0001 adds cgroup->id. This will eventually replace css_id.

0002-0006 are prep patches.

0007 implements is_local flag which tracks whether a cgroup has its own config or should inherit from its parent.

0008 implements hierarchy support.

This patchset is on top of

cgroup/for-3.8 ef9fe980c6 ("cgroup_freezer: implement proper hierarchy support")
+ [1] "[PATCHSET cgroup/for-3.8] cgroup: allow ->post_create() to fail"
+ [2] "[PATCH 1/2] cgroup: s/CGRP_CLONE_CHILDREN/CGRP_CPUSET_CLONE_CHILDREN/"

      "[PATCH 2/2] cgroup, cpuset: remove cgroup_subsys->post_clone()"

and available in the following git branch.

git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git review-netprio_cgroup-hierarchy

diffstat follows.

 Documentation/cgroups/net_prio.txt |   21 +-
 include/linux/cgroup.h             |    2
 include/net/netprio_cgroup.h       |   21 +-
 kernel/cgroup.c                    |   15 +
 net/core/netprio_cgroup.c          |  376 +++++++++++++++++++++++--------------
 5 files changed, 284 insertions(+), 151 deletions(-)

Thanks.

--
tejun

[1] http://thread.gmane.org/gmane.linux.kernel.cgroups/5047
[2] http://thread.gmane.org/gmane.linux.kernel/1393151

author maintainer
#1 lore raw

PATCH 1/8 cgroup: add cgroup->id

With the introduction of generic cgroup hierarchy iterators, css_id is being phased out. It was unnecessarily complex, id'ing the wrong thing (cgroups need IDs, not CSSes) and has other oddities like not being available at ->css_alloc().

This patch adds cgroup->id, which is a simple per-hierarchy ida-allocated ID which is assigned before ->css_alloc() and released after ->css_free().

---
 include/linux/cgroup.h |  2 ++
 kernel/cgroup.c        | 15 ++++++++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)
include/linux/cgroup.h +2 -0
index d5fc8a7..b512469 100644
@@ -159,6 +159,8 @@ struct cgroup {
 	 */
 	atomic_t count;
 
+	int id;				/* ida allocated in-hierarchy ID */
+
 	/*
 	 * We link our 'sibling' struct into our parent's 'children'.
 	 * Our children link their 'sibling' into our 'children'.
kernel/cgroup.c +14 -1
index 99d5e69..0b25dcb 100644
@@ -138,6 +138,9 @@ struct cgroupfs_root {
 	/* Hierarchy-specific flags */
 	unsigned long flags;
 
+	/* IDs for cgroups in this hierarchy */
+	struct ida cgroup_ida;
+
 	/* The path to use for release notifications. */
 	char release_agent_path[PATH_MAX];
 
@@ -890,6 +893,7 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
 
 		simple_xattrs_free(&cgrp->xattrs);
 
+		ida_simple_remove(&cgrp->root->cgroup_ida, cgrp->id);
 		kfree(cgrp);
 	} else {
 		struct cfent *cfe = __d_cfe(dentry);
@@ -1465,6 +1469,7 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts)
 
 	root->subsys_mask = opts->subsys_mask;
 	root->flags = opts->flags;
+	ida_init(&root->cgroup_ida);
 	if (opts->release_agent)
 		strcpy(root->release_agent_path, opts->release_agent);
 	if (opts->name)
@@ -1483,6 +1488,7 @@ static void cgroup_drop_root(struct cgroupfs_root *root)
 	spin_lock(&hierarchy_id_lock);
 	ida_remove(&hierarchy_ida, root->hierarchy_id);
 	spin_unlock(&hierarchy_id_lock);
+	ida_destroy(&root->cgroup_ida);
 	kfree(root);
 }
 
@@ -4093,10 +4099,15 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
 	struct cgroup_subsys *ss;
 	struct super_block *sb = root->sb;
 
+	/* allocate the cgroup and its ID, 0 is reserved for the root */
 	cgrp = kzalloc(sizeof(*cgrp), GFP_KERNEL);
 	if (!cgrp)
 		return -ENOMEM;
 
+	cgrp->id = ida_simple_get(&root->cgroup_ida, 1, 0, GFP_KERNEL);
+	if (cgrp->id < 0)
+		goto err_free_cgrp;
+
 	/*
 	 * Only live parents can have children.  Note that the liveliness
 	 * check isn't strictly necessary because cgroup_mkdir() and
@@ -4106,7 +4117,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
 	 */
 	if (!cgroup_lock_live_group(parent)) {
 		err = -ENODEV;
-		goto err_free_cgrp;
+		goto err_free_id;
 	}
 
 	/* Grab a reference on the superblock so the hierarchy doesn't
@@ -4198,6 +4209,8 @@ err_free_all:
 	mutex_unlock(&cgroup_mutex);
 	/* Release the reference count that we took on the superblock */
 	deactivate_super(sb);
+err_free_id:
+	ida_simple_remove(&root->cgroup_ida, cgrp->id);
 err_free_cgrp:
 	kfree(cgrp);
 	return err;
Signature · 1 line
1.7.11.7
Acked-by on v1 1/8
#2 lore raw

Re: [PATCH 1/8] cgroup: add cgroup->id

Quoted 10 lines · Tejun Heo

With the introduction of generic cgroup hierarchy iterators, css_id is being phased out. It was unnecessarily complex, id'ing the wrong thing (cgroups need IDs, not CSSes) and has other oddities like not being available at ->css_alloc().

This patch adds cgroup->id, which is a simple per-hierarchy ida-allocated ID which is assigned before ->css_alloc() and released after ->css_free().

author maintainer Applied
#3 lore raw

Re: [PATCH 1/8] cgroup: add cgroup->id

Quoted 6 lines · Li Zefan
Quoted 5 lines · Tejun Heo

With the introduction of generic cgroup hierarchy iterators, css_id is being phased out. It was unnecessarily complex, id'ing the wrong thing (cgroups need IDs, not CSSes) and has other oddities like not being available at ->css_alloc().

Quoted 7 lines
Quoted 5 lines

This patch adds cgroup->id, which is a simple per-hierarchy ida-allocated ID which is assigned before ->css_alloc() and released after ->css_free().

Applied to cgroup/for-3.8.

Thanks.

Signature · 1 line
tejun

A message that is not in the archive (sent off-list or not yet received): 1353093624-22608-2-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org

Acked-by
#5 lore raw

Re: [PATCH 1/8] cgroup: add cgroup->id

Quoted 10 lines · Tejun Heo

With the introduction of generic cgroup hierarchy iterators, css_id is being phased out. It was unnecessarily complex, id'ing the wrong thing (cgroups need IDs, not CSSes) and has other oddities like not being available at ->css_alloc().

This patch adds cgroup->id, which is a simple per-hierarchy ida-allocated ID which is assigned before ->css_alloc() and released after ->css_free().

#6 lore raw

Re: [PATCH 1/8] cgroup: add cgroup->id

In reply to Tejun Heo
Quoted 10 lines · Tejun Heo

With the introduction of generic cgroup hierarchy iterators, css_id is being phased out. It was unnecessarily complex, id'ing the wrong thing (cgroups need IDs, not CSSes) and has other oddities like not being available at ->css_alloc().

This patch adds cgroup->id, which is a simple per-hierarchy ida-allocated ID which is assigned before ->css_alloc() and released after ->css_free().

I'm sorry if I misunderstand ... current usage of css-id in memory/swap cgroup is for recording information of memory cgroup which may be destroyed. In some case, a memcg's cgroup is freed but a struct memcgroup and its css are available, swap_cgroup may contain id ot if.
This patch puts cgroup's id at diput(), so, the id used in swap_cgroup can be reused while it's in use. Right ?

Thanks,
-Kame

Quoted 91 lines
---
  include/linux/cgroup.h |  2 ++
  kernel/cgroup.c        | 15 ++++++++++++++-
  2 files changed, 16 insertions(+), 1 deletion(-)
include/linux/cgroup.h +2 -0
index d5fc8a7..b512469 100644
@@ -159,6 +159,8 @@ struct cgroup {
  	 */
  	atomic_t count;
 
+	int id;				/* ida allocated in-hierarchy ID */
+
  	/*
  	 * We link our 'sibling' struct into our parent's 'children'.
  	 * Our children link their 'sibling' into our 'children'.
kernel/cgroup.c +14 -1
index 99d5e69..0b25dcb 100644
@@ -138,6 +138,9 @@ struct cgroupfs_root {
  	/* Hierarchy-specific flags */
  	unsigned long flags;
 
+	/* IDs for cgroups in this hierarchy */
+	struct ida cgroup_ida;
+
  	/* The path to use for release notifications. */
  	char release_agent_path[PATH_MAX];
 
@@ -890,6 +893,7 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
 
  		simple_xattrs_free(&cgrp->xattrs);
 
+		ida_simple_remove(&cgrp->root->cgroup_ida, cgrp->id);
  		kfree(cgrp);
  	} else {
  		struct cfent *cfe = __d_cfe(dentry);
@@ -1465,6 +1469,7 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts)
 
  	root->subsys_mask = opts->subsys_mask;
  	root->flags = opts->flags;
+	ida_init(&root->cgroup_ida);
  	if (opts->release_agent)
  		strcpy(root->release_agent_path, opts->release_agent);
  	if (opts->name)
@@ -1483,6 +1488,7 @@ static void cgroup_drop_root(struct cgroupfs_root *root)
  	spin_lock(&hierarchy_id_lock);
  	ida_remove(&hierarchy_ida, root->hierarchy_id);
  	spin_unlock(&hierarchy_id_lock);
+	ida_destroy(&root->cgroup_ida);
  	kfree(root);
  }
 
@@ -4093,10 +4099,15 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
  	struct cgroup_subsys *ss;
  	struct super_block *sb = root->sb;
 
+	/* allocate the cgroup and its ID, 0 is reserved for the root */
  	cgrp = kzalloc(sizeof(*cgrp), GFP_KERNEL);
  	if (!cgrp)
  		return -ENOMEM;
 
+	cgrp->id = ida_simple_get(&root->cgroup_ida, 1, 0, GFP_KERNEL);
+	if (cgrp->id < 0)
+		goto err_free_cgrp;
+
  	/*
  	 * Only live parents can have children.  Note that the liveliness
  	 * check isn't strictly necessary because cgroup_mkdir() and
@@ -4106,7 +4117,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
  	 */
  	if (!cgroup_lock_live_group(parent)) {
  		err = -ENODEV;
-		goto err_free_cgrp;
+		goto err_free_id;
  	}
 
  	/* Grab a reference on the superblock so the hierarchy doesn't
@@ -4198,6 +4209,8 @@ err_free_all:
  	mutex_unlock(&cgroup_mutex);
  	/* Release the reference count that we took on the superblock */
  	deactivate_super(sb);
+err_free_id:
+	ida_simple_remove(&root->cgroup_ida, cgrp->id);
  err_free_cgrp:
  	kfree(cgrp);
  	return err;
author maintainer
#7 lore raw

Re: [PATCH 1/8] cgroup: add cgroup->id

Hello, Kamezawa.

Quoted 6 lines · Kamezawa Hiroyuki

I'm sorry if I misunderstand ... current usage of css-id in memory/swap cgroup is for recording information of memory cgroup which may be destroyed. In some case, a memcg's cgroup is freed but a struct memcgroup and its css are available, swap_cgroup may contain id ot if.
This patch puts cgroup's id at diput(), so, the id used in swap_cgroup can be reused while it's in use. Right ?

CSSes hold onto cgroups, so if memcg is around, its cgroup doesn't go away, so the right thing to do would be holding onto CSS whlie there are remaining references, which IMHO is the way it should have been implemented from the beginning. The only reason memcg currently has its own refcnt nested inside css refcnt is because cgroup used to require css refs to be completely drained for cgroup_rmdir() to proceed. Now that that weirdity is gone, we should go back to sane css based reference counting, right?

Thanks.

Signature · 1 line
tejun
#8 lore raw

Re: [PATCH 1/8] cgroup: add cgroup->id

Quoted 10 lines · Tejun Heo

Hello, Kamezawa.

Quoted 6 lines · Kamezawa Hiroyuki

I'm sorry if I misunderstand ... current usage of css-id in memory/swap cgroup is for recording information of memory cgroup which may be destroyed. In some case, a memcg's cgroup is freed but a struct memcgroup and its css are available, swap_cgroup may contain id ot if.
This patch puts cgroup's id at diput(), so, the id used in swap_cgroup can be reused while it's in use. Right ?

Quoted 9 lines

CSSes hold onto cgroups, so if memcg is around, its cgroup doesn't go away, so the right thing to do would be holding onto CSS whlie there are remaining references, which IMHO is the way it should have been implemented from the beginning. The only reason memcg currently has its own refcnt nested inside css refcnt is because cgroup used to require css refs to be completely drained for cgroup_rmdir() to proceed. Now that that weirdity is gone, we should go back to sane css based reference counting, right?

Ah, hm, Maybe I missed new __css_put() implementation...

Quoted 13 lines

void __css_put(struct cgroup_subsys_state *css)

{
        struct cgroup *cgrp = css->cgroup;
        int v;

        rcu_read_lock();
        v = css_unbias_refcnt(atomic_dec_return(&css->refcnt));

        switch (v) {
        case 1:
                if (notify_on_release(cgrp)) {
                        set_bit(CGRP_RELEASABLE, &cgrp->flags);
                        check_for_release(cgrp);
Quoted 8 lines
                }
                break;
        case 0:
                schedule_work(&css->dput_work);
                break;
        }
        rcu_read_unlock();
}

If swap_cgroup holds css's refcnt instead of memcg's.... final dput will be invoked when the last swap_cgroup release a reference.

It seems to work and we can drop memcg's refcnt (maybe).

BTW, css's ID was limited to 65535 to be encoded in 2bytes. If we use INT, this will increase size of swap_cgroup. (2bytes per page => 4bytes per page) It's preallocated at swapon() because allocating memory dynamically when we swap a memory is not good.

Do we really need 4bytes for ID ? If so, swap_cgroup should be totally re-designed.

Thanks,
-Kame

author maintainer
#9 lore raw

Re: [PATCH 1/8] cgroup: add cgroup->id

Hello, Kamezawa.

Quoted 6 lines · Kamezawa Hiroyuki

BTW, css's ID was limited to 65535 to be encoded in 2bytes. If we use INT, this will increase size of swap_cgroup. (2bytes per page => 4bytes per page) It's preallocated at swapon() because allocating memory dynamically when we swap a memory is not good.

Do we really need 4bytes for ID ? If so, swap_cgroup should be totally re-designed.

That's a memcg restriction which shouldn't have been imposed on cgroup core from the beginning. What memcg should do is rejecting to become online from ->css_onilne() if cgrp->id is out of the range it can handle.

Thanks.

Signature · 1 line
tejun
#10 lore raw

Re: [PATCH 1/8] cgroup: add cgroup->id

Quoted 8 lines · Tejun Heo

Hello, Kamezawa.

Quoted 5 lines · Kamezawa Hiroyuki

BTW, css's ID was limited to 65535 to be encoded in 2bytes. If we use INT, this will increase size of swap_cgroup. (2bytes per page => 4bytes per page) It's preallocated at swapon() because allocating memory dynamically when we swap a memory is not good.

Quoted 7 lines
Quoted 1 line

Do we really need 4bytes for ID ? If so, swap_cgroup should be totally re-designed.

That's a memcg restriction which shouldn't have been imposed on cgroup core from the beginning. What memcg should do is rejecting to become online from ->css_onilne() if cgrp->id is out of the range it can handle.

Hmm. I'll think a little and consider a patch to remove memcg's refcnt.

Thanks,
-Kame

A message that is not in the archive (sent off-list or not yet received): [email protected]

#12 lore raw

Re: [PATCH 1/8] cgroup: add cgroup->id

Hello, Kamezawa.

Quoted 6 lines · Kamezawa Hiroyuki

BTW, css's ID was limited to 65535 to be encoded in 2bytes. If we use INT, this will increase size of swap_cgroup. (2bytes per page => 4bytes per page) It's preallocated at swapon() because allocating memory dynamically when we swap a memory is not good.

Do we really need 4bytes for ID ? If so, swap_cgroup should be totally re-designed.

That's a memcg restriction which shouldn't have been imposed on cgroup core from the beginning. What memcg should do is rejecting to become online from ->css_onilne() if cgrp->id is out of the range it can handle.

Thanks.

Signature · 1 line
tejun
#13 lore raw

Re: [PATCH 1/8] cgroup: add cgroup->id

In reply to a message not in the archive
Quoted 54 lines · Kamezawa Hiroyuki
Quoted 14 lines · Tejun Heo

Hello, Kamezawa.

Quoted 10 lines · Kamezawa Hiroyuki

I'm sorry if I misunderstand ... current usage of css-id in memory/swap cgroup
is for recording information of memory cgroup which may be destroyed. In some case,
a memcg's cgroup is freed but a struct memcgroup and its css are available, swap_cgroup
may contain id ot if.
This patch puts cgroup's id at diput(), so, the id used in swap_cgroup can be
reused while it's in use. Right ?

Quoted 9 lines

CSSes hold onto cgroups, so if memcg is around, its cgroup doesn't go away, so the right thing to do would be holding onto CSS whlie there are remaining references, which IMHO is the way it should have been implemented from the beginning. The only reason memcg currently has its own refcnt nested inside css refcnt is because cgroup used to require css refs to be completely drained for cgroup_rmdir() to proceed. Now that that weirdity is gone, we should go back to sane css based reference counting, right?

Ah, hm, Maybe I missed new __css_put() implementation...

Quoted 13 lines

void __css_put(struct cgroup_subsys_state *css)

{
        struct cgroup *cgrp = css->cgroup;
        int v;

        rcu_read_lock();
        v = css_unbias_refcnt(atomic_dec_return(&css->refcnt));

        switch (v) {
        case 1:
                if (notify_on_release(cgrp)) {
                        set_bit(CGRP_RELEASABLE, &cgrp->flags);
                        check_for_release(cgrp);
Quoted 8 lines
                }
                break;
        case 0:
                schedule_work(&css->dput_work);
                break;
        }
        rcu_read_unlock();
}

If swap_cgroup holds css's refcnt instead of memcg's.... final dput will be invoked when the last swap_cgroup release a reference.

It seems to work and we can drop memcg's refcnt (maybe).

Quoted 8 lines

BTW, css's ID was limited to 65535 to be encoded in 2bytes. If we use INT, this will increase size of swap_cgroup. (2bytes per page => 4bytes per page) It's preallocated at swapon() because allocating memory dynamically when we swap a memory is not good.

Do we really need 4bytes for ID ? If so, swap_cgroup should be totally re-designed.

For the record, I've already came to the conclusion myself that swap_cgroup should be redesigned for this very same reason. (I was testing it a while ago). I haven't had much time to think about it, though. But I was considering using the memcg address itself, in a sparsely populated structure.

#14 lore raw

Re: [PATCH 1/8] cgroup: add cgroup->id

In reply to Kamezawa Hiroyuki
Quoted 54 lines · Kamezawa Hiroyuki
Quoted 14 lines · Tejun Heo

Hello, Kamezawa.

Quoted 10 lines · Kamezawa Hiroyuki

I'm sorry if I misunderstand ... current usage of css-id in memory/swap cgroup
is for recording information of memory cgroup which may be destroyed. In some case,
a memcg's cgroup is freed but a struct memcgroup and its css are available, swap_cgroup
may contain id ot if.
This patch puts cgroup's id at diput(), so, the id used in swap_cgroup can be
reused while it's in use. Right ?

Quoted 9 lines

CSSes hold onto cgroups, so if memcg is around, its cgroup doesn't go away, so the right thing to do would be holding onto CSS whlie there are remaining references, which IMHO is the way it should have been implemented from the beginning. The only reason memcg currently has its own refcnt nested inside css refcnt is because cgroup used to require css refs to be completely drained for cgroup_rmdir() to proceed. Now that that weirdity is gone, we should go back to sane css based reference counting, right?

Ah, hm, Maybe I missed new __css_put() implementation...

Quoted 13 lines

void __css_put(struct cgroup_subsys_state *css)

{
        struct cgroup *cgrp = css->cgroup;
        int v;

        rcu_read_lock();
        v = css_unbias_refcnt(atomic_dec_return(&css->refcnt));

        switch (v) {
        case 1:
                if (notify_on_release(cgrp)) {
                        set_bit(CGRP_RELEASABLE, &cgrp->flags);
                        check_for_release(cgrp);
Quoted 8 lines
                }
                break;
        case 0:
                schedule_work(&css->dput_work);
                break;
        }
        rcu_read_unlock();
}

If swap_cgroup holds css's refcnt instead of memcg's.... final dput will be invoked when the last swap_cgroup release a reference.

It seems to work and we can drop memcg's refcnt (maybe).

Quoted 8 lines

BTW, css's ID was limited to 65535 to be encoded in 2bytes. If we use INT, this will increase size of swap_cgroup. (2bytes per page => 4bytes per page) It's preallocated at swapon() because allocating memory dynamically when we swap a memory is not good.

Do we really need 4bytes for ID ? If so, swap_cgroup should be totally re-designed.

For the record, I've already came to the conclusion myself that swap_cgroup should be redesigned for this very same reason. (I was testing it a while ago). I haven't had much time to think about it, though. But I was considering using the memcg address itself, in a sparsely populated structure.

A message that is not in the archive (sent off-list or not yet received): [email protected]

#16 lore raw

Re: [PATCH 1/8] cgroup: add cgroup->id

Hello, Kamezawa.

Quoted 6 lines · Kamezawa Hiroyuki

I'm sorry if I misunderstand ... current usage of css-id in memory/swap cgroup is for recording information of memory cgroup which may be destroyed. In some case, a memcg's cgroup is freed but a struct memcgroup and its css are available, swap_cgroup may contain id ot if.
This patch puts cgroup's id at diput(), so, the id used in swap_cgroup can be reused while it's in use. Right ?

CSSes hold onto cgroups, so if memcg is around, its cgroup doesn't go away, so the right thing to do would be holding onto CSS whlie there are remaining references, which IMHO is the way it should have been implemented from the beginning. The only reason memcg currently has its own refcnt nested inside css refcnt is because cgroup used to require css refs to be completely drained for cgroup_rmdir() to proceed. Now that that weirdity is gone, we should go back to sane css based reference counting, right?

Thanks.

Signature · 1 line
tejun
author maintainer
#17 lore raw

PATCH 2/8 netprio: simplify write_priomap()

In reply to Tejun Heo

sscanf() doesn't bite.

---
 net/core/netprio_cgroup.c | 56 ++++++++++-------------------------------------
 1 file changed, 11 insertions(+), 45 deletions(-)
net/core/netprio_cgroup.c +11 -45
index f0b6b0d..66d98da 100644
@@ -176,66 +176,32 @@ static int read_priomap(struct cgroup *cont, struct cftype *cft,
 static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
 			 const char *buffer)
 {
-	char *devname = kstrdup(buffer, GFP_KERNEL);
-	int ret = -EINVAL;
 	u32 prioidx = cgrp_netprio_state(cgrp)->prioidx;
-	unsigned long priority;
-	char *priostr;
+	char devname[IFNAMSIZ + 1];
 	struct net_device *dev;
 	struct netprio_map *map;
+	u32 prio;
+	int ret;
 
-	if (!devname)
-		return -ENOMEM;
-
-	/*
-	 * Minimally sized valid priomap string
-	 */
-	if (strlen(devname) < 3)
-		goto out_free_devname;
-
-	priostr = strstr(devname, " ");
-	if (!priostr)
-		goto out_free_devname;
-
-	/*
-	 *Separate the devname from the associated priority
-	 *and advance the priostr pointer to the priority value
-	 */
-	*priostr = '\0';
-	priostr++;
-
-	/*
-	 * If the priostr points to NULL, we're at the end of the passed
-	 * in string, and its not a valid write
-	 */
-	if (*priostr == '\0')
-		goto out_free_devname;
-
-	ret = kstrtoul(priostr, 10, &priority);
-	if (ret < 0)
-		goto out_free_devname;
-
-	ret = -ENODEV;
+	if (sscanf(buffer, "%"__stringify(IFNAMSIZ)"s %u", devname, &prio) != 2)
+		return -EINVAL;
 
 	dev = dev_get_by_name(&init_net, devname);
 	if (!dev)
-		goto out_free_devname;
+		return -ENODEV;
 
 	rtnl_lock();
+
 	ret = write_update_netdev_table(dev);
-	if (ret < 0)
-		goto out_put_dev;
+	if (ret)
+		goto out_unlock;
 
 	map = rtnl_dereference(dev->priomap);
 	if (map)
-		map->priomap[prioidx] = priority;
-
-out_put_dev:
+		map->priomap[prioidx] = prio;
+out_unlock:
 	rtnl_unlock();
 	dev_put(dev);
-
-out_free_devname:
-	kfree(devname);
 	return ret;
 }
 
Signature · 1 line
1.7.11.7
author maintainer
#18 lore raw

PATCH 3/8 netprio_cgroup: shorten variable names in extend_netdev_table()

In reply to Tejun Heo

The function is about to go through a rewrite. In preparation, shorten the variable names so that we don't repeat "priomap" so often.

This patch is cosmetic.

---
 net/core/netprio_cgroup.c | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)
net/core/netprio_cgroup.c +11 -12
index 66d98da..92cc54c 100644
@@ -71,26 +71,25 @@ static int extend_netdev_table(struct net_device *dev, u32 new_len)
 {
 	size_t new_size = sizeof(struct netprio_map) +
 			   ((sizeof(u32) * new_len));
-	struct netprio_map *new_priomap = kzalloc(new_size, GFP_KERNEL);
-	struct netprio_map *old_priomap;
+	struct netprio_map *new = kzalloc(new_size, GFP_KERNEL);
+	struct netprio_map *old;
 
-	old_priomap  = rtnl_dereference(dev->priomap);
+	old = rtnl_dereference(dev->priomap);
 
-	if (!new_priomap) {
+	if (!new) {
 		pr_warn("Unable to alloc new priomap!\n");
 		return -ENOMEM;
 	}
 
-	if (old_priomap)
-		memcpy(new_priomap->priomap, old_priomap->priomap,
-		       old_priomap->priomap_len *
-		       sizeof(old_priomap->priomap[0]));
+	if (old)
+		memcpy(new->priomap, old->priomap,
+		       old->priomap_len * sizeof(old->priomap[0]));
 
-	new_priomap->priomap_len = new_len;
+	new->priomap_len = new_len;
 
-	rcu_assign_pointer(dev->priomap, new_priomap);
-	if (old_priomap)
-		kfree_rcu(old_priomap, rcu);
+	rcu_assign_pointer(dev->priomap, new);
+	if (old)
+		kfree_rcu(old, rcu);
 	return 0;
 }
 
Signature · 1 line
1.7.11.7
author maintainer
#19 lore raw

PATCH 4/8 netprio_cgroup: reimplement priomap expansion

In reply to Tejun Heo

netprio kept track of the highest prioidx allocated and resized priomaps accordingly when necessary. This makes it necessary to keep track of prioidx allocation and may end up resizing on every new prioidx.

Update extend_netdev_table() such that it takes @target_idx which the priomap should be able to accomodate. If the priomap is large enough, nothing happens; otherwise, the size is doubled until @target_idx can be accomodated.

This makes max_prioidx and write_update_netdev_table() unnecessary. write_priomap() now calls extend_netdev_table() directly.

---
 net/core/netprio_cgroup.c | 56 ++++++++++++++++++++++++++++-------------------
 1 file changed, 33 insertions(+), 23 deletions(-)
net/core/netprio_cgroup.c +33 -23
index 92cc54c..569d83d 100644
@@ -27,11 +27,11 @@
 
 #include <linux/fdtable.h>
 
+#define PRIOMAP_MIN_SZ		128
 #define PRIOIDX_SZ 128
 
 static unsigned long prioidx_map[PRIOIDX_SZ];
 static DEFINE_SPINLOCK(prioidx_map_lock);
-static atomic_t max_prioidx = ATOMIC_INIT(0);
 
 static inline struct cgroup_netprio_state *cgrp_netprio_state(struct cgroup *cgrp)
 {
@@ -51,8 +51,6 @@ static int get_prioidx(u32 *prio)
 		return -ENOSPC;
 	}
 	set_bit(prioidx, prioidx_map);
-	if (atomic_read(&max_prioidx) < prioidx)
-		atomic_set(&max_prioidx, prioidx);
 	spin_unlock_irqrestore(&prioidx_map_lock, flags);
 	*prio = prioidx;
 	return 0;
@@ -67,15 +65,40 @@ static void put_prioidx(u32 idx)
 	spin_unlock_irqrestore(&prioidx_map_lock, flags);
 }
 
-static int extend_netdev_table(struct net_device *dev, u32 new_len)
+/*
+ * Extend @dev->priomap so that it's large enough to accomodate
+ * @target_idx.  @dev->priomap.priomap_len > @target_idx after successful
+ * return.  Must be called under rtnl lock.
+ */
+static int extend_netdev_table(struct net_device *dev, u32 target_idx)
 {
-	size_t new_size = sizeof(struct netprio_map) +
-			   ((sizeof(u32) * new_len));
-	struct netprio_map *new = kzalloc(new_size, GFP_KERNEL);
-	struct netprio_map *old;
+	struct netprio_map *old, *new;
+	size_t new_sz, new_len;
 
+	/* is the existing priomap large enough? */
 	old = rtnl_dereference(dev->priomap);
+	if (old && old->priomap_len > target_idx)
+		return 0;
+
+	/*
+	 * Determine the new size.  Let's keep it power-of-two.  We start
+	 * from PRIOMAP_MIN_SZ and double it until it's large enough to
+	 * accommodate @target_idx.
+	 */
+	new_sz = PRIOMAP_MIN_SZ;
+	while (true) {
+		new_len = (new_sz - offsetof(struct netprio_map, priomap)) /
+			sizeof(new->priomap[0]);
+		if (new_len > target_idx)
+			break;
+		new_sz *= 2;
+		/* overflowed? */
+		if (WARN_ON(new_sz < PRIOMAP_MIN_SZ))
+			return -ENOSPC;
+	}
 
+	/* allocate & copy */
+	new = kzalloc(new_sz, GFP_KERNEL);
 	if (!new) {
 		pr_warn("Unable to alloc new priomap!\n");
 		return -ENOMEM;
@@ -87,26 +110,13 @@ static int extend_netdev_table(struct net_device *dev, u32 new_len)
 
 	new->priomap_len = new_len;
 
+	/* install the new priomap */
 	rcu_assign_pointer(dev->priomap, new);
 	if (old)
 		kfree_rcu(old, rcu);
 	return 0;
 }
 
-static int write_update_netdev_table(struct net_device *dev)
-{
-	int ret = 0;
-	u32 max_len;
-	struct netprio_map *map;
-
-	max_len = atomic_read(&max_prioidx) + 1;
-	map = rtnl_dereference(dev->priomap);
-	if (!map || map->priomap_len < max_len)
-		ret = extend_netdev_table(dev, max_len);
-
-	return ret;
-}
-
 static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
 {
 	struct cgroup_netprio_state *cs;
@@ -191,7 +201,7 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
 
 	rtnl_lock();
 
-	ret = write_update_netdev_table(dev);
+	ret = extend_netdev_table(dev, prioidx);
 	if (ret)
 		goto out_unlock;
 
Signature · 1 line
1.7.11.7
author maintainer
#20 lore raw

PATCH 5/8 netprio_cgroup: use cgroup->id instead of cgroup_netprio_state->prioidx

In reply to Tejun Heo

With priomap expansion no longer depending on knowing max id allocated, netprio_cgroup can use cgroup->id insted of cs->prioidx. Drop prioidx alloc/free logic and convert all uses to cgroup->id.

* In cgrp_css_alloc(), parent->id test is moved above @cs allocation to simplify error path.

* In cgrp_css_free(), @cs assignment is made initialization.

---
 include/net/netprio_cgroup.h | 11 +++-----
 net/core/netprio_cgroup.c    | 65 ++++++++------------------------------------
 2 files changed, 15 insertions(+), 61 deletions(-)
include/net/netprio_cgroup.h +4 -7
index 2760f4f..1d04b6f 100644
@@ -27,7 +27,6 @@ struct netprio_map {
 
 struct cgroup_netprio_state {
 	struct cgroup_subsys_state css;
-	u32 prioidx;
 };
 
 extern void sock_update_netprioidx(struct sock *sk, struct task_struct *task);
@@ -36,13 +35,12 @@ extern void sock_update_netprioidx(struct sock *sk, struct task_struct *task);
 
 static inline u32 task_netprioidx(struct task_struct *p)
 {
-	struct cgroup_netprio_state *state;
+	struct cgroup_subsys_state *css;
 	u32 idx;
 
 	rcu_read_lock();
-	state = container_of(task_subsys_state(p, net_prio_subsys_id),
-			     struct cgroup_netprio_state, css);
-	idx = state->prioidx;
+	css = task_subsys_state(p, net_prio_subsys_id);
+	idx = css->cgroup->id;
 	rcu_read_unlock();
 	return idx;
 }
@@ -57,8 +55,7 @@ static inline u32 task_netprioidx(struct task_struct *p)
 	rcu_read_lock();
 	css = task_subsys_state(p, net_prio_subsys_id);
 	if (css)
-		idx = container_of(css,
-				   struct cgroup_netprio_state, css)->prioidx;
+		idx = css->cgroup->id;
 	rcu_read_unlock();
 	return idx;
 }
net/core/netprio_cgroup.c +11 -54

135 lines not on this page · raw message

Signature · 1 line
1.7.11.7
author maintainer
#21 lore raw

PATCH 6/8 netprio_cgroup: implement netprio[_set]_prio() helpers

In reply to Tejun Heo

Introduce two helpers - netprio_prio() and netprio_set_prio() - which hide the details of priomap access and expansion. This will help implementing hierarchy support.

---
 net/core/netprio_cgroup.c | 72 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 50 insertions(+), 22 deletions(-)
net/core/netprio_cgroup.c +50 -22
index 9409cdf..b2af0d0 100644
@@ -87,6 +87,51 @@ static int extend_netdev_table(struct net_device *dev, u32 target_idx)
 	return 0;
 }
 
+/**
+ * netprio_prio - return the effective netprio of a cgroup-net_device pair
+ * @cgrp: cgroup part of the target pair
+ * @dev: net_device part of the target pair
+ *
+ * Should be called under RCU read or rtnl lock.
+ */
+static u32 netprio_prio(struct cgroup *cgrp, struct net_device *dev)
+{
+	struct netprio_map *map = rcu_dereference_rtnl(dev->priomap);
+
+	if (map && cgrp->id < map->priomap_len)
+		return map->priomap[cgrp->id];
+	return 0;
+}
+
+/**
+ * netprio_set_prio - set netprio on a cgroup-net_device pair
+ * @cgrp: cgroup part of the target pair
+ * @dev: net_device part of the target pair
+ * @prio: prio to set
+ *
+ * Set netprio to @prio on @cgrp-@dev pair.  Should be called under rtnl
+ * lock and may fail under memory pressure for non-zero @prio.
+ */
+static int netprio_set_prio(struct cgroup *cgrp, struct net_device *dev,
+			    u32 prio)
+{
+	struct netprio_map *map;
+	int ret;
+
+	/* avoid extending priomap for zero writes */
+	map = rtnl_dereference(dev->priomap);
+	if (!prio && (!map || map->priomap_len <= cgrp->id))
+		return 0;
+
+	ret = extend_netdev_table(dev, cgrp->id);
+	if (ret)
+		return ret;
+
+	map = rtnl_dereference(dev->priomap);
+	map->priomap[cgrp->id] = prio;
+	return 0;
+}
+
 static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
 {
 	struct cgroup_netprio_state *cs;
@@ -105,14 +150,10 @@ static void cgrp_css_free(struct cgroup *cgrp)
 {
 	struct cgroup_netprio_state *cs = cgrp_netprio_state(cgrp);
 	struct net_device *dev;
-	struct netprio_map *map;
 
 	rtnl_lock();
-	for_each_netdev(&init_net, dev) {
-		map = rtnl_dereference(dev->priomap);
-		if (map && cgrp->id < map->priomap_len)
-			map->priomap[cgrp->id] = 0;
-	}
+	for_each_netdev(&init_net, dev)
+		WARN_ON_ONCE(netprio_set_prio(cgrp, dev, 0));
 	rtnl_unlock();
 	kfree(cs);
 }
@@ -126,16 +167,10 @@ static int read_priomap(struct cgroup *cont, struct cftype *cft,
 			struct cgroup_map_cb *cb)
 {
 	struct net_device *dev;
-	u32 id = cont->id;
-	u32 priority;
-	struct netprio_map *map;
 
 	rcu_read_lock();
-	for_each_netdev_rcu(&init_net, dev) {
-		map = rcu_dereference(dev->priomap);
-		priority = (map && id < map->priomap_len) ? map->priomap[id] : 0;
-		cb->fill(cb, dev->name, priority);
-	}
+	for_each_netdev_rcu(&init_net, dev)
+		cb->fill(cb, dev->name, netprio_prio(cont, dev));
 	rcu_read_unlock();
 	return 0;
 }
@@ -145,7 +180,6 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
 {
 	char devname[IFNAMSIZ + 1];
 	struct net_device *dev;
-	struct netprio_map *map;
 	u32 prio;
 	int ret;
 
@@ -158,14 +192,8 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
 
 	rtnl_lock();
 
-	ret = extend_netdev_table(dev, cgrp->id);
-	if (ret)
-		goto out_unlock;
+	ret = netprio_set_prio(cgrp, dev, prio);
 
-	map = rtnl_dereference(dev->priomap);
-	if (map)
-		map->priomap[cgrp->id] = prio;
-out_unlock:
 	rtnl_unlock();
 	dev_put(dev);
 	return ret;
Signature · 1 line
1.7.11.7
author maintainer
#22 lore raw

PATCH 7/8 netprio_cgroup: keep track of whether prio is set or not

In reply to Tejun Heo

netprio_cgroup keeps prio config per cgroup-netdev pair and doesn't distinguish between unconfigured and explicit 0 priority. To implement hierarchy support, it's necessary to know whether a given pair has explicit configuration or not.

This patch adds netprio_map->aux[] which is indexed by cgroup->id and currently only contains one bool - is_local. netprio[_set]_prio() is updated to handle @is_local. is_local is set iff the pair has explicit config. write_priomap() now clears is_local if a negative value is written and sets on positive. With cgrp_css_free() also updated to clear it, is_local is set for a cgroup-netdev pair iff the pair is online and a positive prio has been configured via "net_prio.ifpriomap".

is_local is visible to userland via cgroup file "net_prio.is_local".

This currently doesn't change any behavior. It will be used to implement hierarchy support.

---
 include/net/netprio_cgroup.h | 10 +++++
 net/core/netprio_cgroup.c    | 94 ++++++++++++++++++++++++++++++++++----------
 2 files changed, 83 insertions(+), 21 deletions(-)
include/net/netprio_cgroup.h +10 -0
index 1d04b6f..bd3daf8 100644
@@ -19,8 +19,18 @@
 
 
 #if IS_ENABLED(CONFIG_NETPRIO_CGROUP)
+
+/*
+ * Auxliary per-cgroup-netdev configuration.  Kept separate from priomap[]
+ * so that priomap[] has better spatial locality.
+ */
+struct netprio_aux {
+	bool		is_local:1;	/* cgroup has priority configured */
+};
+
 struct netprio_map {
 	struct rcu_head rcu;
+	struct netprio_aux *aux;	/* auxiliary config array */
 	u32 priomap_len;
 	u32 priomap[];
 };
net/core/netprio_cgroup.c +73 -21

201 lines not on this page · raw message

Signature · 1 line
1.7.11.7

A message that is not in the archive (sent off-list or not yet received): 1353093624-22608-1-git-send-email-tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org

#24 lore raw

PATCH 7/8 netprio_cgroup: keep track of whether prio is set or not

netprio_cgroup keeps prio config per cgroup-netdev pair and doesn't distinguish between unconfigured and explicit 0 priority. To implement hierarchy support, it's necessary to know whether a given pair has explicit configuration or not.

This patch adds netprio_map->aux[] which is indexed by cgroup->id and currently only contains one bool - is_local. netprio[_set]_prio() is updated to handle @is_local. is_local is set iff the pair has explicit config. write_priomap() now clears is_local if a negative value is written and sets on positive. With cgrp_css_free() also updated to clear it, is_local is set for a cgroup-netdev pair iff the pair is online and a positive prio has been configured via "net_prio.ifpriomap".

is_local is visible to userland via cgroup file "net_prio.is_local".

This currently doesn't change any behavior. It will be used to implement hierarchy support.

---
 include/net/netprio_cgroup.h | 10 +++++
 net/core/netprio_cgroup.c    | 94 ++++++++++++++++++++++++++++++++++----------
 2 files changed, 83 insertions(+), 21 deletions(-)
include/net/netprio_cgroup.h +10 -0
index 1d04b6f..bd3daf8 100644
@@ -19,8 +19,18 @@
 
 
 #if IS_ENABLED(CONFIG_NETPRIO_CGROUP)
+
+/*
+ * Auxliary per-cgroup-netdev configuration.  Kept separate from priomap[]
+ * so that priomap[] has better spatial locality.
+ */
+struct netprio_aux {
+	bool		is_local:1;	/* cgroup has priority configured */
+};
+
 struct netprio_map {
 	struct rcu_head rcu;
+	struct netprio_aux *aux;	/* auxiliary config array */
 	u32 priomap_len;
 	u32 priomap[];
 };
net/core/netprio_cgroup.c +73 -21

201 lines not on this page · raw message

Signature · 1 line
1.7.11.7
#25 lore raw

PATCH 8/8 netprio_cgroup: implement hierarchy support

In reply to a message not in the archive

Implement hierarchy support. Each netprio_cgroup inherits its parent's prio config for any net_device which it doesn't have local config on.

As each netprio_cgroup is fully ready after ->css_alloc() and config inheritance doesn't affect the parent, netprio_cgroup doesn't need to strictly distinguish on and offline cgroups and can get by simply inheriting the parent's configuration from ->css_online() and propagating config updates downwards in write_priomap().

* As ->css_online() inherits prios on all netdevs from the parent, clearing priomap on ->css_free() is no longer necessary. Removed.

* Error out on nesting in ->css_alloc() removed along with ss->broken_hierarchy marking.

Note that this patch changes userland-visible behavior. Nesting is now allowed and priority configuration is inherited through hierarchy. This especially changes how the first level cgroups below the root cgroup behave - any unconfigured pairs now inherit priorities from the root cgroup instead of assuming 0.

---
 Documentation/cgroups/net_prio.txt |  21 +++++-
 net/core/netprio_cgroup.c          | 130 ++++++++++++++++++++++++++++++-------
 2 files changed, 125 insertions(+), 26 deletions(-)
Documentation/cgroups/net_prio.txt +18 -3
index 01b3226..4dcca61 100644
@@ -22,13 +22,15 @@ With the above step, the initial group acting as the parent accounting group
 becomes visible at '/sys/fs/cgroup/net_prio'.  This group includes all tasks in
 the system. '/sys/fs/cgroup/net_prio/tasks' lists the tasks in this cgroup.
 
-Each net_prio cgroup contains two files that are subsystem specific
+Each net_prio cgroup contains three files that are subsystem specific
+
+* net_prio.prioidx
 
-net_prio.prioidx
 This file is read-only, and is simply informative.  It contains a unique integer
 value that the kernel uses as an internal representation of this cgroup.
 
-net_prio.ifpriomap
+* net_prio.ifpriomap
+
 This file contains a map of the priorities assigned to traffic originating from
 processes in this group and egressing the system on various interfaces. It
 contains a list of tuples in the form <ifname priority>.  Contents of this file
@@ -51,3 +53,16 @@ One usage for the net_prio cgroup is with mqprio qdisc allowing application
 traffic to be steered to hardware/driver based traffic classes. These mappings
 can then be managed by administrators or other networking protocols such as
 DCBX.
+
+If priority is not set for an interface, the parent's priority is inherited.
+For the root cgroup, there's no parent and all unset priorities are zero.
+Priority can be unset by echoing negative value to ifpriomap.  For example,
+the following would undo the configuration done above and make iscsi cgroup
+to inherit prio for eth0 from the root cgroup.
+
+echo "eth0 -1" > /sys/fs/cgroups/net_prio/iscsi/net_prio.ifpriomap
+
+* net_prio.is_local
+
+This file is read-only and shows whether the net_prio cgroup has its own
+priority configured or inherited priority from its parent for each interface.
net/core/netprio_cgroup.c +107 -23

182 lines not on this page · raw message

Signature · 1 line
1.7.11.7
author maintainer
#27 lore raw

PATCH 8/8 netprio_cgroup: implement hierarchy support

In reply to Tejun Heo

Implement hierarchy support. Each netprio_cgroup inherits its parent's prio config for any net_device which it doesn't have local config on.

As each netprio_cgroup is fully ready after ->css_alloc() and config inheritance doesn't affect the parent, netprio_cgroup doesn't need to strictly distinguish on and offline cgroups and can get by simply inheriting the parent's configuration from ->css_online() and propagating config updates downwards in write_priomap().

* As ->css_online() inherits prios on all netdevs from the parent, clearing priomap on ->css_free() is no longer necessary. Removed.

* Error out on nesting in ->css_alloc() removed along with ss->broken_hierarchy marking.

Note that this patch changes userland-visible behavior. Nesting is now allowed and priority configuration is inherited through hierarchy. This especially changes how the first level cgroups below the root cgroup behave - any unconfigured pairs now inherit priorities from the root cgroup instead of assuming 0.

---
 Documentation/cgroups/net_prio.txt |  21 +++++-
 net/core/netprio_cgroup.c          | 130 ++++++++++++++++++++++++++++++-------
 2 files changed, 125 insertions(+), 26 deletions(-)
Documentation/cgroups/net_prio.txt +18 -3
index 01b3226..4dcca61 100644
@@ -22,13 +22,15 @@ With the above step, the initial group acting as the parent accounting group
 becomes visible at '/sys/fs/cgroup/net_prio'.  This group includes all tasks in
 the system. '/sys/fs/cgroup/net_prio/tasks' lists the tasks in this cgroup.
 
-Each net_prio cgroup contains two files that are subsystem specific
+Each net_prio cgroup contains three files that are subsystem specific
+
+* net_prio.prioidx
 
-net_prio.prioidx
 This file is read-only, and is simply informative.  It contains a unique integer
 value that the kernel uses as an internal representation of this cgroup.
 
-net_prio.ifpriomap
+* net_prio.ifpriomap
+
 This file contains a map of the priorities assigned to traffic originating from
 processes in this group and egressing the system on various interfaces. It
 contains a list of tuples in the form <ifname priority>.  Contents of this file
@@ -51,3 +53,16 @@ One usage for the net_prio cgroup is with mqprio qdisc allowing application
 traffic to be steered to hardware/driver based traffic classes. These mappings
 can then be managed by administrators or other networking protocols such as
 DCBX.
+
+If priority is not set for an interface, the parent's priority is inherited.
+For the root cgroup, there's no parent and all unset priorities are zero.
+Priority can be unset by echoing negative value to ifpriomap.  For example,
+the following would undo the configuration done above and make iscsi cgroup
+to inherit prio for eth0 from the root cgroup.
+
+echo "eth0 -1" > /sys/fs/cgroups/net_prio/iscsi/net_prio.ifpriomap
+
+* net_prio.is_local
+
+This file is read-only and shows whether the net_prio cgroup has its own
+priority configured or inherited priority from its parent for each interface.
net/core/netprio_cgroup.c +107 -23

182 lines not on this page · raw message

Signature · 1 line
1.7.11.7
Acked-by on v1 1/1
#28 lore raw
In reply to Tejun Heo
Quoted 65 lines · Tejun Heo

Hello, guys.

This patchset implements hierarchy support for netprio_cgroup. netprio_cgroup along with netcls_cgroup is a rather weird in that it really isn't about resource control. It just hitches on cgroup as a convenient mechanism to do stuff to groups of tasks. The hierarchy support reflects such nature. There's no limit being imposed from ancestors. It simply propagates configuration downwards until there's a node with its own config. IOW, any given cgroup inherits priorities from its parent for all netdevs which it doesn't have its own config for.

As a parent isn't affected by child inheriting its config, the hierarchy implementation is pretty simple. It's enough to inherit config from ->css_online() and propagate new config downwards from write_priomap(). As each node needs to know which config is its local one and which is inherited, an extra config array is added - netprio_map->aux[]. It's a separate array to avoid disturbing spatial locality of ->priomap[]. While it currently contains single one-bit flag, I still made it a struct so that adding more configuration (e.g. max_prio) is easy.

Note that this does change userland-visible behavior. Now, nesting is allowed and cgroups at the first level inherit priorities from the root cgroup. I can't think of any better way than just biting the bullet here. :(

0001-cgroup-add-cgroup-id.patch 0002-netprio-simplify-write_priomap.patch 0003-netprio_cgroup-shorten-variable-names-in-extend_netd.patch 0004-netprio_cgroup-reimplement-priomap-expansion.patch 0005-netprio_cgroup-use-cgroup-id-instead-of-cgroup_netpr.patch 0006-netprio_cgroup-implement-netprio-_set-_prio-helpers.patch 0007-netprio_cgroup-keep-track-of-whether-prio-is-set-or-.patch 0008-netprio_cgroup-implement-hierarchy-support.patch

0001 adds cgroup->id. This will eventually replace css_id.

0002-0006 are prep patches.

0007 implements is_local flag which tracks whether a cgroup has its own config or should inherit from its parent.

0008 implements hierarchy support.

This patchset is on top of

cgroup/for-3.8 ef9fe980c6 ("cgroup_freezer: implement proper hierarchy support")
+ [1] "[PATCHSET cgroup/for-3.8] cgroup: allow ->post_create() to fail"
+ [2] "[PATCH 1/2] cgroup: s/CGRP_CLONE_CHILDREN/CGRP_CPUSET_CLONE_CHILDREN/"

      "[PATCH 2/2] cgroup, cpuset: remove cgroup_subsys->post_clone()"

and available in the following git branch.

git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git review-netprio_cgroup-hierarchy

diffstat follows.

 Documentation/cgroups/net_prio.txt |   21 +-
 include/linux/cgroup.h             |    2
 include/net/netprio_cgroup.h       |   21 +-
 kernel/cgroup.c                    |   15 +
 net/core/netprio_cgroup.c          |  376 +++++++++++++++++++++++--------------
 5 files changed, 284 insertions(+), 151 deletions(-)
Quoted 8 lines

Thanks.

--
tejun

[1] http://thread.gmane.org/gmane.linux.kernel.cgroups/5047
[2] http://thread.gmane.org/gmane.linux.kernel/1393151

Thanks Tejun

For the series:

#30 lore raw
Quoted 4 lines · Daniel Wagner

Hi Tejun,

I have tested this series and it works nicely. I didn't mentioned yet to review it completely. I will do it tomorrow.

s/mentioned/managed/

A message that is not in the archive (sent off-list or not yet received): [email protected]

#32 lore raw
Quoted 4 lines · Daniel Wagner

Hi Tejun,

I have tested this series and it works nicely. I didn't mentioned yet to review it completely. I will do it tomorrow.

s/mentioned/managed/