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:
parent
6d268910a4
commit
f7a2ba5ab9
|
@ -475,24 +475,31 @@ static int ila_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue