1
0
Fork 0

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>
hifive-unleashed-5.1
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 ila_dump_iter {
struct rhashtable_iter rhiter; struct rhashtable_iter rhiter;
int skip;
}; };
static int ila_nl_dump_start(struct netlink_callback *cb) static int ila_nl_dump_start(struct netlink_callback *cb)
{ {
struct net *net = sock_net(cb->skb->sk); struct net *net = sock_net(cb->skb->sk);
struct ila_net *ilan = net_generic(net, ila_net_id); 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);
iter = kmalloc(sizeof(*iter), GFP_KERNEL); if (!iter)
if (!iter) return -ENOMEM;
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, iter->skip = 0;
GFP_KERNEL); cb->args[0] = (long)iter;
return ret;
} }
static int ila_nl_dump_done(struct netlink_callback *cb) 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 ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0];
struct rhashtable_iter *rhiter = &iter->rhiter; struct rhashtable_iter *rhiter = &iter->rhiter;
int skip = iter->skip;
struct ila_map *ila; struct ila_map *ila;
int ret; int ret;
rhashtable_walk_start(rhiter); rhashtable_walk_start(rhiter);
for (;;) { /* Get first entry */
ila = rhashtable_walk_next(rhiter); 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 (IS_ERR(ila)) {
if (PTR_ERR(ila) == -EAGAIN)
continue;
ret = PTR_ERR(ila); 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) { } else if (!ila) {
ret = 0;
break; 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, cb->nlh->nlmsg_seq, NLM_F_MULTI,
skb, ILA_CMD_GET); skb, ILA_CMD_GET);
if (ret) if (ret)
goto done; goto out;
skip++;
ila = rcu_access_pointer(ila->next); 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); rhashtable_walk_stop(rhiter);
return ret; return ret;
} }