Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753428Ab2KPTUr (ORCPT ); Fri, 16 Nov 2012 14:20:47 -0500 Received: from mail-da0-f46.google.com ([209.85.210.46]:49538 "EHLO mail-da0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753389Ab2KPTUp (ORCPT ); Fri, 16 Nov 2012 14:20:45 -0500 From: Tejun Heo To: daniel.wagner@bmw-carit.de, srivatsa.bhat@linux.vnet.ibm.com, john.r.fastabend@intel.com, nhorman@tuxdriver.com Cc: lizefan@huawei.com, containers@lists.linux-foundation.org, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, Tejun Heo Subject: [PATCH 7/8] netprio_cgroup: keep track of whether prio is set or not Date: Fri, 16 Nov 2012 11:20:23 -0800 Message-Id: <1353093624-22608-8-git-send-email-tj@kernel.org> X-Mailer: git-send-email 1.7.11.7 In-Reply-To: <1353093624-22608-1-git-send-email-tj@kernel.org> References: <1353093624-22608-1-git-send-email-tj@kernel.org> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7848 Lines: 271 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. Signed-off-by: Tejun Heo --- include/net/netprio_cgroup.h | 10 +++++ net/core/netprio_cgroup.c | 94 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 83 insertions(+), 21 deletions(-) diff --git a/include/net/netprio_cgroup.h b/include/net/netprio_cgroup.h index 1d04b6f..bd3daf8 100644 --- a/include/net/netprio_cgroup.h +++ b/include/net/netprio_cgroup.h @@ -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[]; }; diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index b2af0d0..e7a5b03 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c @@ -35,6 +35,14 @@ static inline struct cgroup_netprio_state *cgrp_netprio_state(struct cgroup *cgr struct cgroup_netprio_state, css); } +static void free_netprio_map(struct netprio_map *map) +{ + if (map) { + kfree(map->aux); + kfree_rcu(map, rcu); + } +} + /* * Extend @dev->priomap so that it's large enough to accomodate * @target_idx. @dev->priomap.priomap_len > @target_idx after successful @@ -69,38 +77,55 @@ static int extend_netdev_table(struct net_device *dev, u32 target_idx) /* allocate & copy */ new = kzalloc(new_sz, GFP_KERNEL); - if (!new) { - pr_warn("Unable to alloc new priomap!\n"); - return -ENOMEM; - } + if (!new) + goto enomem; + + new->aux = kzalloc(new_len * sizeof(new->aux[0]), GFP_KERNEL); + if (!new->aux) + goto enomem; - if (old) + if (old) { memcpy(new->priomap, old->priomap, old->priomap_len * sizeof(old->priomap[0])); + memcpy(new->aux, old->aux, + old->priomap_len * sizeof(old->aux[0])); + } new->priomap_len = new_len; /* install the new priomap */ rcu_assign_pointer(dev->priomap, new); - if (old) - kfree_rcu(old, rcu); + free_netprio_map(old); return 0; + +enomem: + free_netprio_map(new); + pr_warn("Unable to alloc new priomap!\n"); + return -ENOMEM; } /** * 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 + * @is_local_p: optional out param, %true if @cgrp-@dev has local config * * Should be called under RCU read or rtnl lock. */ -static u32 netprio_prio(struct cgroup *cgrp, struct net_device *dev) +static u32 netprio_prio(struct cgroup *cgrp, struct net_device *dev, + bool *is_local_p) { struct netprio_map *map = rcu_dereference_rtnl(dev->priomap); + bool is_local = false; + u32 prio = 0; - if (map && cgrp->id < map->priomap_len) - return map->priomap[cgrp->id]; - return 0; + if (map && cgrp->id < map->priomap_len) { + is_local = map->aux[cgrp->id].is_local; + prio = map->priomap[cgrp->id]; + } + if (is_local_p) + *is_local_p = is_local; + return prio; } /** @@ -108,19 +133,20 @@ static u32 netprio_prio(struct cgroup *cgrp, struct net_device *dev) * @cgrp: cgroup part of the target pair * @dev: net_device part of the target pair * @prio: prio to set + * @is_local: indicates whether @prio is @cgrp's local prio configuration * * Set netprio to @prio on @cgrp-@dev pair. Should be called under rtnl - * lock and may fail under memory pressure for non-zero @prio. + * lock and may fail under memory pressure if (@prio || @is_local). */ static int netprio_set_prio(struct cgroup *cgrp, struct net_device *dev, - u32 prio) + u32 prio, bool is_local) { struct netprio_map *map; int ret; - /* avoid extending priomap for zero writes */ + /* avoid extending priomap for clearing zero writes */ map = rtnl_dereference(dev->priomap); - if (!prio && (!map || map->priomap_len <= cgrp->id)) + if (!is_local && !prio && (!map || map->priomap_len <= cgrp->id)) return 0; ret = extend_netdev_table(dev, cgrp->id); @@ -128,6 +154,7 @@ static int netprio_set_prio(struct cgroup *cgrp, struct net_device *dev, return ret; map = rtnl_dereference(dev->priomap); + map->aux[cgrp->id].is_local = is_local; map->priomap[cgrp->id] = prio; return 0; } @@ -153,7 +180,7 @@ static void cgrp_css_free(struct cgroup *cgrp) rtnl_lock(); for_each_netdev(&init_net, dev) - WARN_ON_ONCE(netprio_set_prio(cgrp, dev, 0)); + WARN_ON_ONCE(netprio_set_prio(cgrp, dev, 0, false)); rtnl_unlock(); kfree(cs); } @@ -170,7 +197,7 @@ static int read_priomap(struct cgroup *cont, struct cftype *cft, rcu_read_lock(); for_each_netdev_rcu(&init_net, dev) - cb->fill(cb, dev->name, netprio_prio(cont, dev)); + cb->fill(cb, dev->name, netprio_prio(cont, dev, NULL)); rcu_read_unlock(); return 0; } @@ -180,25 +207,46 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft, { char devname[IFNAMSIZ + 1]; struct net_device *dev; + s64 v; u32 prio; + bool is_local; int ret; - if (sscanf(buffer, "%"__stringify(IFNAMSIZ)"s %u", devname, &prio) != 2) + if (sscanf(buffer, "%"__stringify(IFNAMSIZ)"s %lld", devname, &v) != 2) return -EINVAL; + prio = clamp_val(v, 0, UINT_MAX); + is_local = v >= 0; + dev = dev_get_by_name(&init_net, devname); if (!dev) return -ENODEV; rtnl_lock(); - ret = netprio_set_prio(cgrp, dev, prio); + ret = netprio_set_prio(cgrp, dev, prio, is_local); rtnl_unlock(); dev_put(dev); return ret; } +static int netprio_read_is_local(struct cgroup *cont, struct cftype *cft, + struct seq_file *m) +{ + struct net_device *dev; + + rtnl_lock(); + for_each_netdev(&init_net, dev) { + bool is_local; + + netprio_prio(cont, dev, &is_local); + seq_printf(m, "%s %d\n", dev->name, is_local); + } + rtnl_unlock(); + return 0; +} + static int update_netprio(const void *v, struct file *file, unsigned n) { int err; @@ -231,6 +279,10 @@ static struct cftype ss_files[] = { .read_map = read_priomap, .write_string = write_priomap, }, + { + .name = "is_local", + .read_seq_string = netprio_read_is_local, + }, { } /* terminate */ }; @@ -270,7 +322,7 @@ static int netprio_device_event(struct notifier_block *unused, old = rtnl_dereference(dev->priomap); RCU_INIT_POINTER(dev->priomap, NULL); if (old) - kfree_rcu(old, rcu); + free_netprio_map(old); break; } return NOTIFY_DONE; @@ -308,7 +360,7 @@ static void __exit exit_cgroup_netprio(void) old = rtnl_dereference(dev->priomap); RCU_INIT_POINTER(dev->priomap, NULL); if (old) - kfree_rcu(old, rcu); + free_netprio_map(old); } rtnl_unlock(); } -- 1.7.11.7 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/