net: sched: Pass root lock to Qdisc_ops.enqueue
A following patch introduces qevents, points in qdisc algorithm where packet can be processed by user-defined filters. Should this processing lead to a situation where a new packet is to be enqueued on the same port, holding the root lock would lead to deadlocks. To solve the issue, qevent handler needs to unlock and relock the root lock when necessary. To that end, add the root lock argument to the qdisc op enqueue, and propagate throughout. Signed-off-by: Petr Machata <petrm@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
5e701e49b7
commit
aebe4426cc
@@ -187,7 +187,7 @@ static int tbf_offload_dump(struct Qdisc *sch)
|
||||
/* GSO packet is too big, segment it so that tbf can transmit
|
||||
* each segment in time
|
||||
*/
|
||||
static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch,
|
||||
static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch, spinlock_t *root_lock,
|
||||
struct sk_buff **to_free)
|
||||
{
|
||||
struct tbf_sched_data *q = qdisc_priv(sch);
|
||||
@@ -206,7 +206,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch,
|
||||
skb_mark_not_on_list(segs);
|
||||
qdisc_skb_cb(segs)->pkt_len = segs->len;
|
||||
len += segs->len;
|
||||
ret = qdisc_enqueue(segs, q->qdisc, to_free);
|
||||
ret = qdisc_enqueue(segs, q->qdisc, root_lock, to_free);
|
||||
if (ret != NET_XMIT_SUCCESS) {
|
||||
if (net_xmit_drop_count(ret))
|
||||
qdisc_qstats_drop(sch);
|
||||
@@ -221,7 +221,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch,
|
||||
return nb > 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP;
|
||||
}
|
||||
|
||||
static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
||||
static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch, spinlock_t *root_lock,
|
||||
struct sk_buff **to_free)
|
||||
{
|
||||
struct tbf_sched_data *q = qdisc_priv(sch);
|
||||
@@ -231,10 +231,10 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
||||
if (qdisc_pkt_len(skb) > q->max_size) {
|
||||
if (skb_is_gso(skb) &&
|
||||
skb_gso_validate_mac_len(skb, q->max_size))
|
||||
return tbf_segment(skb, sch, to_free);
|
||||
return tbf_segment(skb, sch, root_lock, to_free);
|
||||
return qdisc_drop(skb, sch, to_free);
|
||||
}
|
||||
ret = qdisc_enqueue(skb, q->qdisc, to_free);
|
||||
ret = qdisc_enqueue(skb, q->qdisc, root_lock, to_free);
|
||||
if (ret != NET_XMIT_SUCCESS) {
|
||||
if (net_xmit_drop_count(ret))
|
||||
qdisc_qstats_drop(sch);
|
||||
|
Reference in New Issue
Block a user