Commit c3194a67 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'small-tc-taprio-improvements'

Vladimir Oltean says:

====================
Small tc-taprio improvements

This series contains:
- the proper protected variant of rcu_dereference() of admin and oper
  schedules for accesses from the slow path
- a removal of an extra function pointer indirection for
  qdisc->dequeue() and qdisc->peek()
- a removal of WARN_ON_ONCE() checks that can never trigger
- the addition of netlink extack messages to some qdisc->init() failures

These were split from an earlier patch set, hence the v2.
====================

Link: https://lore.kernel.org/r/20220915105046.2404072-1-vladimir.oltean@nxp.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 4d3c8848 2c08a4f8
......@@ -78,8 +78,6 @@ struct taprio_sched {
struct sched_gate_list __rcu *admin_sched;
struct hrtimer advance_timer;
struct list_head taprio_list;
struct sk_buff *(*dequeue)(struct Qdisc *sch);
struct sk_buff *(*peek)(struct Qdisc *sch);
u32 txtime_delay;
};
......@@ -434,6 +432,9 @@ static int taprio_enqueue_one(struct sk_buff *skb, struct Qdisc *sch,
return qdisc_enqueue(skb, child, to_free);
}
/* Will not be called in the full offload case, since the TX queues are
* attached to the Qdisc created using qdisc_create_dflt()
*/
static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch,
struct sk_buff **to_free)
{
......@@ -441,11 +442,6 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch,
struct Qdisc *child;
int queue;
if (unlikely(FULL_OFFLOAD_IS_ENABLED(q->flags))) {
WARN_ONCE(1, "Trying to enqueue skb into the root of a taprio qdisc configured with full offload\n");
return qdisc_drop(skb, sch, to_free);
}
queue = skb_get_queue_mapping(skb);
child = q->qdiscs[queue];
......@@ -454,10 +450,10 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch,
/* Large packets might not be transmitted when the transmission duration
* exceeds any configured interval. Therefore, segment the skb into
* smaller chunks. Skip it for the full offload case, as the driver
* and/or the hardware is expected to handle this.
* smaller chunks. Drivers with full offload are expected to handle
* this in hardware.
*/
if (skb_is_gso(skb) && !FULL_OFFLOAD_IS_ENABLED(q->flags)) {
if (skb_is_gso(skb)) {
unsigned int slen = 0, numsegs = 0, len = qdisc_pkt_len(skb);
netdev_features_t features = netif_skb_features(skb);
struct sk_buff *segs, *nskb;
......@@ -491,7 +487,10 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch,
return taprio_enqueue_one(skb, sch, child, to_free);
}
static struct sk_buff *taprio_peek_soft(struct Qdisc *sch)
/* Will not be called in the full offload case, since the TX queues are
* attached to the Qdisc created using qdisc_create_dflt()
*/
static struct sk_buff *taprio_peek(struct Qdisc *sch)
{
struct taprio_sched *q = qdisc_priv(sch);
struct net_device *dev = qdisc_dev(sch);
......@@ -535,20 +534,6 @@ static struct sk_buff *taprio_peek_soft(struct Qdisc *sch)
return NULL;
}
static struct sk_buff *taprio_peek_offload(struct Qdisc *sch)
{
WARN_ONCE(1, "Trying to peek into the root of a taprio qdisc configured with full offload\n");
return NULL;
}
static struct sk_buff *taprio_peek(struct Qdisc *sch)
{
struct taprio_sched *q = qdisc_priv(sch);
return q->peek(sch);
}
static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry)
{
atomic_set(&entry->budget,
......@@ -556,7 +541,10 @@ static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry)
atomic64_read(&q->picos_per_byte)));
}
static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch)
/* Will not be called in the full offload case, since the TX queues are
* attached to the Qdisc created using qdisc_create_dflt()
*/
static struct sk_buff *taprio_dequeue(struct Qdisc *sch)
{
struct taprio_sched *q = qdisc_priv(sch);
struct net_device *dev = qdisc_dev(sch);
......@@ -644,20 +632,6 @@ static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch)
return skb;
}
static struct sk_buff *taprio_dequeue_offload(struct Qdisc *sch)
{
WARN_ONCE(1, "Trying to dequeue from the root of a taprio qdisc configured with full offload\n");
return NULL;
}
static struct sk_buff *taprio_dequeue(struct Qdisc *sch)
{
struct taprio_sched *q = qdisc_priv(sch);
return q->dequeue(sch);
}
static bool should_restart_cycle(const struct sched_gate_list *oper,
const struct sched_entry *entry)
{
......@@ -1193,16 +1167,10 @@ static void taprio_offload_config_changed(struct taprio_sched *q)
{
struct sched_gate_list *oper, *admin;
spin_lock(&q->current_entry_lock);
oper = rcu_dereference_protected(q->oper_sched,
lockdep_is_held(&q->current_entry_lock));
admin = rcu_dereference_protected(q->admin_sched,
lockdep_is_held(&q->current_entry_lock));
oper = rtnl_dereference(q->oper_sched);
admin = rtnl_dereference(q->admin_sched);
switch_schedules(q, &admin, &oper);
spin_unlock(&q->current_entry_lock);
}
static u32 tc_map_to_queue_mask(struct net_device *dev, u32 tc_mask)
......@@ -1490,10 +1458,8 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
}
INIT_LIST_HEAD(&new_admin->entries);
rcu_read_lock();
oper = rcu_dereference(q->oper_sched);
admin = rcu_dereference(q->admin_sched);
rcu_read_unlock();
oper = rtnl_dereference(q->oper_sched);
admin = rtnl_dereference(q->admin_sched);
/* no changes - no new mqprio settings */
if (!taprio_mqprio_cmp(dev, mqprio))
......@@ -1563,17 +1529,6 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
q->advance_timer.function = advance_sched;
}
if (FULL_OFFLOAD_IS_ENABLED(q->flags)) {
q->dequeue = taprio_dequeue_offload;
q->peek = taprio_peek_offload;
} else {
/* Be sure to always keep the function pointers
* in a consistent state.
*/
q->dequeue = taprio_dequeue_soft;
q->peek = taprio_peek_soft;
}
err = taprio_get_start_time(sch, new_admin, &start);
if (err < 0) {
NL_SET_ERR_MSG(extack, "Internal error: failed get start time");
......@@ -1642,6 +1597,7 @@ static void taprio_destroy(struct Qdisc *sch)
{
struct taprio_sched *q = qdisc_priv(sch);
struct net_device *dev = qdisc_dev(sch);
struct sched_gate_list *oper, *admin;
unsigned int i;
spin_lock(&taprio_list_lock);
......@@ -1665,11 +1621,14 @@ static void taprio_destroy(struct Qdisc *sch)
netdev_reset_tc(dev);
if (q->oper_sched)
call_rcu(&q->oper_sched->rcu, taprio_free_sched_cb);
oper = rtnl_dereference(q->oper_sched);
admin = rtnl_dereference(q->admin_sched);
if (oper)
call_rcu(&oper->rcu, taprio_free_sched_cb);
if (q->admin_sched)
call_rcu(&q->admin_sched->rcu, taprio_free_sched_cb);
if (admin)
call_rcu(&admin->rcu, taprio_free_sched_cb);
}
static int taprio_init(struct Qdisc *sch, struct nlattr *opt,
......@@ -1684,9 +1643,6 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt,
hrtimer_init(&q->advance_timer, CLOCK_TAI, HRTIMER_MODE_ABS);
q->advance_timer.function = advance_sched;
q->dequeue = taprio_dequeue_soft;
q->peek = taprio_peek_soft;
q->root = sch;
/* We only support static clockids. Use an invalid value as default
......@@ -1699,11 +1655,15 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt,
list_add(&q->taprio_list, &taprio_list);
spin_unlock(&taprio_list_lock);
if (sch->parent != TC_H_ROOT)
if (sch->parent != TC_H_ROOT) {
NL_SET_ERR_MSG_MOD(extack, "Can only be attached as root qdisc");
return -EOPNOTSUPP;
}
if (!netif_is_multiqueue(dev))
if (!netif_is_multiqueue(dev)) {
NL_SET_ERR_MSG_MOD(extack, "Multi-queue device is required");
return -EOPNOTSUPP;
}
/* pre-allocate qdisc, attachment can't fail */
q->qdiscs = kcalloc(dev->num_tx_queues,
......@@ -1884,9 +1844,8 @@ static int taprio_dump(struct Qdisc *sch, struct sk_buff *skb)
struct nlattr *nest, *sched_nest;
unsigned int i;
rcu_read_lock();
oper = rcu_dereference(q->oper_sched);
admin = rcu_dereference(q->admin_sched);
oper = rtnl_dereference(q->oper_sched);
admin = rtnl_dereference(q->admin_sched);
opt.num_tc = netdev_get_num_tc(dev);
memcpy(opt.prio_tc_map, dev->prio_tc_map, sizeof(opt.prio_tc_map));
......@@ -1930,8 +1889,6 @@ static int taprio_dump(struct Qdisc *sch, struct sk_buff *skb)
nla_nest_end(skb, sched_nest);
done:
rcu_read_unlock();
return nla_nest_end(skb, nest);
admin_error:
......@@ -1941,7 +1898,6 @@ static int taprio_dump(struct Qdisc *sch, struct sk_buff *skb)
nla_nest_cancel(skb, nest);
start_error:
rcu_read_unlock();
return -ENOSPC;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment