aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWANG Cong <xiyou.wangcong@gmail.com>2014-09-11 18:35:12 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-13 16:38:42 -0400
commit83aa29eefdb152d65e65a90605593766b4f793ef (patch)
treeff658963e930a203ca95648fd7fef850186cdb23
parent013b4d90387a5dca54281263e0d4650db97bd67c (diff)
ipv6: refactor __ipv6_dev_ac_inc()
Refactor out allocation and initialization and make the refcount code more readable. Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv6/anycast.c62
1 files changed, 39 insertions, 23 deletions
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 66c19320119a..952c1fd06150 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -203,6 +203,11 @@ void ipv6_sock_ac_close(struct sock *sk)
203 rtnl_unlock(); 203 rtnl_unlock();
204} 204}
205 205
206static void aca_get(struct ifacaddr6 *aca)
207{
208 atomic_inc(&aca->aca_refcnt);
209}
210
206static void aca_put(struct ifacaddr6 *ac) 211static void aca_put(struct ifacaddr6 *ac)
207{ 212{
208 if (atomic_dec_and_test(&ac->aca_refcnt)) { 213 if (atomic_dec_and_test(&ac->aca_refcnt)) {
@@ -212,6 +217,29 @@ static void aca_put(struct ifacaddr6 *ac)
212 } 217 }
213} 218}
214 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
215/* 243/*
216 * device anycast group inc (add if not found) 244 * device anycast group inc (add if not found)
217 */ 245 */
@@ -223,7 +251,6 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)
223 251
224 ASSERT_RTNL(); 252 ASSERT_RTNL();
225 253
226 in6_dev_hold(idev);
227 write_lock_bh(&idev->lock); 254 write_lock_bh(&idev->lock);
228 if (idev->dead) { 255 if (idev->dead) {
229 err = -ENODEV; 256 err = -ENODEV;
@@ -238,35 +265,25 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)
238 } 265 }
239 } 266 }
240 267
241 /*
242 * not found: create a new one.
243 */
244
245 aca = kzalloc(sizeof(struct ifacaddr6), GFP_ATOMIC);
246
247 if (aca == NULL) {
248 err = -ENOMEM;
249 goto out;
250 }
251
252 rt = addrconf_dst_alloc(idev, addr, true); 268 rt = addrconf_dst_alloc(idev, addr, true);
253 if (IS_ERR(rt)) { 269 if (IS_ERR(rt)) {
254 kfree(aca);
255 err = PTR_ERR(rt); 270 err = PTR_ERR(rt);
256 goto out; 271 goto out;
257 } 272 }
258 273 aca = aca_alloc(rt, addr);
259 aca->aca_addr = *addr; 274 if (aca == NULL) {
260 aca->aca_idev = idev; 275 ip6_rt_put(rt);
261 aca->aca_rt = rt; 276 err = -ENOMEM;
262 aca->aca_users = 1; 277 goto out;
263 /* aca_tstamp should be updated upon changes */ 278 }
264 aca->aca_cstamp = aca->aca_tstamp = jiffies;
265 atomic_set(&aca->aca_refcnt, 2);
266 spin_lock_init(&aca->aca_lock);
267 279
268 aca->aca_next = idev->ac_list; 280 aca->aca_next = idev->ac_list;
269 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);
270 write_unlock_bh(&idev->lock); 287 write_unlock_bh(&idev->lock);
271 288
272 ip6_ins_rt(rt); 289 ip6_ins_rt(rt);
@@ -277,7 +294,6 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)
277 return 0; 294 return 0;
278out: 295out:
279 write_unlock_bh(&idev->lock); 296 write_unlock_bh(&idev->lock);
280 in6_dev_put(idev);
281 return err; 297 return err;
282} 298}
283 299