On Thu, Nov 21, 2024 at 10:04:15AM +0100, Sven Eckelmann wrote:
> On Wednesday, 20 November 2024 18:47:17 CET Remi Pommarel wrote:
> > The tt.local_changes atomic is either written with tt.changes_list_lock
> > or close to it (see batadv_tt_local_event()). Thus the performance gain
> > using an atomic was limited (or because of atomic_read() impact even
> > negative). Using atomic also comes with the need to be wary of potential
> > negative tt.local_changes value.
> >
> > Simplify the tt.local_changes usage by removing the atomic property and
> > modifying it only with tt.changes_list_lock held.
>
> The overall change assumes that the compiler never splits writes (store
> tearing) [1]. Of course, writes are protected against each other using locks.
> But the reader is no longer protected from partial writes. I haven't checked
> whether store fusing might be a problem.
>
> Kind regards,
> Sven
>
> [1]
> https://www.kernel.org/doc/html/latest/core-api/wrappers/memory-barriers.html
Good catch thanks.
>
> [...]
> > @@ -783,13 +783,13 @@ static int batadv_softif_init_late(struct net_device
> > *dev)
> > atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE);
> > atomic_set(&bat_priv->bcast_seqno, 1);
> > atomic_set(&bat_priv->tt.vn, 0);
> > - atomic_set(&bat_priv->tt.local_changes, 0);
> > atomic_set(&bat_priv->tt.ogm_append_cnt, 0);
> > #ifdef CONFIG_BATMAN_ADV_BLA
> > atomic_set(&bat_priv->bla.num_requests, 0);
> > #endif
> > atomic_set(&bat_priv->tp_num, 0);
> >
> > + bat_priv->tt.local_changes = 0;
>
> Would need WRITE_ONCE (just to be consistent)
>
> [...]
> > @@ -508,21 +507,17 @@ static void batadv_tt_local_event(struct batadv_priv
> > *bat_priv,
> > del:
> > list_del(&entry->list);
> > kmem_cache_free(batadv_tt_change_cache, entry);
> > + bat_priv->tt.local_changes--;
> > kmem_cache_free(batadv_tt_change_cache, tt_change_node);
> > - event_removed = true;
> > goto unlock;
> > }
> >
> > /* track the change in the OGMinterval list */
> > list_add_tail(&tt_change_node->list, &bat_priv->tt.changes_list);
> > + bat_priv->tt.local_changes++;
>
> Needs more complex constructs with WRITE_ONCE or
> __sync_add_and_fetch/__sync_sub_and_fetch (which were handled before inside
> atomic_inc). The latter are not used that often in the kernel, so I wouldn't
> want to introduce them in the batman-adv module.
What about using something in the line:
WRITE_ONCE(&bat_priv->tt.local_changes,
READ_ONCE(&bat_priv->tt.local_changes) + 1);
>
> > @@ -1022,7 +1017,7 @@ static void batadv_tt_tvlv_container_update(struct
> > batadv_priv *bat_priv)
> > tt_data->flags = BATADV_TT_OGM_DIFF;
> >
> > spin_lock_bh(&bat_priv->tt.changes_list_lock);
> > - atomic_set(&bat_priv->tt.local_changes, 0);
> > + bat_priv->tt.local_changes = 0;
> >
> > list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
> > list) {
>
> Would need WRITE_ONCE
>
> > @@ -1438,7 +1433,7 @@ static void batadv_tt_changes_list_free(struct
> > batadv_priv *bat_priv)
> > kmem_cache_free(batadv_tt_change_cache, entry);
> > }
> >
> > - atomic_set(&bat_priv->tt.local_changes, 0);
> > + bat_priv->tt.local_changes = 0;
> > spin_unlock_bh(&bat_priv->tt.changes_list_lock);
> > }
>
> Would need WRITE_ONCE
Yes.
Thanks for the review.
--
Remi