diff options
-rw-r--r-- | net/core/netprio_cgroup.c | 72 |
1 files changed, 50 insertions, 22 deletions
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index 9409cdf9f268..b2af0d099663 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c | |||
@@ -87,6 +87,51 @@ static int extend_netdev_table(struct net_device *dev, u32 target_idx) | |||
87 | return 0; | 87 | return 0; |
88 | } | 88 | } |
89 | 89 | ||
90 | /** | ||
91 | * netprio_prio - return the effective netprio of a cgroup-net_device pair | ||
92 | * @cgrp: cgroup part of the target pair | ||
93 | * @dev: net_device part of the target pair | ||
94 | * | ||
95 | * Should be called under RCU read or rtnl lock. | ||
96 | */ | ||
97 | static u32 netprio_prio(struct cgroup *cgrp, struct net_device *dev) | ||
98 | { | ||
99 | struct netprio_map *map = rcu_dereference_rtnl(dev->priomap); | ||
100 | |||
101 | if (map && cgrp->id < map->priomap_len) | ||
102 | return map->priomap[cgrp->id]; | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * netprio_set_prio - set netprio on a cgroup-net_device pair | ||
108 | * @cgrp: cgroup part of the target pair | ||
109 | * @dev: net_device part of the target pair | ||
110 | * @prio: prio to set | ||
111 | * | ||
112 | * Set netprio to @prio on @cgrp-@dev pair. Should be called under rtnl | ||
113 | * lock and may fail under memory pressure for non-zero @prio. | ||
114 | */ | ||
115 | static int netprio_set_prio(struct cgroup *cgrp, struct net_device *dev, | ||
116 | u32 prio) | ||
117 | { | ||
118 | struct netprio_map *map; | ||
119 | int ret; | ||
120 | |||
121 | /* avoid extending priomap for zero writes */ | ||
122 | map = rtnl_dereference(dev->priomap); | ||
123 | if (!prio && (!map || map->priomap_len <= cgrp->id)) | ||
124 | return 0; | ||
125 | |||
126 | ret = extend_netdev_table(dev, cgrp->id); | ||
127 | if (ret) | ||
128 | return ret; | ||
129 | |||
130 | map = rtnl_dereference(dev->priomap); | ||
131 | map->priomap[cgrp->id] = prio; | ||
132 | return 0; | ||
133 | } | ||
134 | |||
90 | static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp) | 135 | static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp) |
91 | { | 136 | { |
92 | struct cgroup_netprio_state *cs; | 137 | struct cgroup_netprio_state *cs; |
@@ -105,14 +150,10 @@ static void cgrp_css_free(struct cgroup *cgrp) | |||
105 | { | 150 | { |
106 | struct cgroup_netprio_state *cs = cgrp_netprio_state(cgrp); | 151 | struct cgroup_netprio_state *cs = cgrp_netprio_state(cgrp); |
107 | struct net_device *dev; | 152 | struct net_device *dev; |
108 | struct netprio_map *map; | ||
109 | 153 | ||
110 | rtnl_lock(); | 154 | rtnl_lock(); |
111 | for_each_netdev(&init_net, dev) { | 155 | for_each_netdev(&init_net, dev) |
112 | map = rtnl_dereference(dev->priomap); | 156 | WARN_ON_ONCE(netprio_set_prio(cgrp, dev, 0)); |
113 | if (map && cgrp->id < map->priomap_len) | ||
114 | map->priomap[cgrp->id] = 0; | ||
115 | } | ||
116 | rtnl_unlock(); | 157 | rtnl_unlock(); |
117 | kfree(cs); | 158 | kfree(cs); |
118 | } | 159 | } |
@@ -126,16 +167,10 @@ static int read_priomap(struct cgroup *cont, struct cftype *cft, | |||
126 | struct cgroup_map_cb *cb) | 167 | struct cgroup_map_cb *cb) |
127 | { | 168 | { |
128 | struct net_device *dev; | 169 | struct net_device *dev; |
129 | u32 id = cont->id; | ||
130 | u32 priority; | ||
131 | struct netprio_map *map; | ||
132 | 170 | ||
133 | rcu_read_lock(); | 171 | rcu_read_lock(); |
134 | for_each_netdev_rcu(&init_net, dev) { | 172 | for_each_netdev_rcu(&init_net, dev) |
135 | map = rcu_dereference(dev->priomap); | 173 | cb->fill(cb, dev->name, netprio_prio(cont, dev)); |
136 | priority = (map && id < map->priomap_len) ? map->priomap[id] : 0; | ||
137 | cb->fill(cb, dev->name, priority); | ||
138 | } | ||
139 | rcu_read_unlock(); | 174 | rcu_read_unlock(); |
140 | return 0; | 175 | return 0; |
141 | } | 176 | } |
@@ -145,7 +180,6 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft, | |||
145 | { | 180 | { |
146 | char devname[IFNAMSIZ + 1]; | 181 | char devname[IFNAMSIZ + 1]; |
147 | struct net_device *dev; | 182 | struct net_device *dev; |
148 | struct netprio_map *map; | ||
149 | u32 prio; | 183 | u32 prio; |
150 | int ret; | 184 | int ret; |
151 | 185 | ||
@@ -158,14 +192,8 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft, | |||
158 | 192 | ||
159 | rtnl_lock(); | 193 | rtnl_lock(); |
160 | 194 | ||
161 | ret = extend_netdev_table(dev, cgrp->id); | 195 | ret = netprio_set_prio(cgrp, dev, prio); |
162 | if (ret) | ||
163 | goto out_unlock; | ||
164 | 196 | ||
165 | map = rtnl_dereference(dev->priomap); | ||
166 | if (map) | ||
167 | map->priomap[cgrp->id] = prio; | ||
168 | out_unlock: | ||
169 | rtnl_unlock(); | 197 | rtnl_unlock(); |
170 | dev_put(dev); | 198 | dev_put(dev); |
171 | return ret; | 199 | return ret; |