diff options
| -rw-r--r-- | net/core/netprio_cgroup.c | 71 |
1 files changed, 54 insertions, 17 deletions
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index 3e953eaddbfc..b2e9caa1ad1a 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c | |||
| @@ -65,7 +65,7 @@ static void put_prioidx(u32 idx) | |||
| 65 | spin_unlock_irqrestore(&prioidx_map_lock, flags); | 65 | spin_unlock_irqrestore(&prioidx_map_lock, flags); |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | static void extend_netdev_table(struct net_device *dev, u32 new_len) | 68 | static int extend_netdev_table(struct net_device *dev, u32 new_len) |
| 69 | { | 69 | { |
| 70 | size_t new_size = sizeof(struct netprio_map) + | 70 | size_t new_size = sizeof(struct netprio_map) + |
| 71 | ((sizeof(u32) * new_len)); | 71 | ((sizeof(u32) * new_len)); |
| @@ -77,7 +77,7 @@ static void extend_netdev_table(struct net_device *dev, u32 new_len) | |||
| 77 | 77 | ||
| 78 | if (!new_priomap) { | 78 | if (!new_priomap) { |
| 79 | pr_warn("Unable to alloc new priomap!\n"); | 79 | pr_warn("Unable to alloc new priomap!\n"); |
| 80 | return; | 80 | return -ENOMEM; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | for (i = 0; | 83 | for (i = 0; |
| @@ -90,46 +90,79 @@ static void extend_netdev_table(struct net_device *dev, u32 new_len) | |||
| 90 | rcu_assign_pointer(dev->priomap, new_priomap); | 90 | rcu_assign_pointer(dev->priomap, new_priomap); |
| 91 | if (old_priomap) | 91 | if (old_priomap) |
| 92 | kfree_rcu(old_priomap, rcu); | 92 | kfree_rcu(old_priomap, rcu); |
| 93 | return 0; | ||
| 93 | } | 94 | } |
| 94 | 95 | ||
| 95 | static void update_netdev_tables(void) | 96 | static int write_update_netdev_table(struct net_device *dev) |
| 96 | { | 97 | { |
| 98 | int ret = 0; | ||
| 99 | u32 max_len; | ||
| 100 | struct netprio_map *map; | ||
| 101 | |||
| 102 | rtnl_lock(); | ||
| 103 | max_len = atomic_read(&max_prioidx) + 1; | ||
| 104 | map = rtnl_dereference(dev->priomap); | ||
| 105 | if (!map || map->priomap_len < max_len) | ||
| 106 | ret = extend_netdev_table(dev, max_len); | ||
| 107 | rtnl_unlock(); | ||
| 108 | |||
| 109 | return ret; | ||
| 110 | } | ||
| 111 | |||
| 112 | static int update_netdev_tables(void) | ||
| 113 | { | ||
| 114 | int ret = 0; | ||
| 97 | struct net_device *dev; | 115 | struct net_device *dev; |
| 98 | u32 max_len = atomic_read(&max_prioidx) + 1; | 116 | u32 max_len; |
| 99 | struct netprio_map *map; | 117 | struct netprio_map *map; |
| 100 | 118 | ||
| 101 | rtnl_lock(); | 119 | rtnl_lock(); |
| 120 | max_len = atomic_read(&max_prioidx) + 1; | ||
| 102 | for_each_netdev(&init_net, dev) { | 121 | for_each_netdev(&init_net, dev) { |
| 103 | map = rtnl_dereference(dev->priomap); | 122 | map = rtnl_dereference(dev->priomap); |
| 104 | if ((!map) || | 123 | /* |
| 105 | (map->priomap_len < max_len)) | 124 | * don't allocate priomap if we didn't |
| 106 | extend_netdev_table(dev, max_len); | 125 | * change net_prio.ifpriomap (map == NULL), |
| 126 | * this will speed up skb_update_prio. | ||
| 127 | */ | ||
| 128 | if (map && map->priomap_len < max_len) { | ||
| 129 | ret = extend_netdev_table(dev, max_len); | ||
| 130 | if (ret < 0) | ||
| 131 | break; | ||
| 132 | } | ||
| 107 | } | 133 | } |
| 108 | rtnl_unlock(); | 134 | rtnl_unlock(); |
| 135 | return ret; | ||
| 109 | } | 136 | } |
| 110 | 137 | ||
| 111 | static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp) | 138 | static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp) |
| 112 | { | 139 | { |
| 113 | struct cgroup_netprio_state *cs; | 140 | struct cgroup_netprio_state *cs; |
| 114 | int ret; | 141 | int ret = -EINVAL; |
| 115 | 142 | ||
| 116 | cs = kzalloc(sizeof(*cs), GFP_KERNEL); | 143 | cs = kzalloc(sizeof(*cs), GFP_KERNEL); |
| 117 | if (!cs) | 144 | if (!cs) |
| 118 | return ERR_PTR(-ENOMEM); | 145 | return ERR_PTR(-ENOMEM); |
| 119 | 146 | ||
| 120 | if (cgrp->parent && cgrp_netprio_state(cgrp->parent)->prioidx) { | 147 | if (cgrp->parent && cgrp_netprio_state(cgrp->parent)->prioidx) |
| 121 | kfree(cs); | 148 | goto out; |
| 122 | return ERR_PTR(-EINVAL); | ||
| 123 | } | ||
| 124 | 149 | ||
| 125 | ret = get_prioidx(&cs->prioidx); | 150 | ret = get_prioidx(&cs->prioidx); |
| 126 | if (ret != 0) { | 151 | if (ret < 0) { |
| 127 | pr_warn("No space in priority index array\n"); | 152 | pr_warn("No space in priority index array\n"); |
| 128 | kfree(cs); | 153 | goto out; |
| 129 | return ERR_PTR(ret); | 154 | } |
| 155 | |||
| 156 | ret = update_netdev_tables(); | ||
| 157 | if (ret < 0) { | ||
| 158 | put_prioidx(cs->prioidx); | ||
| 159 | goto out; | ||
| 130 | } | 160 | } |
| 131 | 161 | ||
| 132 | return &cs->css; | 162 | return &cs->css; |
| 163 | out: | ||
| 164 | kfree(cs); | ||
| 165 | return ERR_PTR(ret); | ||
| 133 | } | 166 | } |
| 134 | 167 | ||
| 135 | static void cgrp_destroy(struct cgroup *cgrp) | 168 | static void cgrp_destroy(struct cgroup *cgrp) |
| @@ -221,13 +254,17 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft, | |||
| 221 | if (!dev) | 254 | if (!dev) |
| 222 | goto out_free_devname; | 255 | goto out_free_devname; |
| 223 | 256 | ||
| 224 | update_netdev_tables(); | 257 | ret = write_update_netdev_table(dev); |
| 225 | ret = 0; | 258 | if (ret < 0) |
| 259 | goto out_put_dev; | ||
| 260 | |||
| 226 | rcu_read_lock(); | 261 | rcu_read_lock(); |
| 227 | map = rcu_dereference(dev->priomap); | 262 | map = rcu_dereference(dev->priomap); |
| 228 | if (map) | 263 | if (map) |
| 229 | map->priomap[prioidx] = priority; | 264 | map->priomap[prioidx] = priority; |
| 230 | rcu_read_unlock(); | 265 | rcu_read_unlock(); |
| 266 | |||
| 267 | out_put_dev: | ||
| 231 | dev_put(dev); | 268 | dev_put(dev); |
| 232 | 269 | ||
| 233 | out_free_devname: | 270 | out_free_devname: |
