diff options
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r-- | net/tipc/socket.c | 76 |
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); | ||
3262 | out: | 3261 | out: |
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 | } |
3269 | EXPORT_SYMBOL(tipc_nl_sk_walk); | 3264 | EXPORT_SYMBOL(tipc_nl_sk_walk); |
3270 | 3265 | ||
3266 | int 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 | } | ||
3283 | EXPORT_SYMBOL(tipc_dump_start); | ||
3284 | |||
3285 | int 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 | } | ||
3293 | EXPORT_SYMBOL(tipc_dump_done); | ||
3294 | |||
3271 | int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct netlink_callback *cb, | 3295 | int 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)) |