Re: [PATCH net-next 1/4] u64_stats: Introduce u64_stats_copy()
Yangfl <[email protected]>
| Newsgroups | gmane.linux.network.bridge,gmane.linux.network,gmane.linux.kernel |
|---|---|
| Message-ID | <CAAXyoMMAMAbEu=-wTf3MGMiZr2Uq7pqJXC+_zrtxKrsjyYi+AQ@mail.gmail.com> |
On Thu, Jan 22, 2026 at 1:23 AM Sabrina Dubroca <[email protected]> wrote: > > 2026-01-20, 17:21:29 +0800, David Yang wrote: > > The following (anti-)pattern was observed in the code tree: > > > > do { > > start = u64_stats_fetch_begin(&pstats->syncp); > > memcpy(&temp, &pstats->stats, sizeof(temp)); > > } while (u64_stats_fetch_retry(&pstats->syncp, start)); > > > > On 64bit arches, struct u64_stats_sync is empty and provides no help > > against load/store tearing, especially for memcpy(), for which arches may > > provide their highly-optimized implements. > > > > In theory the affected code should convert to u64_stats_t, or use > > READ_ONCE()/WRITE_ONCE() properly. > > > > However since there are needs to copy chunks of statistics, instead of > > writing loops at random places, we provide a safe memcpy() variant for > > u64_stats. > > > > Signed-off-by: David Yang <[email protected]> > > --- > > include/linux/u64_stats_sync.h | 15 +++++++++++++++ > > 1 file changed, 15 insertions(+) > > > > diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h > > index 457879938fc1..849ff6e159c6 100644 > > --- a/include/linux/u64_stats_sync.h > > +++ b/include/linux/u64_stats_sync.h > > @@ -79,6 +79,14 @@ static inline u64 u64_stats_read(const u64_stats_t *p) > > return local64_read(&p->v); > > } > > > > +static inline void *u64_stats_copy(void *dst, const void *src, size_t len) > > +{ > > + BUILD_BUG_ON(len % sizeof(u64_stats_t)); > > + for (size_t i = 0; i < len / sizeof(u64_stats_t); i++) > > + ((u64 *)dst)[i] = local64_read(&((local64_t *)src)[i]); > > Maybe u64_stats_read/u64_stats_t instead of local64_read/local64_t? > I think casting to u64_stats_t is a bit overkill here since we accept const void * and we are the actual implementation. Again, they should convert to u64_stats_t, and this solution already implies that u64_stats_t is binary compatible with u64. I've already sent several patches related to that, but that's another issue. > > + return dst; > > +} > > Since this new helper is always used within a > u64_stats_fetch_begin/u64_stats_fetch_retry loop, maybe it would be > nicer to push the retry loop into the helper as well? Not a strong > opinion. It would be a bit "simpler" for the callers, but your current > proposal has the advantage of looking like memcpy(), and of also > looking (for the caller) like other retry loops fetching each counter > explicitly. > The callers may want to copy other discontinuous data as well, albeit no one did it then. do { start = u64_stats_fetch_begin(&pstats->syncp); memcpy(...); u64_stats_read(...); } while (u64_stats_fetch_retry(&pstats->syncp, start)); It would be redundant to provide two variants of the function. Moreover, callers can (and already) invent their own reader/writer helpers, for example #define SLIC_GET_STATS_COUNTER(newst, st, counter) \ { \ unsigned int start; \ do { \ start = u64_stats_fetch_begin(&(st)->syncp); \ newst = u64_stats_read(&(st)->counter); \ } while (u64_stats_fetch_retry(&(st)->syncp, start)); \ } > Either way, I think extending the "Usage" section of the big comment > at the top of the file with this new helper would be nice. > I think callers should avoid memcpy() eventually, and they almost certainly copied more data than what they need. However, I took a look at some instances, and it would be non trivial to modify those drivers. > -- > Sabrina