ila: Fix use of rhashtable walk in ila_xlat.c

Perform better EAGAIN handling, handle case where ila_dump_info
fails and we missed objects in the dump, and add a skip index
to skip over ila entires in a list on a rhashtable node that have
already been visited (by a previous call to ila_nl_dump).

Signed-off-by: Tom Herbert <tom@quantonium.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Tom Herbert 2018-06-27 14:38:59 -07:00 committed by David S. Miller
parent 6d268910a4
commit f7a2ba5ab9
1 changed files with 54 additions and 16 deletions

View File

@ -475,24 +475,31 @@ out_free:
struct ila_dump_iter {
struct rhashtable_iter rhiter;
int skip;
};
static int ila_nl_dump_start(struct netlink_callback *cb)
{
struct net *net = sock_net(cb->skb->sk);
struct ila_net *ilan = net_generic(net, ila_net_id);
struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0];
struct ila_dump_iter *iter;
int ret;
if (!iter) {
iter = kmalloc(sizeof(*iter), GFP_KERNEL);
if (!iter)
return -ENOMEM;
iter = kmalloc(sizeof(*iter), GFP_KERNEL);
if (!iter)
return -ENOMEM;
cb->args[0] = (long)iter;
ret = rhashtable_walk_init(&ilan->rhash_table, &iter->rhiter,
GFP_KERNEL);
if (ret) {
kfree(iter);
return ret;
}
return rhashtable_walk_init(&ilan->rhash_table, &iter->rhiter,
GFP_KERNEL);
iter->skip = 0;
cb->args[0] = (long)iter;
return ret;
}
static int ila_nl_dump_done(struct netlink_callback *cb)
@ -510,20 +517,45 @@ static int ila_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0];
struct rhashtable_iter *rhiter = &iter->rhiter;
int skip = iter->skip;
struct ila_map *ila;
int ret;
rhashtable_walk_start(rhiter);
for (;;) {
ila = rhashtable_walk_next(rhiter);
/* Get first entry */
ila = rhashtable_walk_peek(rhiter);
if (ila && !IS_ERR(ila) && skip) {
/* Skip over visited entries */
while (ila && skip) {
/* Skip over any ila entries in this list that we
* have already dumped.
*/
ila = rcu_access_pointer(ila->next);
skip--;
}
}
skip = 0;
for (;;) {
if (IS_ERR(ila)) {
if (PTR_ERR(ila) == -EAGAIN)
continue;
ret = PTR_ERR(ila);
goto done;
if (ret == -EAGAIN) {
/* Table has changed and iter has reset. Return
* -EAGAIN to the application even if we have
* written data to the skb. The application
* needs to deal with this.
*/
goto out_ret;
} else {
break;
}
} else if (!ila) {
ret = 0;
break;
}
@ -532,15 +564,21 @@ static int ila_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
cb->nlh->nlmsg_seq, NLM_F_MULTI,
skb, ILA_CMD_GET);
if (ret)
goto done;
goto out;
skip++;
ila = rcu_access_pointer(ila->next);
}
skip = 0;
ila = rhashtable_walk_next(rhiter);
}
ret = skb->len;
out:
iter->skip = skip;
ret = (skb->len ? : ret);
done:
out_ret:
rhashtable_walk_stop(rhiter);
return ret;
}