aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-09-13 16:38:53 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-13 16:38:53 -0400
commit4361eb664de09a9f60955c7f5e9355f7ed46a08d (patch)
tree1456a054df7e78b1e4f10fac2041b3673e2b35de
parent8801d48cbde6ddd275c1e6b866e434a72cafeabd (diff)
parent1691c63ea42d6f57ba769df401b9773664edb936 (diff)
Merge branch 'ipv6-cleanups'
Cong Wang says: ==================== ipv6: clean up locking code in anycast and mcast This patchset cleans up the locking code in anycast.c and mcast.c and makes the refcount code more readable. Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> v1 -> v2: * refactor some code and make it in a separated patch * update comments ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--include/net/addrconf.h2
-rw-r--r--net/core/dev.c14
-rw-r--r--net/ipv6/addrconf.c2
-rw-r--r--net/ipv6/anycast.c108
-rw-r--r--net/ipv6/mcast.c129
6 files changed, 123 insertions, 136 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ae721f53739e..ee38b948d9a0 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2083,8 +2083,8 @@ void __dev_remove_pack(struct packet_type *pt);
2083void dev_add_offload(struct packet_offload *po); 2083void dev_add_offload(struct packet_offload *po);
2084void dev_remove_offload(struct packet_offload *po); 2084void dev_remove_offload(struct packet_offload *po);
2085 2085
2086struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short flags, 2086struct net_device *__dev_get_by_flags(struct net *net, unsigned short flags,
2087 unsigned short mask); 2087 unsigned short mask);
2088struct net_device *dev_get_by_name(struct net *net, const char *name); 2088struct net_device *dev_get_by_name(struct net *net, const char *name);
2089struct net_device *dev_get_by_name_rcu(struct net *net, const char *name); 2089struct net_device *dev_get_by_name_rcu(struct net *net, const char *name);
2090struct net_device *__dev_get_by_name(struct net *net, const char *name); 2090struct net_device *__dev_get_by_name(struct net *net, const char *name);
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index f679877bb601..9b1d42e66cca 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -202,7 +202,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex,
202 const struct in6_addr *addr); 202 const struct in6_addr *addr);
203void ipv6_sock_ac_close(struct sock *sk); 203void ipv6_sock_ac_close(struct sock *sk);
204 204
205int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr); 205int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr);
206int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr); 206int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr);
207bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev, 207bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
208 const struct in6_addr *addr); 208 const struct in6_addr *addr);
diff --git a/net/core/dev.c b/net/core/dev.c
index b3d6dbc0c696..e916ba8caccf 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -897,23 +897,25 @@ struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type)
897EXPORT_SYMBOL(dev_getfirstbyhwtype); 897EXPORT_SYMBOL(dev_getfirstbyhwtype);
898 898
899/** 899/**
900 * dev_get_by_flags_rcu - find any device with given flags 900 * __dev_get_by_flags - find any device with given flags
901 * @net: the applicable net namespace 901 * @net: the applicable net namespace
902 * @if_flags: IFF_* values 902 * @if_flags: IFF_* values
903 * @mask: bitmask of bits in if_flags to check 903 * @mask: bitmask of bits in if_flags to check
904 * 904 *
905 * Search for any interface with the given flags. Returns NULL if a device 905 * Search for any interface with the given flags. Returns NULL if a device
906 * is not found or a pointer to the device. Must be called inside 906 * is not found or a pointer to the device. Must be called inside
907 * rcu_read_lock(), and result refcount is unchanged. 907 * rtnl_lock(), and result refcount is unchanged.
908 */ 908 */
909 909
910struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short if_flags, 910struct net_device *__dev_get_by_flags(struct net *net, unsigned short if_flags,
911 unsigned short mask) 911 unsigned short mask)
912{ 912{
913 struct net_device *dev, *ret; 913 struct net_device *dev, *ret;
914 914
915 ASSERT_RTNL();
916
915 ret = NULL; 917 ret = NULL;
916 for_each_netdev_rcu(net, dev) { 918 for_each_netdev(net, dev) {
917 if (((dev->flags ^ if_flags) & mask) == 0) { 919 if (((dev->flags ^ if_flags) & mask) == 0) {
918 ret = dev; 920 ret = dev;
919 break; 921 break;
@@ -921,7 +923,7 @@ struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short if_flags
921 } 923 }
922 return ret; 924 return ret;
923} 925}
924EXPORT_SYMBOL(dev_get_by_flags_rcu); 926EXPORT_SYMBOL(__dev_get_by_flags);
925 927
926/** 928/**
927 * dev_valid_name - check if name is okay for network device 929 * dev_valid_name - check if name is okay for network device
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index ad4598fcc416..6b6a373a30b2 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1725,7 +1725,7 @@ static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
1725 ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len); 1725 ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
1726 if (ipv6_addr_any(&addr)) 1726 if (ipv6_addr_any(&addr))
1727 return; 1727 return;
1728 ipv6_dev_ac_inc(ifp->idev->dev, &addr); 1728 __ipv6_dev_ac_inc(ifp->idev, &addr);
1729} 1729}
1730 1730
1731/* caller must hold RTNL */ 1731/* caller must hold RTNL */
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index ff2de7d9d8e6..952c1fd06150 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -46,10 +46,6 @@
46 46
47static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr); 47static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr);
48 48
49/* Big ac list lock for all the sockets */
50static DEFINE_SPINLOCK(ipv6_sk_ac_lock);
51
52
53/* 49/*
54 * socket join an anycast group 50 * socket join an anycast group
55 */ 51 */
@@ -78,7 +74,6 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
78 pac->acl_addr = *addr; 74 pac->acl_addr = *addr;
79 75
80 rtnl_lock(); 76 rtnl_lock();
81 rcu_read_lock();
82 if (ifindex == 0) { 77 if (ifindex == 0) {
83 struct rt6_info *rt; 78 struct rt6_info *rt;
84 79
@@ -91,11 +86,11 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
91 goto error; 86 goto error;
92 } else { 87 } else {
93 /* router, no matching interface: just pick one */ 88 /* router, no matching interface: just pick one */
94 dev = dev_get_by_flags_rcu(net, IFF_UP, 89 dev = __dev_get_by_flags(net, IFF_UP,
95 IFF_UP | IFF_LOOPBACK); 90 IFF_UP | IFF_LOOPBACK);
96 } 91 }
97 } else 92 } else
98 dev = dev_get_by_index_rcu(net, ifindex); 93 dev = __dev_get_by_index(net, ifindex);
99 94
100 if (dev == NULL) { 95 if (dev == NULL) {
101 err = -ENODEV; 96 err = -ENODEV;
@@ -127,17 +122,14 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
127 goto error; 122 goto error;
128 } 123 }
129 124
130 err = ipv6_dev_ac_inc(dev, addr); 125 err = __ipv6_dev_ac_inc(idev, addr);
131 if (!err) { 126 if (!err) {
132 spin_lock_bh(&ipv6_sk_ac_lock);
133 pac->acl_next = np->ipv6_ac_list; 127 pac->acl_next = np->ipv6_ac_list;
134 np->ipv6_ac_list = pac; 128 np->ipv6_ac_list = pac;
135 spin_unlock_bh(&ipv6_sk_ac_lock);
136 pac = NULL; 129 pac = NULL;
137 } 130 }
138 131
139error: 132error:
140 rcu_read_unlock();
141 rtnl_unlock(); 133 rtnl_unlock();
142 if (pac) 134 if (pac)
143 sock_kfree_s(sk, pac, sizeof(*pac)); 135 sock_kfree_s(sk, pac, sizeof(*pac));
@@ -154,7 +146,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
154 struct ipv6_ac_socklist *pac, *prev_pac; 146 struct ipv6_ac_socklist *pac, *prev_pac;
155 struct net *net = sock_net(sk); 147 struct net *net = sock_net(sk);
156 148
157 spin_lock_bh(&ipv6_sk_ac_lock); 149 rtnl_lock();
158 prev_pac = NULL; 150 prev_pac = NULL;
159 for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) { 151 for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) {
160 if ((ifindex == 0 || pac->acl_ifindex == ifindex) && 152 if ((ifindex == 0 || pac->acl_ifindex == ifindex) &&
@@ -163,7 +155,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
163 prev_pac = pac; 155 prev_pac = pac;
164 } 156 }
165 if (!pac) { 157 if (!pac) {
166 spin_unlock_bh(&ipv6_sk_ac_lock); 158 rtnl_unlock();
167 return -ENOENT; 159 return -ENOENT;
168 } 160 }
169 if (prev_pac) 161 if (prev_pac)
@@ -171,14 +163,9 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
171 else 163 else
172 np->ipv6_ac_list = pac->acl_next; 164 np->ipv6_ac_list = pac->acl_next;
173 165
174 spin_unlock_bh(&ipv6_sk_ac_lock); 166 dev = __dev_get_by_index(net, pac->acl_ifindex);
175
176 rtnl_lock();
177 rcu_read_lock();
178 dev = dev_get_by_index_rcu(net, pac->acl_ifindex);
179 if (dev) 167 if (dev)
180 ipv6_dev_ac_dec(dev, &pac->acl_addr); 168 ipv6_dev_ac_dec(dev, &pac->acl_addr);
181 rcu_read_unlock();
182 rtnl_unlock(); 169 rtnl_unlock();
183 170
184 sock_kfree_s(sk, pac, sizeof(*pac)); 171 sock_kfree_s(sk, pac, sizeof(*pac));
@@ -196,19 +183,16 @@ void ipv6_sock_ac_close(struct sock *sk)
196 if (!np->ipv6_ac_list) 183 if (!np->ipv6_ac_list)
197 return; 184 return;
198 185
199 spin_lock_bh(&ipv6_sk_ac_lock); 186 rtnl_lock();
200 pac = np->ipv6_ac_list; 187 pac = np->ipv6_ac_list;
201 np->ipv6_ac_list = NULL; 188 np->ipv6_ac_list = NULL;
202 spin_unlock_bh(&ipv6_sk_ac_lock);
203 189
204 prev_index = 0; 190 prev_index = 0;
205 rtnl_lock();
206 rcu_read_lock();
207 while (pac) { 191 while (pac) {
208 struct ipv6_ac_socklist *next = pac->acl_next; 192 struct ipv6_ac_socklist *next = pac->acl_next;
209 193
210 if (pac->acl_ifindex != prev_index) { 194 if (pac->acl_ifindex != prev_index) {
211 dev = dev_get_by_index_rcu(net, pac->acl_ifindex); 195 dev = __dev_get_by_index(net, pac->acl_ifindex);
212 prev_index = pac->acl_ifindex; 196 prev_index = pac->acl_ifindex;
213 } 197 }
214 if (dev) 198 if (dev)
@@ -216,10 +200,14 @@ void ipv6_sock_ac_close(struct sock *sk)
216 sock_kfree_s(sk, pac, sizeof(*pac)); 200 sock_kfree_s(sk, pac, sizeof(*pac));
217 pac = next; 201 pac = next;
218 } 202 }
219 rcu_read_unlock();
220 rtnl_unlock(); 203 rtnl_unlock();
221} 204}
222 205
206static void aca_get(struct ifacaddr6 *aca)
207{
208 atomic_inc(&aca->aca_refcnt);
209}
210
223static void aca_put(struct ifacaddr6 *ac) 211static void aca_put(struct ifacaddr6 *ac)
224{ 212{
225 if (atomic_dec_and_test(&ac->aca_refcnt)) { 213 if (atomic_dec_and_test(&ac->aca_refcnt)) {
@@ -229,23 +217,40 @@ static void aca_put(struct ifacaddr6 *ac)
229 } 217 }
230} 218}
231 219
220static struct ifacaddr6 *aca_alloc(struct rt6_info *rt,
221 const struct in6_addr *addr)
222{
223 struct inet6_dev *idev = rt->rt6i_idev;
224 struct ifacaddr6 *aca;
225
226 aca = kzalloc(sizeof(*aca), GFP_ATOMIC);
227 if (aca == NULL)
228 return NULL;
229
230 aca->aca_addr = *addr;
231 in6_dev_hold(idev);
232 aca->aca_idev = idev;
233 aca->aca_rt = rt;
234 aca->aca_users = 1;
235 /* aca_tstamp should be updated upon changes */
236 aca->aca_cstamp = aca->aca_tstamp = jiffies;
237 atomic_set(&aca->aca_refcnt, 1);
238 spin_lock_init(&aca->aca_lock);
239
240 return aca;
241}
242
232/* 243/*
233 * device anycast group inc (add if not found) 244 * device anycast group inc (add if not found)
234 */ 245 */
235int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr) 246int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)
236{ 247{
237 struct ifacaddr6 *aca; 248 struct ifacaddr6 *aca;
238 struct inet6_dev *idev;
239 struct rt6_info *rt; 249 struct rt6_info *rt;
240 int err; 250 int err;
241 251
242 ASSERT_RTNL(); 252 ASSERT_RTNL();
243 253
244 idev = in6_dev_get(dev);
245
246 if (idev == NULL)
247 return -EINVAL;
248
249 write_lock_bh(&idev->lock); 254 write_lock_bh(&idev->lock);
250 if (idev->dead) { 255 if (idev->dead) {
251 err = -ENODEV; 256 err = -ENODEV;
@@ -260,46 +265,35 @@ int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr)
260 } 265 }
261 } 266 }
262 267
263 /*
264 * not found: create a new one.
265 */
266
267 aca = kzalloc(sizeof(struct ifacaddr6), GFP_ATOMIC);
268
269 if (aca == NULL) {
270 err = -ENOMEM;
271 goto out;
272 }
273
274 rt = addrconf_dst_alloc(idev, addr, true); 268 rt = addrconf_dst_alloc(idev, addr, true);
275 if (IS_ERR(rt)) { 269 if (IS_ERR(rt)) {
276 kfree(aca);
277 err = PTR_ERR(rt); 270 err = PTR_ERR(rt);
278 goto out; 271 goto out;
279 } 272 }
280 273 aca = aca_alloc(rt, addr);
281 aca->aca_addr = *addr; 274 if (aca == NULL) {
282 aca->aca_idev = idev; 275 ip6_rt_put(rt);
283 aca->aca_rt = rt; 276 err = -ENOMEM;
284 aca->aca_users = 1; 277 goto out;
285 /* aca_tstamp should be updated upon changes */ 278 }
286 aca->aca_cstamp = aca->aca_tstamp = jiffies;
287 atomic_set(&aca->aca_refcnt, 2);
288 spin_lock_init(&aca->aca_lock);
289 279
290 aca->aca_next = idev->ac_list; 280 aca->aca_next = idev->ac_list;
291 idev->ac_list = aca; 281 idev->ac_list = aca;
282
283 /* Hold this for addrconf_join_solict() below before we unlock,
284 * it is already exposed via idev->ac_list.
285 */
286 aca_get(aca);
292 write_unlock_bh(&idev->lock); 287 write_unlock_bh(&idev->lock);
293 288
294 ip6_ins_rt(rt); 289 ip6_ins_rt(rt);
295 290
296 addrconf_join_solict(dev, &aca->aca_addr); 291 addrconf_join_solict(idev->dev, &aca->aca_addr);
297 292
298 aca_put(aca); 293 aca_put(aca);
299 return 0; 294 return 0;
300out: 295out:
301 write_unlock_bh(&idev->lock); 296 write_unlock_bh(&idev->lock);
302 in6_dev_put(idev);
303 return err; 297 return err;
304} 298}
305 299
@@ -341,7 +335,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr)
341 return 0; 335 return 0;
342} 336}
343 337
344/* called with rcu_read_lock() */ 338/* called with rtnl_lock() */
345static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr) 339static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr)
346{ 340{
347 struct inet6_dev *idev = __in6_dev_get(dev); 341 struct inet6_dev *idev = __in6_dev_get(dev);
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 484a94215d88..592eba61e78a 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -73,9 +73,6 @@ static void *__mld2_query_bugs[] __attribute__((__unused__)) = {
73 73
74static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; 74static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT;
75 75
76/* Big mc list lock for all the sockets */
77static DEFINE_SPINLOCK(ipv6_sk_mc_lock);
78
79static void igmp6_join_group(struct ifmcaddr6 *ma); 76static void igmp6_join_group(struct ifmcaddr6 *ma);
80static void igmp6_leave_group(struct ifmcaddr6 *ma); 77static void igmp6_leave_group(struct ifmcaddr6 *ma);
81static void igmp6_timer_handler(unsigned long data); 78static void igmp6_timer_handler(unsigned long data);
@@ -165,7 +162,6 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
165 mc_lst->addr = *addr; 162 mc_lst->addr = *addr;
166 163
167 rtnl_lock(); 164 rtnl_lock();
168 rcu_read_lock();
169 if (ifindex == 0) { 165 if (ifindex == 0) {
170 struct rt6_info *rt; 166 struct rt6_info *rt;
171 rt = rt6_lookup(net, addr, NULL, 0, 0); 167 rt = rt6_lookup(net, addr, NULL, 0, 0);
@@ -174,10 +170,9 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
174 ip6_rt_put(rt); 170 ip6_rt_put(rt);
175 } 171 }
176 } else 172 } else
177 dev = dev_get_by_index_rcu(net, ifindex); 173 dev = __dev_get_by_index(net, ifindex);
178 174
179 if (dev == NULL) { 175 if (dev == NULL) {
180 rcu_read_unlock();
181 rtnl_unlock(); 176 rtnl_unlock();
182 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); 177 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
183 return -ENODEV; 178 return -ENODEV;
@@ -195,18 +190,14 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
195 err = ipv6_dev_mc_inc(dev, addr); 190 err = ipv6_dev_mc_inc(dev, addr);
196 191
197 if (err) { 192 if (err) {
198 rcu_read_unlock();
199 rtnl_unlock(); 193 rtnl_unlock();
200 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); 194 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
201 return err; 195 return err;
202 } 196 }
203 197
204 spin_lock(&ipv6_sk_mc_lock);
205 mc_lst->next = np->ipv6_mc_list; 198 mc_lst->next = np->ipv6_mc_list;
206 rcu_assign_pointer(np->ipv6_mc_list, mc_lst); 199 rcu_assign_pointer(np->ipv6_mc_list, mc_lst);
207 spin_unlock(&ipv6_sk_mc_lock);
208 200
209 rcu_read_unlock();
210 rtnl_unlock(); 201 rtnl_unlock();
211 202
212 return 0; 203 return 0;
@@ -226,20 +217,16 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
226 return -EINVAL; 217 return -EINVAL;
227 218
228 rtnl_lock(); 219 rtnl_lock();
229 spin_lock(&ipv6_sk_mc_lock);
230 for (lnk = &np->ipv6_mc_list; 220 for (lnk = &np->ipv6_mc_list;
231 (mc_lst = rcu_dereference_protected(*lnk, 221 (mc_lst = rtnl_dereference(*lnk)) != NULL;
232 lockdep_is_held(&ipv6_sk_mc_lock))) != NULL;
233 lnk = &mc_lst->next) { 222 lnk = &mc_lst->next) {
234 if ((ifindex == 0 || mc_lst->ifindex == ifindex) && 223 if ((ifindex == 0 || mc_lst->ifindex == ifindex) &&
235 ipv6_addr_equal(&mc_lst->addr, addr)) { 224 ipv6_addr_equal(&mc_lst->addr, addr)) {
236 struct net_device *dev; 225 struct net_device *dev;
237 226
238 *lnk = mc_lst->next; 227 *lnk = mc_lst->next;
239 spin_unlock(&ipv6_sk_mc_lock);
240 228
241 rcu_read_lock(); 229 dev = __dev_get_by_index(net, mc_lst->ifindex);
242 dev = dev_get_by_index_rcu(net, mc_lst->ifindex);
243 if (dev != NULL) { 230 if (dev != NULL) {
244 struct inet6_dev *idev = __in6_dev_get(dev); 231 struct inet6_dev *idev = __in6_dev_get(dev);
245 232
@@ -248,7 +235,6 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
248 __ipv6_dev_mc_dec(idev, &mc_lst->addr); 235 __ipv6_dev_mc_dec(idev, &mc_lst->addr);
249 } else 236 } else
250 (void) ip6_mc_leave_src(sk, mc_lst, NULL); 237 (void) ip6_mc_leave_src(sk, mc_lst, NULL);
251 rcu_read_unlock();
252 rtnl_unlock(); 238 rtnl_unlock();
253 239
254 atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); 240 atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
@@ -256,7 +242,6 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
256 return 0; 242 return 0;
257 } 243 }
258 } 244 }
259 spin_unlock(&ipv6_sk_mc_lock);
260 rtnl_unlock(); 245 rtnl_unlock();
261 246
262 return -EADDRNOTAVAIL; 247 return -EADDRNOTAVAIL;
@@ -303,16 +288,12 @@ void ipv6_sock_mc_close(struct sock *sk)
303 return; 288 return;
304 289
305 rtnl_lock(); 290 rtnl_lock();
306 spin_lock(&ipv6_sk_mc_lock); 291 while ((mc_lst = rtnl_dereference(np->ipv6_mc_list)) != NULL) {
307 while ((mc_lst = rcu_dereference_protected(np->ipv6_mc_list,
308 lockdep_is_held(&ipv6_sk_mc_lock))) != NULL) {
309 struct net_device *dev; 292 struct net_device *dev;
310 293
311 np->ipv6_mc_list = mc_lst->next; 294 np->ipv6_mc_list = mc_lst->next;
312 spin_unlock(&ipv6_sk_mc_lock);
313 295
314 rcu_read_lock(); 296 dev = __dev_get_by_index(net, mc_lst->ifindex);
315 dev = dev_get_by_index_rcu(net, mc_lst->ifindex);
316 if (dev) { 297 if (dev) {
317 struct inet6_dev *idev = __in6_dev_get(dev); 298 struct inet6_dev *idev = __in6_dev_get(dev);
318 299
@@ -321,14 +302,11 @@ void ipv6_sock_mc_close(struct sock *sk)
321 __ipv6_dev_mc_dec(idev, &mc_lst->addr); 302 __ipv6_dev_mc_dec(idev, &mc_lst->addr);
322 } else 303 } else
323 (void) ip6_mc_leave_src(sk, mc_lst, NULL); 304 (void) ip6_mc_leave_src(sk, mc_lst, NULL);
324 rcu_read_unlock();
325 305
326 atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); 306 atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
327 kfree_rcu(mc_lst, rcu); 307 kfree_rcu(mc_lst, rcu);
328 308
329 spin_lock(&ipv6_sk_mc_lock);
330 } 309 }
331 spin_unlock(&ipv6_sk_mc_lock);
332 rtnl_unlock(); 310 rtnl_unlock();
333} 311}
334 312
@@ -578,9 +556,8 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
578 } 556 }
579 557
580 err = -EADDRNOTAVAIL; 558 err = -EADDRNOTAVAIL;
581 /* 559 /* changes to the ipv6_mc_list require the socket lock and
582 * changes to the ipv6_mc_list require the socket lock and 560 * rtnl lock. We have the socket lock and rcu read lock,
583 * a read lock on ip6_sk_mc_lock. We have the socket lock,
584 * so reading the list is safe. 561 * so reading the list is safe.
585 */ 562 */
586 563
@@ -604,9 +581,8 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
604 copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) { 581 copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) {
605 return -EFAULT; 582 return -EFAULT;
606 } 583 }
607 /* changes to psl require the socket lock, a read lock on 584 /* changes to psl require the socket lock, and a write lock
608 * on ipv6_sk_mc_lock and a write lock on pmc->sflock. We 585 * on pmc->sflock. We have the socket lock so reading here is safe.
609 * have the socket lock, so reading here is safe.
610 */ 586 */
611 for (i = 0; i < copycount; i++) { 587 for (i = 0; i < copycount; i++) {
612 struct sockaddr_in6 *psin6; 588 struct sockaddr_in6 *psin6;
@@ -665,14 +641,6 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
665 return rv; 641 return rv;
666} 642}
667 643
668static void ma_put(struct ifmcaddr6 *mc)
669{
670 if (atomic_dec_and_test(&mc->mca_refcnt)) {
671 in6_dev_put(mc->idev);
672 kfree(mc);
673 }
674}
675
676static void igmp6_group_added(struct ifmcaddr6 *mc) 644static void igmp6_group_added(struct ifmcaddr6 *mc)
677{ 645{
678 struct net_device *dev = mc->idev->dev; 646 struct net_device *dev = mc->idev->dev;
@@ -838,6 +806,48 @@ static void mld_clear_delrec(struct inet6_dev *idev)
838 read_unlock_bh(&idev->lock); 806 read_unlock_bh(&idev->lock);
839} 807}
840 808
809static void mca_get(struct ifmcaddr6 *mc)
810{
811 atomic_inc(&mc->mca_refcnt);
812}
813
814static void ma_put(struct ifmcaddr6 *mc)
815{
816 if (atomic_dec_and_test(&mc->mca_refcnt)) {
817 in6_dev_put(mc->idev);
818 kfree(mc);
819 }
820}
821
822static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev,
823 const struct in6_addr *addr)
824{
825 struct ifmcaddr6 *mc;
826
827 mc = kzalloc(sizeof(*mc), GFP_ATOMIC);
828 if (mc == NULL)
829 return NULL;
830
831 setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc);
832
833 mc->mca_addr = *addr;
834 mc->idev = idev; /* reference taken by caller */
835 mc->mca_users = 1;
836 /* mca_stamp should be updated upon changes */
837 mc->mca_cstamp = mc->mca_tstamp = jiffies;
838 atomic_set(&mc->mca_refcnt, 1);
839 spin_lock_init(&mc->mca_lock);
840
841 /* initial mode is (EX, empty) */
842 mc->mca_sfmode = MCAST_EXCLUDE;
843 mc->mca_sfcount[MCAST_EXCLUDE] = 1;
844
845 if (ipv6_addr_is_ll_all_nodes(&mc->mca_addr) ||
846 IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL)
847 mc->mca_flags |= MAF_NOREPORT;
848
849 return mc;
850}
841 851
842/* 852/*
843 * device multicast group inc (add if not found) 853 * device multicast group inc (add if not found)
@@ -873,38 +883,20 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
873 } 883 }
874 } 884 }
875 885
876 /* 886 mc = mca_alloc(idev, addr);
877 * not found: create a new one. 887 if (!mc) {
878 */
879
880 mc = kzalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);
881
882 if (mc == NULL) {
883 write_unlock_bh(&idev->lock); 888 write_unlock_bh(&idev->lock);
884 in6_dev_put(idev); 889 in6_dev_put(idev);
885 return -ENOMEM; 890 return -ENOMEM;
886 } 891 }
887 892
888 setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc);
889
890 mc->mca_addr = *addr;
891 mc->idev = idev; /* (reference taken) */
892 mc->mca_users = 1;
893 /* mca_stamp should be updated upon changes */
894 mc->mca_cstamp = mc->mca_tstamp = jiffies;
895 atomic_set(&mc->mca_refcnt, 2);
896 spin_lock_init(&mc->mca_lock);
897
898 /* initial mode is (EX, empty) */
899 mc->mca_sfmode = MCAST_EXCLUDE;
900 mc->mca_sfcount[MCAST_EXCLUDE] = 1;
901
902 if (ipv6_addr_is_ll_all_nodes(&mc->mca_addr) ||
903 IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL)
904 mc->mca_flags |= MAF_NOREPORT;
905
906 mc->next = idev->mc_list; 893 mc->next = idev->mc_list;
907 idev->mc_list = mc; 894 idev->mc_list = mc;
895
896 /* Hold this for the code below before we unlock,
897 * it is already exposed via idev->mc_list.
898 */
899 mca_get(mc);
908 write_unlock_bh(&idev->lock); 900 write_unlock_bh(&idev->lock);
909 901
910 mld_del_delrec(idev, &mc->mca_addr); 902 mld_del_delrec(idev, &mc->mca_addr);
@@ -948,7 +940,7 @@ int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)
948 struct inet6_dev *idev; 940 struct inet6_dev *idev;
949 int err; 941 int err;
950 942
951 rcu_read_lock(); 943 ASSERT_RTNL();
952 944
953 idev = __in6_dev_get(dev); 945 idev = __in6_dev_get(dev);
954 if (!idev) 946 if (!idev)
@@ -956,7 +948,6 @@ int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)
956 else 948 else
957 err = __ipv6_dev_mc_dec(idev, addr); 949 err = __ipv6_dev_mc_dec(idev, addr);
958 950
959 rcu_read_unlock();
960 return err; 951 return err;
961} 952}
962 953
@@ -2373,7 +2364,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
2373{ 2364{
2374 int err; 2365 int err;
2375 2366
2376 /* callers have the socket lock and a write lock on ipv6_sk_mc_lock, 2367 /* callers have the socket lock and rtnl lock
2377 * so no other readers or writers of iml or its sflist 2368 * so no other readers or writers of iml or its sflist
2378 */ 2369 */
2379 if (!iml->sflist) { 2370 if (!iml->sflist) {