diff options
author | WANG Cong <xiyou.wangcong@gmail.com> | 2014-09-11 18:35:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-13 16:38:42 -0400 |
commit | 83aa29eefdb152d65e65a90605593766b4f793ef (patch) | |
tree | ff658963e930a203ca95648fd7fef850186cdb23 | |
parent | 013b4d90387a5dca54281263e0d4650db97bd67c (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.c | 62 |
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 | ||
206 | static void aca_get(struct ifacaddr6 *aca) | ||
207 | { | ||
208 | atomic_inc(&aca->aca_refcnt); | ||
209 | } | ||
210 | |||
206 | static void aca_put(struct ifacaddr6 *ac) | 211 | static 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 | ||
220 | static 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; |
278 | out: | 295 | out: |
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 | ||