Skip to content

Commit

Permalink
u64_stats: provide u64_stats_t type
Browse files Browse the repository at this point in the history
On 64bit arches, struct u64_stats_sync is empty and provides
no help against load/store tearing.

Using READ_ONCE()/WRITE_ONCE() would be needed.

But the update side would be slightly more expensive.

local64_t was defined so that we could use regular adds
in a manner which is atomic wrt IRQs.

However the u64_stats infra means we do not have to use
local64_t on 32bit arches since the syncp provides the needed
protection.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Eric Dumazet authored and davem330 committed Nov 8, 2019
1 parent 4a43b1f commit 316580b
Showing 1 changed file with 47 additions and 4 deletions.
51 changes: 47 additions & 4 deletions include/linux/u64_stats_sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
* spin_lock_bh(...) or other synchronization to get exclusive access
* ...
* u64_stats_update_begin(&stats->syncp);
* stats->bytes64 += len; // non atomic operation
* stats->packets64++; // non atomic operation
* u64_stats_add(&stats->bytes64, len); // non atomic operation
* u64_stats_inc(&stats->packets64); // non atomic operation
* u64_stats_update_end(&stats->syncp);
*
* While a consumer (reader) should use following template to get consistent
Expand All @@ -52,8 +52,8 @@
*
* do {
* start = u64_stats_fetch_begin(&stats->syncp);
* tbytes = stats->bytes64; // non atomic operation
* tpackets = stats->packets64; // non atomic operation
* tbytes = u64_stats_read(&stats->bytes64); // non atomic operation
* tpackets = u64_stats_read(&stats->packets64); // non atomic operation
* } while (u64_stats_fetch_retry(&stats->syncp, start));
*
*
Expand All @@ -68,6 +68,49 @@ struct u64_stats_sync {
#endif
};

#if BITS_PER_LONG == 64
#include <asm/local64.h>

typedef struct {
local64_t v;
} u64_stats_t ;

static inline u64 u64_stats_read(const u64_stats_t *p)
{
return local64_read(&p->v);
}

static inline void u64_stats_add(u64_stats_t *p, unsigned long val)
{
local64_add(val, &p->v);
}

static inline void u64_stats_inc(u64_stats_t *p)
{
local64_inc(&p->v);
}

#else

typedef struct {
u64 v;
} u64_stats_t;

static inline u64 u64_stats_read(const u64_stats_t *p)
{
return p->v;
}

static inline void u64_stats_add(u64_stats_t *p, unsigned long val)
{
p->v += val;
}

static inline void u64_stats_inc(u64_stats_t *p)
{
p->v++;
}
#endif

static inline void u64_stats_init(struct u64_stats_sync *syncp)
{
Expand Down

0 comments on commit 316580b

Please sign in to comment.