mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-08 15:04:45 +00:00
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>
This commit is contained in:
parent
e445dd5f67
commit
d6e164e321
@ -2749,29 +2749,35 @@ int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|||||||
struct tipc_sock *tsk;
|
struct tipc_sock *tsk;
|
||||||
const struct bucket_table *tbl;
|
const struct bucket_table *tbl;
|
||||||
struct rhash_head *pos;
|
struct rhash_head *pos;
|
||||||
u32 prev_portid = cb->args[0];
|
|
||||||
u32 portid = prev_portid;
|
|
||||||
struct net *net = sock_net(skb->sk);
|
struct net *net = sock_net(skb->sk);
|
||||||
struct tipc_net *tn = net_generic(net, tipc_net_id);
|
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();
|
rcu_read_lock();
|
||||||
tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht);
|
tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht);
|
||||||
for (i = 0; i < tbl->size; i++) {
|
for (; tbl_id < tbl->size; tbl_id++) {
|
||||||
rht_for_each_entry_rcu(tsk, pos, tbl, i, node) {
|
rht_for_each_entry_rcu(tsk, pos, tbl, tbl_id, node) {
|
||||||
spin_lock_bh(&tsk->sk.sk_lock.slock);
|
spin_lock_bh(&tsk->sk.sk_lock.slock);
|
||||||
portid = tsk->portid;
|
if (prev_portid && prev_portid != tsk->portid) {
|
||||||
err = __tipc_nl_add_sk(skb, cb, tsk);
|
spin_unlock_bh(&tsk->sk.sk_lock.slock);
|
||||||
spin_unlock_bh(&tsk->sk.sk_lock.slock);
|
continue;
|
||||||
if (err)
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
prev_portid = portid;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
cb->args[0] = tbl_id;
|
||||||
cb->args[0] = prev_portid;
|
cb->args[1] = prev_portid;
|
||||||
|
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user