aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r--net/tipc/socket.c84
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
2677static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid) 2680static 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);
3260out: 3262out:
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}
3267EXPORT_SYMBOL(tipc_nl_sk_walk); 3265EXPORT_SYMBOL(tipc_nl_sk_walk);
3268 3266
3267int tipc_dump_start(struct netlink_callback *cb)
3268{
3269 return __tipc_dump_start(cb, sock_net(cb->skb->sk));
3270}
3271EXPORT_SYMBOL(tipc_dump_start);
3272
3273int __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
3291int 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}
3299EXPORT_SYMBOL(tipc_dump_done);
3300
3269int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct netlink_callback *cb, 3301int 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))