diff options
author | Richard Alpe <richard.alpe@ericsson.com> | 2015-01-16 12:30:40 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-01-18 00:27:05 -0500 |
commit | d6e164e3215794f9920af69cd2c6794632773478 (patch) | |
tree | f6c3a913982d5f580191e5f0c31083e83ed39f6f /net/tipc | |
parent | e445dd5f6745922bf4d8c18e1f071b28c5a061bb (diff) | |
download | linux-d6e164e3215794f9920af69cd2c6794632773478.tar.bz2 |
tipc: fix socket list regression in new nl api
Commit 07f6c4bc (tipc: convert tipc reference table to use generic
rhashtable) introduced a problem with port listing in the new netlink
API. It broke the resume functionality resulting in a never ending
loop. This was caused by starting with the first hash table every time
subsequently never returning an empty skb (terminating).
This patch fixes the resume mechanism by keeping a logical reference
to the last hash table along with a logical reference to the socket
(port) that didn't fit in the previous message.
Signed-off-by: Richard Alpe <richard.alpe@ericsson.com>
Reviewed-by: Erik Hugne <erik.hugne@ericsson.com>
Reviewed-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/socket.c | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 720fda6cc2e6..679a22082fcb 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2749,29 +2749,35 @@ int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb) struct tipc_sock *tsk; const struct bucket_table *tbl; struct rhash_head *pos; - u32 prev_portid = cb->args[0]; - u32 portid = prev_portid; struct net *net = sock_net(skb->sk); struct tipc_net *tn = net_generic(net, tipc_net_id); - int i; + u32 tbl_id = cb->args[0]; + u32 prev_portid = cb->args[1]; rcu_read_lock(); tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht); - for (i = 0; i < tbl->size; i++) { - rht_for_each_entry_rcu(tsk, pos, tbl, i, node) { + for (; tbl_id < tbl->size; tbl_id++) { + rht_for_each_entry_rcu(tsk, pos, tbl, tbl_id, node) { spin_lock_bh(&tsk->sk.sk_lock.slock); - portid = tsk->portid; + if (prev_portid && prev_portid != tsk->portid) { + spin_unlock_bh(&tsk->sk.sk_lock.slock); + continue; + } + err = __tipc_nl_add_sk(skb, cb, tsk); + if (err) { + prev_portid = tsk->portid; + spin_unlock_bh(&tsk->sk.sk_lock.slock); + goto out; + } + prev_portid = 0; spin_unlock_bh(&tsk->sk.sk_lock.slock); - if (err) - break; - - prev_portid = portid; } } +out: rcu_read_unlock(); - - cb->args[0] = prev_portid; + cb->args[0] = tbl_id; + cb->args[1] = prev_portid; return skb->len; } |