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.c88
1 files changed, 61 insertions, 27 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index c1e93c9515bc..b6f99b021d09 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);
@@ -1418,8 +1419,10 @@ static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dlen)
1418 /* Handle implicit connection setup */ 1419 /* Handle implicit connection setup */
1419 if (unlikely(dest)) { 1420 if (unlikely(dest)) {
1420 rc = __tipc_sendmsg(sock, m, dlen); 1421 rc = __tipc_sendmsg(sock, m, dlen);
1421 if (dlen && (dlen == rc)) 1422 if (dlen && dlen == rc) {
1423 tsk->peer_caps = tipc_node_get_capabilities(net, dnode);
1422 tsk->snt_unacked = tsk_inc(tsk, dlen + msg_hdr_sz(hdr)); 1424 tsk->snt_unacked = tsk_inc(tsk, dlen + msg_hdr_sz(hdr));
1425 }
1423 return rc; 1426 return rc;
1424 } 1427 }
1425 1428
@@ -2672,6 +2675,8 @@ void tipc_sk_reinit(struct net *net)
2672 2675
2673 rhashtable_walk_stop(&iter); 2676 rhashtable_walk_stop(&iter);
2674 } while (tsk == ERR_PTR(-EAGAIN)); 2677 } while (tsk == ERR_PTR(-EAGAIN));
2678
2679 rhashtable_walk_exit(&iter);
2675} 2680}
2676 2681
2677static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid) 2682static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid)
@@ -3227,45 +3232,74 @@ int tipc_nl_sk_walk(struct sk_buff *skb, struct netlink_callback *cb,
3227 struct netlink_callback *cb, 3232 struct netlink_callback *cb,
3228 struct tipc_sock *tsk)) 3233 struct tipc_sock *tsk))
3229{ 3234{
3230 struct net *net = sock_net(skb->sk); 3235 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; 3236 struct tipc_sock *tsk;
3237 int err; 3237 int err;
3238 3238
3239 rcu_read_lock(); 3239 rhashtable_walk_start(iter);
3240 tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht); 3240 while ((tsk = rhashtable_walk_next(iter)) != NULL) {
3241 for (; tbl_id < tbl->size; tbl_id++) { 3241 if (IS_ERR(tsk)) {
3242 rht_for_each_entry_rcu(tsk, pos, tbl, tbl_id, node) { 3242 err = PTR_ERR(tsk);
3243 spin_lock_bh(&tsk->sk.sk_lock.slock); 3243 if (err == -EAGAIN) {
3244 if (prev_portid && prev_portid != tsk->portid) { 3244 err = 0;
3245 spin_unlock_bh(&tsk->sk.sk_lock.slock);
3246 continue; 3245 continue;
3247 } 3246 }
3247 break;
3248 }
3248 3249
3249 err = skb_handler(skb, cb, tsk); 3250 sock_hold(&tsk->sk);
3250 if (err) { 3251 rhashtable_walk_stop(iter);
3251 prev_portid = tsk->portid; 3252 lock_sock(&tsk->sk);
3252 spin_unlock_bh(&tsk->sk.sk_lock.slock); 3253 err = skb_handler(skb, cb, tsk);
3253 goto out; 3254 if (err) {
3254 } 3255 release_sock(&tsk->sk);
3255 3256 sock_put(&tsk->sk);
3256 prev_portid = 0; 3257 goto out;
3257 spin_unlock_bh(&tsk->sk.sk_lock.slock);
3258 } 3258 }
3259 release_sock(&tsk->sk);
3260 rhashtable_walk_start(iter);
3261 sock_put(&tsk->sk);
3259 } 3262 }
3263 rhashtable_walk_stop(iter);
3260out: 3264out:
3261 rcu_read_unlock();
3262 cb->args[0] = tbl_id;
3263 cb->args[1] = prev_portid;
3264
3265 return skb->len; 3265 return skb->len;
3266} 3266}
3267EXPORT_SYMBOL(tipc_nl_sk_walk); 3267EXPORT_SYMBOL(tipc_nl_sk_walk);
3268 3268
3269int tipc_dump_start(struct netlink_callback *cb)
3270{
3271 return __tipc_dump_start(cb, sock_net(cb->skb->sk));
3272}
3273EXPORT_SYMBOL(tipc_dump_start);
3274
3275int __tipc_dump_start(struct netlink_callback *cb, struct net *net)
3276{
3277 /* tipc_nl_name_table_dump() uses cb->args[0...3]. */
3278 struct rhashtable_iter *iter = (void *)cb->args[4];
3279 struct tipc_net *tn = tipc_net(net);
3280
3281 if (!iter) {
3282 iter = kmalloc(sizeof(*iter), GFP_KERNEL);
3283 if (!iter)
3284 return -ENOMEM;
3285
3286 cb->args[4] = (long)iter;
3287 }
3288
3289 rhashtable_walk_enter(&tn->sk_rht, iter);
3290 return 0;
3291}
3292
3293int tipc_dump_done(struct netlink_callback *cb)
3294{
3295 struct rhashtable_iter *hti = (void *)cb->args[4];
3296
3297 rhashtable_walk_exit(hti);
3298 kfree(hti);
3299 return 0;
3300}
3301EXPORT_SYMBOL(tipc_dump_done);
3302
3269int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct netlink_callback *cb, 3303int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct netlink_callback *cb,
3270 struct tipc_sock *tsk, u32 sk_filter_state, 3304 struct tipc_sock *tsk, u32 sk_filter_state,
3271 u64 (*tipc_diag_gen_cookie)(struct sock *sk)) 3305 u64 (*tipc_diag_gen_cookie)(struct sock *sk))