diff options
author | John Fastabend <john.r.fastabend@intel.com> | 2012-08-14 08:34:35 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-08-16 17:56:11 -0400 |
commit | 476ad154f3b41dd7d9a08a2f641e28388abc2fd1 (patch) | |
tree | df3621b3720766e4bf3a330d1114e8a1c5beace1 | |
parent | 48a87cc26c13b68f6cce4e9d769fcb17a6b3e4b8 (diff) |
net: netprio: fix cgrp create and write priomap race
A race exists where creating cgroups and also updating the priomap
may result in losing a priomap update. This is because priomap
writers are not protected by rtnl_lock.
Move priority writer into rtnl_lock()/rtnl_unlock().
CC: Neil Horman <nhorman@tuxdriver.com>
Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/core/netprio_cgroup.c | 8 |
1 files changed, 3 insertions, 5 deletions
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index f65dba3afd99..c75e3f9d060f 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c | |||
@@ -101,12 +101,10 @@ static int write_update_netdev_table(struct net_device *dev) | |||
101 | u32 max_len; | 101 | u32 max_len; |
102 | struct netprio_map *map; | 102 | struct netprio_map *map; |
103 | 103 | ||
104 | rtnl_lock(); | ||
105 | max_len = atomic_read(&max_prioidx) + 1; | 104 | max_len = atomic_read(&max_prioidx) + 1; |
106 | map = rtnl_dereference(dev->priomap); | 105 | map = rtnl_dereference(dev->priomap); |
107 | if (!map || map->priomap_len < max_len) | 106 | if (!map || map->priomap_len < max_len) |
108 | ret = extend_netdev_table(dev, max_len); | 107 | ret = extend_netdev_table(dev, max_len); |
109 | rtnl_unlock(); | ||
110 | 108 | ||
111 | return ret; | 109 | return ret; |
112 | } | 110 | } |
@@ -256,17 +254,17 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft, | |||
256 | if (!dev) | 254 | if (!dev) |
257 | goto out_free_devname; | 255 | goto out_free_devname; |
258 | 256 | ||
257 | rtnl_lock(); | ||
259 | ret = write_update_netdev_table(dev); | 258 | ret = write_update_netdev_table(dev); |
260 | if (ret < 0) | 259 | if (ret < 0) |
261 | goto out_put_dev; | 260 | goto out_put_dev; |
262 | 261 | ||
263 | rcu_read_lock(); | 262 | map = rtnl_dereference(dev->priomap); |
264 | map = rcu_dereference(dev->priomap); | ||
265 | if (map) | 263 | if (map) |
266 | map->priomap[prioidx] = priority; | 264 | map->priomap[prioidx] = priority; |
267 | rcu_read_unlock(); | ||
268 | 265 | ||
269 | out_put_dev: | 266 | out_put_dev: |
267 | rtnl_unlock(); | ||
270 | dev_put(dev); | 268 | dev_put(dev); |
271 | 269 | ||
272 | out_free_devname: | 270 | out_free_devname: |