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

Commit b0ab6f92 authored by John Fastabend's avatar John Fastabend Committed by David S. Miller
Browse files

net: sched: enable per cpu qstats



After previous patches to simplify qstats the qstats can be
made per cpu with a packed union in Qdisc struct.

Signed-off-by: default avatarJohn Fastabend <john.r.fastabend@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 64015853
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -41,7 +41,8 @@ int gnet_stats_copy_rate_est(struct gnet_dump *d,
			     const struct gnet_stats_basic_packed *b,
			     struct gnet_stats_rate_est64 *r);
int gnet_stats_copy_queue(struct gnet_dump *d,
			  struct gnet_stats_queue *q, __u32 len);
			  struct gnet_stats_queue __percpu *cpu_q,
			  struct gnet_stats_queue *q, __u32 qlen);
int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len);

int gnet_stats_finish_copy(struct gnet_dump *d);
+11 −1
Original line number Diff line number Diff line
@@ -90,7 +90,10 @@ struct Qdisc {
		struct gnet_stats_basic_cpu __percpu *cpu_bstats;
	} __packed;
	unsigned int		__state;
	union {
		struct gnet_stats_queue	qstats;
		struct gnet_stats_queue	__percpu *cpu_qstats;
	} __packed;
	struct rcu_head		rcu_head;
	int			padded;
	atomic_t		refcnt;
@@ -543,6 +546,13 @@ static inline void qdisc_qstats_drop(struct Qdisc *sch)
	sch->qstats.drops++;
}

static inline void qdisc_qstats_drop_cpu(struct Qdisc *sch)
{
	struct gnet_stats_queue *qstats = this_cpu_ptr(sch->cpu_qstats);

	qstats->drops++;
}

static inline void qdisc_qstats_overlimit(struct Qdisc *sch)
{
	sch->qstats.overlimits++;
+48 −7
Original line number Diff line number Diff line
@@ -215,33 +215,74 @@ gnet_stats_copy_rate_est(struct gnet_dump *d,
}
EXPORT_SYMBOL(gnet_stats_copy_rate_est);

static void
__gnet_stats_copy_queue_cpu(struct gnet_stats_queue *qstats,
			    const struct gnet_stats_queue __percpu *q)
{
	int i;

	for_each_possible_cpu(i) {
		const struct gnet_stats_queue *qcpu = per_cpu_ptr(q, i);

		qstats->qlen = 0;
		qstats->backlog += qcpu->backlog;
		qstats->drops += qcpu->drops;
		qstats->requeues += qcpu->requeues;
		qstats->overlimits += qcpu->overlimits;
	}
}

static void __gnet_stats_copy_queue(struct gnet_stats_queue *qstats,
				    const struct gnet_stats_queue __percpu *cpu,
				    const struct gnet_stats_queue *q,
				    __u32 qlen)
{
	if (cpu) {
		__gnet_stats_copy_queue_cpu(qstats, cpu);
	} else {
		qstats->qlen = q->qlen;
		qstats->backlog = q->backlog;
		qstats->drops = q->drops;
		qstats->requeues = q->requeues;
		qstats->overlimits = q->overlimits;
	}

	qstats->qlen = qlen;
}

/**
 * gnet_stats_copy_queue - copy queue statistics into statistics TLV
 * @d: dumping handle
 * @cpu_q: per cpu queue statistics
 * @q: queue statistics
 * @qlen: queue length statistics
 *
 * Appends the queue statistics to the top level TLV created by
 * gnet_stats_start_copy().
 * gnet_stats_start_copy(). Using per cpu queue statistics if
 * they are available.
 *
 * Returns 0 on success or -1 with the statistic lock released
 * if the room in the socket buffer was not sufficient.
 */
int
gnet_stats_copy_queue(struct gnet_dump *d,
		      struct gnet_stats_queue __percpu *cpu_q,
		      struct gnet_stats_queue *q, __u32 qlen)
{
	q->qlen = qlen;
	struct gnet_stats_queue qstats = {0};

	__gnet_stats_copy_queue(&qstats, cpu_q, q, qlen);

	if (d->compat_tc_stats) {
		d->tc_stats.drops = q->drops;
		d->tc_stats.qlen = q->qlen;
		d->tc_stats.backlog = q->backlog;
		d->tc_stats.overlimits = q->overlimits;
		d->tc_stats.drops = qstats.drops;
		d->tc_stats.qlen = qstats.qlen;
		d->tc_stats.backlog = qstats.backlog;
		d->tc_stats.overlimits = qstats.overlimits;
	}

	if (d->tail)
		return gnet_stats_copy(d, TCA_STATS_QUEUE, q, sizeof(*q));
		return gnet_stats_copy(d, TCA_STATS_QUEUE,
				       &qstats, sizeof(qstats));

	return 0;
}
+1 −1
Original line number Diff line number Diff line
@@ -623,7 +623,7 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
	if (gnet_stats_copy_basic(&d, NULL, &p->tcfc_bstats) < 0 ||
	    gnet_stats_copy_rate_est(&d, &p->tcfc_bstats,
				     &p->tcfc_rate_est) < 0 ||
	    gnet_stats_copy_queue(&d,
	    gnet_stats_copy_queue(&d, NULL,
				  &p->tcfc_qstats,
				  p->tcfc_qstats.qlen) < 0)
		goto errout;
+10 −2
Original line number Diff line number Diff line
@@ -947,6 +947,10 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
				alloc_percpu(struct gnet_stats_basic_cpu);
			if (!sch->cpu_bstats)
				goto err_out4;

			sch->cpu_qstats = alloc_percpu(struct gnet_stats_queue);
			if (!sch->cpu_qstats)
				goto err_out4;
		}

		if (tca[TCA_STAB]) {
@@ -995,6 +999,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,

err_out4:
	free_percpu(sch->cpu_bstats);
	free_percpu(sch->cpu_qstats);
	/*
	 * Any broken qdiscs that would require a ops->reset() here?
	 * The qdisc was never in action so it shouldn't be necessary.
@@ -1313,6 +1318,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
			 u32 portid, u32 seq, u16 flags, int event)
{
	struct gnet_stats_basic_cpu __percpu *cpu_bstats = NULL;
	struct gnet_stats_queue __percpu *cpu_qstats = NULL;
	struct tcmsg *tcm;
	struct nlmsghdr  *nlh;
	unsigned char *b = skb_tail_pointer(skb);
@@ -1349,12 +1355,14 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
	if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0)
		goto nla_put_failure;

	if (qdisc_is_percpu_stats(q))
	if (qdisc_is_percpu_stats(q)) {
		cpu_bstats = q->cpu_bstats;
		cpu_qstats = q->cpu_qstats;
	}

	if (gnet_stats_copy_basic(&d, cpu_bstats, &q->bstats) < 0 ||
	    gnet_stats_copy_rate_est(&d, &q->bstats, &q->rate_est) < 0 ||
	    gnet_stats_copy_queue(&d, &q->qstats, qlen) < 0)
	    gnet_stats_copy_queue(&d, cpu_qstats, &q->qstats, qlen) < 0)
		goto nla_put_failure;

	if (gnet_stats_finish_copy(&d) < 0)
Loading