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.c76
1 files changed, 50 insertions, 26 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index c9a50b62c738..ab7a2a7178f7 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -3229,45 +3229,69 @@ int tipc_nl_sk_walk(struct sk_buff *skb, struct netlink_callback *cb,
3229 struct netlink_callback *cb, 3229 struct netlink_callback *cb,
3230 struct tipc_sock *tsk)) 3230 struct tipc_sock *tsk))
3231{ 3231{
3232 struct net *net = sock_net(skb->sk); 3232 struct rhashtable_iter *iter = (void *)cb->args[0];
3233 struct tipc_net *tn = tipc_net(net);
3234 const struct bucket_table *tbl;
3235 u32 prev_portid = cb->args[1];
3236 u32 tbl_id = cb->args[0];
3237 struct rhash_head *pos;
3238 struct tipc_sock *tsk; 3233 struct tipc_sock *tsk;
3239 int err; 3234 int err;
3240 3235
3241 rcu_read_lock(); 3236 rhashtable_walk_start(iter);
3242 tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht); 3237 while ((tsk = rhashtable_walk_next(iter)) != NULL) {
3243 for (; tbl_id < tbl->size; tbl_id++) { 3238 if (IS_ERR(tsk)) {
3244 rht_for_each_entry_rcu(tsk, pos, tbl, tbl_id, node) { 3239 err = PTR_ERR(tsk);
3245 spin_lock_bh(&tsk->sk.sk_lock.slock); 3240 if (err == -EAGAIN) {
3246 if (prev_portid && prev_portid != tsk->portid) { 3241 err = 0;
3247 spin_unlock_bh(&tsk->sk.sk_lock.slock);
3248 continue; 3242 continue;
3249 } 3243 }
3244 break;
3245 }
3250 3246
3251 err = skb_handler(skb, cb, tsk); 3247 sock_hold(&tsk->sk);
3252 if (err) { 3248 rhashtable_walk_stop(iter);
3253 prev_portid = tsk->portid; 3249 lock_sock(&tsk->sk);
3254 spin_unlock_bh(&tsk->sk.sk_lock.slock); 3250 err = skb_handler(skb, cb, tsk);
3255 goto out; 3251 if (err) {
3256 } 3252 release_sock(&tsk->sk);
3257 3253 sock_put(&tsk->sk);
3258 prev_portid = 0; 3254 goto out;
3259 spin_unlock_bh(&tsk->sk.sk_lock.slock);
3260 } 3255 }
3256 release_sock(&tsk->sk);
3257 rhashtable_walk_start(iter);
3258 sock_put(&tsk->sk);
3261 } 3259 }
3260 rhashtable_walk_stop(iter);
3262out: 3261out:
3263 rcu_read_unlock();
3264 cb->args[0] = tbl_id;
3265 cb->args[1] = prev_portid;
3266
3267 return skb->len; 3262 return skb->len;
3268} 3263}
3269EXPORT_SYMBOL(tipc_nl_sk_walk); 3264EXPORT_SYMBOL(tipc_nl_sk_walk);
3270 3265
3266int tipc_dump_start(struct netlink_callback *cb)
3267{
3268 struct rhashtable_iter *iter = (void *)cb->args[0];
3269 struct net *net = sock_net(cb->skb->sk);
3270 struct tipc_net *tn = tipc_net(net);
3271
3272 if (!iter) {
3273 iter = kmalloc(sizeof(*iter), GFP_KERNEL);
3274 if (!iter)
3275 return -ENOMEM;
3276
3277 cb->args[0] = (long)iter;
3278 }
3279
3280 rhashtable_walk_enter(&tn->sk_rht, iter);
3281 return 0;
3282}
3283EXPORT_SYMBOL(tipc_dump_start);
3284
3285int tipc_dump_done(struct netlink_callback *cb)
3286{
3287 struct rhashtable_iter *hti = (void *)cb->args[0];
3288
3289 rhashtable_walk_exit(hti);
3290 kfree(hti);
3291 return 0;
3292}
3293EXPORT_SYMBOL(tipc_dump_done);
3294
3271int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct netlink_callback *cb, 3295int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct netlink_callback *cb,
3272 struct tipc_sock *tsk, u32 sk_filter_state, 3296 struct tipc_sock *tsk, u32 sk_filter_state,
3273 u64 (*tipc_diag_gen_cookie)(struct sock *sk)) 3297 u64 (*tipc_diag_gen_cookie)(struct sock *sk))