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

Commit d657e621 authored by Antonio Quartulli's avatar Antonio Quartulli
Browse files

batman-adv: add reference counting for type batadv_tt_orig_list_entry



The batadv_tt_orig_list_entry structure didn't have any refcounting mechanism so
far. This patch introduces it and makes the structure being usable in much more
complex context.

Signed-off-by: default avatarAntonio Quartulli <ordex@autistici.org>
parent 3a7f291b
Loading
Loading
Loading
Loading
+52 −23
Original line number Diff line number Diff line
@@ -152,6 +152,8 @@ static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
static void
batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry)
{
	if (!atomic_dec_and_test(&orig_entry->refcount))
		return;
	/* to avoid race conditions, immediately decrease the tt counter */
	atomic_dec(&orig_entry->orig_node->tt_size);
	call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
@@ -625,50 +627,82 @@ static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv)
	spin_unlock_bh(&bat_priv->tt_changes_list_lock);
}

/* find out if an orig_node is already in the list of a tt_global_entry.
 * returns 1 if found, 0 otherwise
/* retrieves the orig_tt_list_entry belonging to orig_node from the
 * batadv_tt_global_entry list
 *
 * returns it with an increased refcounter, NULL if not found
 */
static bool
batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
static struct batadv_tt_orig_list_entry *
batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
				 const struct batadv_orig_node *orig_node)
{
	struct batadv_tt_orig_list_entry *tmp_orig_entry;
	struct batadv_tt_orig_list_entry *tmp_orig_entry, *orig_entry = NULL;
	const struct hlist_head *head;
	struct hlist_node *node;
	bool found = false;

	rcu_read_lock();
	head = &entry->orig_list;
	hlist_for_each_entry_rcu(tmp_orig_entry, node, head, list) {
		if (tmp_orig_entry->orig_node == orig_node) {
			found = true;
		if (tmp_orig_entry->orig_node != orig_node)
			continue;
		if (!atomic_inc_not_zero(&tmp_orig_entry->refcount))
			continue;

		orig_entry = tmp_orig_entry;
		break;
	}
	}
	rcu_read_unlock();

	return orig_entry;
}

/* find out if an orig_node is already in the list of a tt_global_entry.
 * returns true if found, false otherwise
 */
static bool
batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
				const struct batadv_orig_node *orig_node)
{
	struct batadv_tt_orig_list_entry *orig_entry;
	bool found = false;

	orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node);
	if (orig_entry) {
		found = true;
		batadv_tt_orig_list_entry_free_ref(orig_entry);
	}

	return found;
}

static void
batadv_tt_global_add_orig_entry(struct batadv_tt_global_entry *tt_global_entry,
batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
				struct batadv_orig_node *orig_node, int ttvn)
{
	struct batadv_tt_orig_list_entry *orig_entry;

	orig_entry = batadv_tt_global_orig_entry_find(tt_global, orig_node);
	if (orig_entry)
		goto out;

	orig_entry = kzalloc(sizeof(*orig_entry), GFP_ATOMIC);
	if (!orig_entry)
		return;
		goto out;

	INIT_HLIST_NODE(&orig_entry->list);
	atomic_inc(&orig_node->refcount);
	atomic_inc(&orig_node->tt_size);
	orig_entry->orig_node = orig_node;
	orig_entry->ttvn = ttvn;
	atomic_set(&orig_entry->refcount, 2);

	spin_lock_bh(&tt_global_entry->list_lock);
	spin_lock_bh(&tt_global->list_lock);
	hlist_add_head_rcu(&orig_entry->list,
			   &tt_global_entry->orig_list);
	spin_unlock_bh(&tt_global_entry->list_lock);
			   &tt_global->orig_list);
	spin_unlock_bh(&tt_global->list_lock);
out:
	if (orig_entry)
		batadv_tt_orig_list_entry_free_ref(orig_entry);
}

/* caller must hold orig_node refcount */
@@ -709,9 +743,6 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
			batadv_tt_global_entry_free_ref(tt_global_entry);
			goto out_remove;
		}

		batadv_tt_global_add_orig_entry(tt_global_entry, orig_node,
						ttvn);
	} else {
		/* there is already a global entry, use this one. */

@@ -728,11 +759,9 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
			tt_global_entry->roam_at = 0;
		}

		if (!batadv_tt_global_entry_has_orig(tt_global_entry,
						     orig_node))
			batadv_tt_global_add_orig_entry(tt_global_entry,
							orig_node, ttvn);
	}
	/* add the new orig_entry (if needed) */
	batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn);

	batadv_dbg(BATADV_DBG_TT, bat_priv,
		   "Creating new global tt entry: %pM (via %pM)\n",
+1 −0
Original line number Diff line number Diff line
@@ -282,6 +282,7 @@ struct batadv_tt_global_entry {
struct batadv_tt_orig_list_entry {
	struct batadv_orig_node *orig_node;
	uint8_t ttvn;
	atomic_t refcount;
	struct rcu_head rcu;
	struct hlist_node list;
};