diff options
author | Kirill Tkhai <ktkhai@virtuozzo.com> | 2018-01-12 10:28:31 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-15 14:23:42 -0500 |
commit | 273c28bc57ca9672f7b70bed764ecdfb964930c8 (patch) | |
tree | 99fda63f67f8e081924a6d39af93dfbbb04e6eff | |
parent | 594831a8aba3fd045c3212a3e3bb9788c77b989d (diff) |
net: Convert atomic_t net::count to refcount_t
Since net could be obtained from RCU lists,
and there is a race with net destruction,
the patch converts net::count to refcount_t.
This provides sanity checks for the cases of
incrementing counter of already dead net,
when maybe_get_net() has to used instead
of get_net().
Drivers: allyesconfig and allmodconfig are OK.
Suggested-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/net_namespace.h | 8 | ||||
-rw-r--r-- | net/core/net-sysfs.c | 6 | ||||
-rw-r--r-- | net/core/net_namespace.c | 8 | ||||
-rw-r--r-- | net/ipv4/inet_timewait_sock.c | 4 | ||||
-rw-r--r-- | net/ipv4/tcp_metrics.c | 2 |
5 files changed, 14 insertions, 14 deletions
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 10f99dafd5ac..f8a84a2c2341 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h | |||
@@ -51,7 +51,7 @@ struct net { | |||
51 | refcount_t passive; /* To decided when the network | 51 | refcount_t passive; /* To decided when the network |
52 | * namespace should be freed. | 52 | * namespace should be freed. |
53 | */ | 53 | */ |
54 | atomic_t count; /* To decided when the network | 54 | refcount_t count; /* To decided when the network |
55 | * namespace should be shut down. | 55 | * namespace should be shut down. |
56 | */ | 56 | */ |
57 | spinlock_t rules_mod_lock; | 57 | spinlock_t rules_mod_lock; |
@@ -195,7 +195,7 @@ void __put_net(struct net *net); | |||
195 | 195 | ||
196 | static inline struct net *get_net(struct net *net) | 196 | static inline struct net *get_net(struct net *net) |
197 | { | 197 | { |
198 | atomic_inc(&net->count); | 198 | refcount_inc(&net->count); |
199 | return net; | 199 | return net; |
200 | } | 200 | } |
201 | 201 | ||
@@ -206,14 +206,14 @@ static inline struct net *maybe_get_net(struct net *net) | |||
206 | * exists. If the reference count is zero this | 206 | * exists. If the reference count is zero this |
207 | * function fails and returns NULL. | 207 | * function fails and returns NULL. |
208 | */ | 208 | */ |
209 | if (!atomic_inc_not_zero(&net->count)) | 209 | if (!refcount_inc_not_zero(&net->count)) |
210 | net = NULL; | 210 | net = NULL; |
211 | return net; | 211 | return net; |
212 | } | 212 | } |
213 | 213 | ||
214 | static inline void put_net(struct net *net) | 214 | static inline void put_net(struct net *net) |
215 | { | 215 | { |
216 | if (atomic_dec_and_test(&net->count)) | 216 | if (refcount_dec_and_test(&net->count)) |
217 | __put_net(net); | 217 | __put_net(net); |
218 | } | 218 | } |
219 | 219 | ||
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 799b75268291..7bf8b85ade16 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c | |||
@@ -961,7 +961,7 @@ net_rx_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) | |||
961 | while (--i >= new_num) { | 961 | while (--i >= new_num) { |
962 | struct kobject *kobj = &dev->_rx[i].kobj; | 962 | struct kobject *kobj = &dev->_rx[i].kobj; |
963 | 963 | ||
964 | if (!atomic_read(&dev_net(dev)->count)) | 964 | if (!refcount_read(&dev_net(dev)->count)) |
965 | kobj->uevent_suppress = 1; | 965 | kobj->uevent_suppress = 1; |
966 | if (dev->sysfs_rx_queue_group) | 966 | if (dev->sysfs_rx_queue_group) |
967 | sysfs_remove_group(kobj, dev->sysfs_rx_queue_group); | 967 | sysfs_remove_group(kobj, dev->sysfs_rx_queue_group); |
@@ -1367,7 +1367,7 @@ netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) | |||
1367 | while (--i >= new_num) { | 1367 | while (--i >= new_num) { |
1368 | struct netdev_queue *queue = dev->_tx + i; | 1368 | struct netdev_queue *queue = dev->_tx + i; |
1369 | 1369 | ||
1370 | if (!atomic_read(&dev_net(dev)->count)) | 1370 | if (!refcount_read(&dev_net(dev)->count)) |
1371 | queue->kobj.uevent_suppress = 1; | 1371 | queue->kobj.uevent_suppress = 1; |
1372 | #ifdef CONFIG_BQL | 1372 | #ifdef CONFIG_BQL |
1373 | sysfs_remove_group(&queue->kobj, &dql_group); | 1373 | sysfs_remove_group(&queue->kobj, &dql_group); |
@@ -1558,7 +1558,7 @@ void netdev_unregister_kobject(struct net_device *ndev) | |||
1558 | { | 1558 | { |
1559 | struct device *dev = &ndev->dev; | 1559 | struct device *dev = &ndev->dev; |
1560 | 1560 | ||
1561 | if (!atomic_read(&dev_net(ndev)->count)) | 1561 | if (!refcount_read(&dev_net(ndev)->count)) |
1562 | dev_set_uevent_suppress(dev, 1); | 1562 | dev_set_uevent_suppress(dev, 1); |
1563 | 1563 | ||
1564 | kobject_get(&dev->kobj); | 1564 | kobject_get(&dev->kobj); |
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 60a71be75aea..2213d45fcafd 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
@@ -35,7 +35,7 @@ LIST_HEAD(net_namespace_list); | |||
35 | EXPORT_SYMBOL_GPL(net_namespace_list); | 35 | EXPORT_SYMBOL_GPL(net_namespace_list); |
36 | 36 | ||
37 | struct net init_net = { | 37 | struct net init_net = { |
38 | .count = ATOMIC_INIT(1), | 38 | .count = REFCOUNT_INIT(1), |
39 | .dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head), | 39 | .dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head), |
40 | }; | 40 | }; |
41 | EXPORT_SYMBOL(init_net); | 41 | EXPORT_SYMBOL(init_net); |
@@ -224,10 +224,10 @@ int peernet2id_alloc(struct net *net, struct net *peer) | |||
224 | bool alloc; | 224 | bool alloc; |
225 | int id; | 225 | int id; |
226 | 226 | ||
227 | if (atomic_read(&net->count) == 0) | 227 | if (refcount_read(&net->count) == 0) |
228 | return NETNSA_NSID_NOT_ASSIGNED; | 228 | return NETNSA_NSID_NOT_ASSIGNED; |
229 | spin_lock_bh(&net->nsid_lock); | 229 | spin_lock_bh(&net->nsid_lock); |
230 | alloc = atomic_read(&peer->count) == 0 ? false : true; | 230 | alloc = refcount_read(&peer->count) == 0 ? false : true; |
231 | id = __peernet2id_alloc(net, peer, &alloc); | 231 | id = __peernet2id_alloc(net, peer, &alloc); |
232 | spin_unlock_bh(&net->nsid_lock); | 232 | spin_unlock_bh(&net->nsid_lock); |
233 | if (alloc && id >= 0) | 233 | if (alloc && id >= 0) |
@@ -284,7 +284,7 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) | |||
284 | int error = 0; | 284 | int error = 0; |
285 | LIST_HEAD(net_exit_list); | 285 | LIST_HEAD(net_exit_list); |
286 | 286 | ||
287 | atomic_set(&net->count, 1); | 287 | refcount_set(&net->count, 1); |
288 | refcount_set(&net->passive, 1); | 288 | refcount_set(&net->passive, 1); |
289 | net->dev_base_seq = 1; | 289 | net->dev_base_seq = 1; |
290 | net->user_ns = user_ns; | 290 | net->user_ns = user_ns; |
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 277ff69a312d..c3ea4906d237 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c | |||
@@ -270,14 +270,14 @@ restart: | |||
270 | continue; | 270 | continue; |
271 | tw = inet_twsk(sk); | 271 | tw = inet_twsk(sk); |
272 | if ((tw->tw_family != family) || | 272 | if ((tw->tw_family != family) || |
273 | atomic_read(&twsk_net(tw)->count)) | 273 | refcount_read(&twsk_net(tw)->count)) |
274 | continue; | 274 | continue; |
275 | 275 | ||
276 | if (unlikely(!refcount_inc_not_zero(&tw->tw_refcnt))) | 276 | if (unlikely(!refcount_inc_not_zero(&tw->tw_refcnt))) |
277 | continue; | 277 | continue; |
278 | 278 | ||
279 | if (unlikely((tw->tw_family != family) || | 279 | if (unlikely((tw->tw_family != family) || |
280 | atomic_read(&twsk_net(tw)->count))) { | 280 | refcount_read(&twsk_net(tw)->count))) { |
281 | inet_twsk_put(tw); | 281 | inet_twsk_put(tw); |
282 | goto restart; | 282 | goto restart; |
283 | } | 283 | } |
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 759e6bc8327b..03b51cdcc731 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c | |||
@@ -892,7 +892,7 @@ static void tcp_metrics_flush_all(struct net *net) | |||
892 | pp = &hb->chain; | 892 | pp = &hb->chain; |
893 | for (tm = deref_locked(*pp); tm; tm = deref_locked(*pp)) { | 893 | for (tm = deref_locked(*pp); tm; tm = deref_locked(*pp)) { |
894 | match = net ? net_eq(tm_net(tm), net) : | 894 | match = net ? net_eq(tm_net(tm), net) : |
895 | !atomic_read(&tm_net(tm)->count); | 895 | !refcount_read(&tm_net(tm)->count); |
896 | if (match) { | 896 | if (match) { |
897 | *pp = tm->tcpm_next; | 897 | *pp = tm->tcpm_next; |
898 | kfree_rcu(tm, rcu_head); | 898 | kfree_rcu(tm, rcu_head); |