diff options
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r-- | net/tipc/socket.c | 84 |
1 files changed, 58 insertions, 26 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index c1e93c9515bc..3f03ddd0e35b 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -576,6 +576,7 @@ static int tipc_release(struct socket *sock) | |||
576 | sk_stop_timer(sk, &sk->sk_timer); | 576 | sk_stop_timer(sk, &sk->sk_timer); |
577 | tipc_sk_remove(tsk); | 577 | tipc_sk_remove(tsk); |
578 | 578 | ||
579 | sock_orphan(sk); | ||
579 | /* Reject any messages that accumulated in backlog queue */ | 580 | /* Reject any messages that accumulated in backlog queue */ |
580 | release_sock(sk); | 581 | release_sock(sk); |
581 | tipc_dest_list_purge(&tsk->cong_links); | 582 | tipc_dest_list_purge(&tsk->cong_links); |
@@ -2672,6 +2673,8 @@ void tipc_sk_reinit(struct net *net) | |||
2672 | 2673 | ||
2673 | rhashtable_walk_stop(&iter); | 2674 | rhashtable_walk_stop(&iter); |
2674 | } while (tsk == ERR_PTR(-EAGAIN)); | 2675 | } while (tsk == ERR_PTR(-EAGAIN)); |
2676 | |||
2677 | rhashtable_walk_exit(&iter); | ||
2675 | } | 2678 | } |
2676 | 2679 | ||
2677 | static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid) | 2680 | static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid) |
@@ -3227,45 +3230,74 @@ int tipc_nl_sk_walk(struct sk_buff *skb, struct netlink_callback *cb, | |||
3227 | struct netlink_callback *cb, | 3230 | struct netlink_callback *cb, |
3228 | struct tipc_sock *tsk)) | 3231 | struct tipc_sock *tsk)) |
3229 | { | 3232 | { |
3230 | struct net *net = sock_net(skb->sk); | 3233 | struct rhashtable_iter *iter = (void *)cb->args[4]; |
3231 | struct tipc_net *tn = tipc_net(net); | ||
3232 | const struct bucket_table *tbl; | ||
3233 | u32 prev_portid = cb->args[1]; | ||
3234 | u32 tbl_id = cb->args[0]; | ||
3235 | struct rhash_head *pos; | ||
3236 | struct tipc_sock *tsk; | 3234 | struct tipc_sock *tsk; |
3237 | int err; | 3235 | int err; |
3238 | 3236 | ||
3239 | rcu_read_lock(); | 3237 | rhashtable_walk_start(iter); |
3240 | tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht); | 3238 | while ((tsk = rhashtable_walk_next(iter)) != NULL) { |
3241 | for (; tbl_id < tbl->size; tbl_id++) { | 3239 | if (IS_ERR(tsk)) { |
3242 | rht_for_each_entry_rcu(tsk, pos, tbl, tbl_id, node) { | 3240 | err = PTR_ERR(tsk); |
3243 | spin_lock_bh(&tsk->sk.sk_lock.slock); | 3241 | if (err == -EAGAIN) { |
3244 | if (prev_portid && prev_portid != tsk->portid) { | 3242 | err = 0; |
3245 | spin_unlock_bh(&tsk->sk.sk_lock.slock); | ||
3246 | continue; | 3243 | continue; |
3247 | } | 3244 | } |
3245 | break; | ||
3246 | } | ||
3248 | 3247 | ||
3249 | err = skb_handler(skb, cb, tsk); | 3248 | sock_hold(&tsk->sk); |
3250 | if (err) { | 3249 | rhashtable_walk_stop(iter); |
3251 | prev_portid = tsk->portid; | 3250 | lock_sock(&tsk->sk); |
3252 | spin_unlock_bh(&tsk->sk.sk_lock.slock); | 3251 | err = skb_handler(skb, cb, tsk); |
3253 | goto out; | 3252 | if (err) { |
3254 | } | 3253 | release_sock(&tsk->sk); |
3255 | 3254 | sock_put(&tsk->sk); | |
3256 | prev_portid = 0; | 3255 | goto out; |
3257 | spin_unlock_bh(&tsk->sk.sk_lock.slock); | ||
3258 | } | 3256 | } |
3257 | release_sock(&tsk->sk); | ||
3258 | rhashtable_walk_start(iter); | ||
3259 | sock_put(&tsk->sk); | ||
3259 | } | 3260 | } |
3261 | rhashtable_walk_stop(iter); | ||
3260 | out: | 3262 | out: |
3261 | rcu_read_unlock(); | ||
3262 | cb->args[0] = tbl_id; | ||
3263 | cb->args[1] = prev_portid; | ||
3264 | |||
3265 | return skb->len; | 3263 | return skb->len; |
3266 | } | 3264 | } |
3267 | EXPORT_SYMBOL(tipc_nl_sk_walk); | 3265 | EXPORT_SYMBOL(tipc_nl_sk_walk); |
3268 | 3266 | ||
3267 | int tipc_dump_start(struct netlink_callback *cb) | ||
3268 | { | ||
3269 | return __tipc_dump_start(cb, sock_net(cb->skb->sk)); | ||
3270 | } | ||
3271 | EXPORT_SYMBOL(tipc_dump_start); | ||
3272 | |||
3273 | int __tipc_dump_start(struct netlink_callback *cb, struct net *net) | ||
3274 | { | ||
3275 | /* tipc_nl_name_table_dump() uses cb->args[0...3]. */ | ||
3276 | struct rhashtable_iter *iter = (void *)cb->args[4]; | ||
3277 | struct tipc_net *tn = tipc_net(net); | ||
3278 | |||
3279 | if (!iter) { | ||
3280 | iter = kmalloc(sizeof(*iter), GFP_KERNEL); | ||
3281 | if (!iter) | ||
3282 | return -ENOMEM; | ||
3283 | |||
3284 | cb->args[4] = (long)iter; | ||
3285 | } | ||
3286 | |||
3287 | rhashtable_walk_enter(&tn->sk_rht, iter); | ||
3288 | return 0; | ||
3289 | } | ||
3290 | |||
3291 | int tipc_dump_done(struct netlink_callback *cb) | ||
3292 | { | ||
3293 | struct rhashtable_iter *hti = (void *)cb->args[4]; | ||
3294 | |||
3295 | rhashtable_walk_exit(hti); | ||
3296 | kfree(hti); | ||
3297 | return 0; | ||
3298 | } | ||
3299 | EXPORT_SYMBOL(tipc_dump_done); | ||
3300 | |||
3269 | int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct netlink_callback *cb, | 3301 | int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct netlink_callback *cb, |
3270 | struct tipc_sock *tsk, u32 sk_filter_state, | 3302 | struct tipc_sock *tsk, u32 sk_filter_state, |
3271 | u64 (*tipc_diag_gen_cookie)(struct sock *sk)) | 3303 | u64 (*tipc_diag_gen_cookie)(struct sock *sk)) |