Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7a2ba5a authored by Tom Herbert's avatar Tom Herbert Committed by David S. Miller
Browse files

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: default avatarTom Herbert <tom@quantonium.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6d268910
Loading
Loading
Loading
Loading
+54 −16
Original line number Diff line number Diff line
@@ -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;

		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;
}