Commit f8ba22a1 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'remove-qdisc-running-counter'

Sebastian Andrzej Siewior says:

====================
Try to simplify the gnet_stats and remove qdisc->running sequence counter.

The first few patches is a follow up to
    https://lore.kernel.org/all/20211007175000.2334713-1-bigeasy@linutronix.de/



The remaining patches (#5+) remove the seqcount_t (Qdisc::running) from
the Qdisc. The statistics (Qdisc::bstats and Qdisc::cpu_bstats) use
u64_stats_t and the "running state" is now represented by a bit in
Qdisc::state.

By removing the seqcount_t from Qdisc and decoupling the bstats
statistics from the seqcount_t it is possible to query the statistics
even if the Qdisc is running instead of waiting until it is idle again.

The try-lock like usage of the seqcount_t in qdisc_run_begin() is
problematic on PREEMPT_RT. Inside the qdisc_run_begin/end() qdisc->running
sequence counter write sections, at sch_direct_xmit(), the seqcount write
serialization lock is released then re-acquired. This is fine for !RT, because
the writer is in a BH disabled region and there is a no in-IRQ reader. For RT
though, BH sections are preemptible. The earlier introduced seqcount_LOCKNAME_t
mechanism, which for RT the reader acquires then relesaes the write
serailization lock to avoid infinite spinning if it preempts a seqcount write
section, cannot work: the qdisc->running write serialization lock is already
intermittingly released inside the seqcount write section.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 254ec036 29cbcd85
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -458,7 +458,7 @@ nfp_abm_qdisc_graft(struct nfp_abm_link *alink, u32 handle, u32 child_handle,
static void
nfp_abm_stats_calculate(struct nfp_alink_stats *new,
			struct nfp_alink_stats *old,
			struct gnet_stats_basic_packed *bstats,
			struct gnet_stats_basic_sync *bstats,
			struct gnet_stats_queue *qstats)
{
	_bstats_update(bstats, new->tx_bytes - old->tx_bytes,
+0 −4
Original line number Diff line number Diff line
@@ -1916,7 +1916,6 @@ enum netdev_ml_priv_type {
 *	@sfp_bus:	attached &struct sfp_bus structure.
 *
 *	@qdisc_tx_busylock: lockdep class annotating Qdisc->busylock spinlock
 *	@qdisc_running_key: lockdep class annotating Qdisc->running seqcount
 *
 *	@proto_down:	protocol port state information can be sent to the
 *			switch driver and used to set the phys state of the
@@ -2250,7 +2249,6 @@ struct net_device {
	struct phy_device	*phydev;
	struct sfp_bus		*sfp_bus;
	struct lock_class_key	*qdisc_tx_busylock;
	struct lock_class_key	*qdisc_running_key;
	bool			proto_down;
	unsigned		wol_enabled:1;
	unsigned		threaded:1;
@@ -2360,13 +2358,11 @@ static inline void netdev_for_each_tx_queue(struct net_device *dev,
#define netdev_lockdep_set_classes(dev)				\
{								\
	static struct lock_class_key qdisc_tx_busylock_key;	\
	static struct lock_class_key qdisc_running_key;		\
	static struct lock_class_key qdisc_xmit_lock_key;	\
	static struct lock_class_key dev_addr_list_lock_key;	\
	unsigned int i;						\
								\
	(dev)->qdisc_tx_busylock = &qdisc_tx_busylock_key;	\
	(dev)->qdisc_running_key = &qdisc_running_key;		\
	lockdep_set_class(&(dev)->addr_list_lock,		\
			  &dev_addr_list_lock_key);		\
	for (i = 0; i < (dev)->num_tx_queues; i++)		\
+10 −0
Original line number Diff line number Diff line
@@ -83,6 +83,11 @@ static inline u64 u64_stats_read(const u64_stats_t *p)
	return local64_read(&p->v);
}

static inline void u64_stats_set(u64_stats_t *p, u64 val)
{
	local64_set(&p->v, val);
}

static inline void u64_stats_add(u64_stats_t *p, unsigned long val)
{
	local64_add(val, &p->v);
@@ -104,6 +109,11 @@ static inline u64 u64_stats_read(const u64_stats_t *p)
	return p->v;
}

static inline void u64_stats_set(u64_stats_t *p, u64 val)
{
	p->v = val;
}

static inline void u64_stats_add(u64_stats_t *p, unsigned long val)
{
	p->v += val;
+5 −5
Original line number Diff line number Diff line
@@ -30,13 +30,13 @@ struct tc_action {
	atomic_t			tcfa_bindcnt;
	int				tcfa_action;
	struct tcf_t			tcfa_tm;
	struct gnet_stats_basic_packed	tcfa_bstats;
	struct gnet_stats_basic_packed	tcfa_bstats_hw;
	struct gnet_stats_basic_sync	tcfa_bstats;
	struct gnet_stats_basic_sync	tcfa_bstats_hw;
	struct gnet_stats_queue		tcfa_qstats;
	struct net_rate_estimator __rcu *tcfa_rate_est;
	spinlock_t			tcfa_lock;
	struct gnet_stats_basic_cpu __percpu *cpu_bstats;
	struct gnet_stats_basic_cpu __percpu *cpu_bstats_hw;
	struct gnet_stats_basic_sync __percpu *cpu_bstats;
	struct gnet_stats_basic_sync __percpu *cpu_bstats_hw;
	struct gnet_stats_queue __percpu *cpu_qstats;
	struct tc_cookie	__rcu *act_cookie;
	struct tcf_chain	__rcu *goto_chain;
@@ -206,7 +206,7 @@ static inline void tcf_action_update_bstats(struct tc_action *a,
					    struct sk_buff *skb)
{
	if (likely(a->cpu_bstats)) {
		bstats_cpu_update(this_cpu_ptr(a->cpu_bstats), skb);
		bstats_update(this_cpu_ptr(a->cpu_bstats), skb);
		return;
	}
	spin_lock(&a->tcfa_lock);
+30 −29
Original line number Diff line number Diff line
@@ -7,14 +7,17 @@
#include <linux/rtnetlink.h>
#include <linux/pkt_sched.h>

/* Note: this used to be in include/uapi/linux/gen_stats.h */
struct gnet_stats_basic_packed {
	__u64	bytes;
	__u64	packets;
};

struct gnet_stats_basic_cpu {
	struct gnet_stats_basic_packed bstats;
/* Throughput stats.
 * Must be initialized beforehand with gnet_stats_basic_sync_init().
 *
 * If no reads can ever occur parallel to writes (e.g. stack-allocated
 * bstats), then the internal stat values can be written to and read
 * from directly. Otherwise, use _bstats_set/update() for writes and
 * gnet_stats_add_basic() for reads.
 */
struct gnet_stats_basic_sync {
	u64_stats_t bytes;
	u64_stats_t packets;
	struct u64_stats_sync syncp;
} __aligned(2 * sizeof(u64));

@@ -34,6 +37,7 @@ struct gnet_dump {
	struct tc_stats   tc_stats;
};

void gnet_stats_basic_sync_init(struct gnet_stats_basic_sync *b);
int gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock,
			  struct gnet_dump *d, int padattr);

@@ -42,41 +46,38 @@ int gnet_stats_start_copy_compat(struct sk_buff *skb, int type,
				 spinlock_t *lock, struct gnet_dump *d,
				 int padattr);

int gnet_stats_copy_basic(const seqcount_t *running,
			  struct gnet_dump *d,
			  struct gnet_stats_basic_cpu __percpu *cpu,
			  struct gnet_stats_basic_packed *b);
void __gnet_stats_copy_basic(const seqcount_t *running,
			     struct gnet_stats_basic_packed *bstats,
			     struct gnet_stats_basic_cpu __percpu *cpu,
			     struct gnet_stats_basic_packed *b);
int gnet_stats_copy_basic_hw(const seqcount_t *running,
			     struct gnet_dump *d,
			     struct gnet_stats_basic_cpu __percpu *cpu,
			     struct gnet_stats_basic_packed *b);
int gnet_stats_copy_basic(struct gnet_dump *d,
			  struct gnet_stats_basic_sync __percpu *cpu,
			  struct gnet_stats_basic_sync *b, bool running);
void gnet_stats_add_basic(struct gnet_stats_basic_sync *bstats,
			  struct gnet_stats_basic_sync __percpu *cpu,
			  struct gnet_stats_basic_sync *b, bool running);
int gnet_stats_copy_basic_hw(struct gnet_dump *d,
			     struct gnet_stats_basic_sync __percpu *cpu,
			     struct gnet_stats_basic_sync *b, bool running);
int gnet_stats_copy_rate_est(struct gnet_dump *d,
			     struct net_rate_estimator __rcu **ptr);
int gnet_stats_copy_queue(struct gnet_dump *d,
			  struct gnet_stats_queue __percpu *cpu_q,
			  struct gnet_stats_queue *q, __u32 qlen);
void __gnet_stats_copy_queue(struct gnet_stats_queue *qstats,
void gnet_stats_add_queue(struct gnet_stats_queue *qstats,
			  const struct gnet_stats_queue __percpu *cpu_q,
			     const struct gnet_stats_queue *q, __u32 qlen);
			  const struct gnet_stats_queue *q);
int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len);

int gnet_stats_finish_copy(struct gnet_dump *d);

int gen_new_estimator(struct gnet_stats_basic_packed *bstats,
		      struct gnet_stats_basic_cpu __percpu *cpu_bstats,
int gen_new_estimator(struct gnet_stats_basic_sync *bstats,
		      struct gnet_stats_basic_sync __percpu *cpu_bstats,
		      struct net_rate_estimator __rcu **rate_est,
		      spinlock_t *lock,
		      seqcount_t *running, struct nlattr *opt);
		      bool running, struct nlattr *opt);
void gen_kill_estimator(struct net_rate_estimator __rcu **ptr);
int gen_replace_estimator(struct gnet_stats_basic_packed *bstats,
			  struct gnet_stats_basic_cpu __percpu *cpu_bstats,
int gen_replace_estimator(struct gnet_stats_basic_sync *bstats,
			  struct gnet_stats_basic_sync __percpu *cpu_bstats,
			  struct net_rate_estimator __rcu **ptr,
			  spinlock_t *lock,
			  seqcount_t *running, struct nlattr *opt);
			  bool running, struct nlattr *opt);
bool gen_estimator_active(struct net_rate_estimator __rcu **ptr);
bool gen_estimator_read(struct net_rate_estimator __rcu **ptr,
			struct gnet_stats_rate_est64 *sample);
Loading