Skip to content

Commit f7a2ba5

Browse files
tomratbertdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6d26891 commit f7a2ba5

File tree

1 file changed

+54
-16
lines changed

1 file changed

+54
-16
lines changed

net/ipv6/ila/ila_xlat.c

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -475,24 +475,31 @@ static int ila_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info)
475475

476476
struct ila_dump_iter {
477477
struct rhashtable_iter rhiter;
478+
int skip;
478479
};
479480

480481
static int ila_nl_dump_start(struct netlink_callback *cb)
481482
{
482483
struct net *net = sock_net(cb->skb->sk);
483484
struct ila_net *ilan = net_generic(net, ila_net_id);
484-
struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0];
485+
struct ila_dump_iter *iter;
486+
int ret;
485487

486-
if (!iter) {
487-
iter = kmalloc(sizeof(*iter), GFP_KERNEL);
488-
if (!iter)
489-
return -ENOMEM;
488+
iter = kmalloc(sizeof(*iter), GFP_KERNEL);
489+
if (!iter)
490+
return -ENOMEM;
490491

491-
cb->args[0] = (long)iter;
492+
ret = rhashtable_walk_init(&ilan->rhash_table, &iter->rhiter,
493+
GFP_KERNEL);
494+
if (ret) {
495+
kfree(iter);
496+
return ret;
492497
}
493498

494-
return rhashtable_walk_init(&ilan->rhash_table, &iter->rhiter,
495-
GFP_KERNEL);
499+
iter->skip = 0;
500+
cb->args[0] = (long)iter;
501+
502+
return ret;
496503
}
497504

498505
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)
510517
{
511518
struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args[0];
512519
struct rhashtable_iter *rhiter = &iter->rhiter;
520+
int skip = iter->skip;
513521
struct ila_map *ila;
514522
int ret;
515523

516524
rhashtable_walk_start(rhiter);
517525

518-
for (;;) {
519-
ila = rhashtable_walk_next(rhiter);
526+
/* Get first entry */
527+
ila = rhashtable_walk_peek(rhiter);
528+
529+
if (ila && !IS_ERR(ila) && skip) {
530+
/* Skip over visited entries */
531+
532+
while (ila && skip) {
533+
/* Skip over any ila entries in this list that we
534+
* have already dumped.
535+
*/
536+
ila = rcu_access_pointer(ila->next);
537+
skip--;
538+
}
539+
}
520540

541+
skip = 0;
542+
543+
for (;;) {
521544
if (IS_ERR(ila)) {
522-
if (PTR_ERR(ila) == -EAGAIN)
523-
continue;
524545
ret = PTR_ERR(ila);
525-
goto done;
546+
if (ret == -EAGAIN) {
547+
/* Table has changed and iter has reset. Return
548+
* -EAGAIN to the application even if we have
549+
* written data to the skb. The application
550+
* needs to deal with this.
551+
*/
552+
553+
goto out_ret;
554+
} else {
555+
break;
556+
}
526557
} else if (!ila) {
558+
ret = 0;
527559
break;
528560
}
529561

@@ -532,15 +564,21 @@ static int ila_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
532564
cb->nlh->nlmsg_seq, NLM_F_MULTI,
533565
skb, ILA_CMD_GET);
534566
if (ret)
535-
goto done;
567+
goto out;
536568

569+
skip++;
537570
ila = rcu_access_pointer(ila->next);
538571
}
572+
573+
skip = 0;
574+
ila = rhashtable_walk_next(rhiter);
539575
}
540576

541-
ret = skb->len;
577+
out:
578+
iter->skip = skip;
579+
ret = (skb->len ? : ret);
542580

543-
done:
581+
out_ret:
544582
rhashtable_walk_stop(rhiter);
545583
return ret;
546584
}

0 commit comments

Comments
 (0)