mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 04:18:39 +08:00
net: sched: add rcu annotations around qdisc->qdisc_sleeping
syzbot reported a race around qdisc->qdisc_sleeping [1]
It is time we add proper annotations to reads and writes to/from
qdisc->qdisc_sleeping.
[1]
BUG: KCSAN: data-race in dev_graft_qdisc / qdisc_lookup_rcu
read to 0xffff8881286fc618 of 8 bytes by task 6928 on cpu 1:
qdisc_lookup_rcu+0x192/0x2c0 net/sched/sch_api.c:331
__tcf_qdisc_find+0x74/0x3c0 net/sched/cls_api.c:1174
tc_get_tfilter+0x18f/0x990 net/sched/cls_api.c:2547
rtnetlink_rcv_msg+0x7af/0x8c0 net/core/rtnetlink.c:6386
netlink_rcv_skb+0x126/0x220 net/netlink/af_netlink.c:2546
rtnetlink_rcv+0x1c/0x20 net/core/rtnetlink.c:6413
netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline]
netlink_unicast+0x56f/0x640 net/netlink/af_netlink.c:1365
netlink_sendmsg+0x665/0x770 net/netlink/af_netlink.c:1913
sock_sendmsg_nosec net/socket.c:724 [inline]
sock_sendmsg net/socket.c:747 [inline]
____sys_sendmsg+0x375/0x4c0 net/socket.c:2503
___sys_sendmsg net/socket.c:2557 [inline]
__sys_sendmsg+0x1e3/0x270 net/socket.c:2586
__do_sys_sendmsg net/socket.c:2595 [inline]
__se_sys_sendmsg net/socket.c:2593 [inline]
__x64_sys_sendmsg+0x46/0x50 net/socket.c:2593
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x63/0xcd
write to 0xffff8881286fc618 of 8 bytes by task 6912 on cpu 0:
dev_graft_qdisc+0x4f/0x80 net/sched/sch_generic.c:1115
qdisc_graft+0x7d0/0xb60 net/sched/sch_api.c:1103
tc_modify_qdisc+0x712/0xf10 net/sched/sch_api.c:1693
rtnetlink_rcv_msg+0x807/0x8c0 net/core/rtnetlink.c:6395
netlink_rcv_skb+0x126/0x220 net/netlink/af_netlink.c:2546
rtnetlink_rcv+0x1c/0x20 net/core/rtnetlink.c:6413
netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline]
netlink_unicast+0x56f/0x640 net/netlink/af_netlink.c:1365
netlink_sendmsg+0x665/0x770 net/netlink/af_netlink.c:1913
sock_sendmsg_nosec net/socket.c:724 [inline]
sock_sendmsg net/socket.c:747 [inline]
____sys_sendmsg+0x375/0x4c0 net/socket.c:2503
___sys_sendmsg net/socket.c:2557 [inline]
__sys_sendmsg+0x1e3/0x270 net/socket.c:2586
__do_sys_sendmsg net/socket.c:2595 [inline]
__se_sys_sendmsg net/socket.c:2593 [inline]
__x64_sys_sendmsg+0x46/0x50 net/socket.c:2593
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x63/0xcd
Reported by Kernel Concurrency Sanitizer on:
CPU: 0 PID: 6912 Comm: syz-executor.5 Not tainted 6.4.0-rc3-syzkaller-00190-g0d85b27b0cc6 #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/16/2023
Fixes: 3a7d0d07a3
("net: sched: extend Qdisc with rcu")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Vlad Buslov <vladbu@nvidia.com>
Acked-by: Jamal Hadi Salim<jhs@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
e3144ff52f
commit
d636fc5dd6
@ -620,7 +620,7 @@ struct netdev_queue {
|
|||||||
netdevice_tracker dev_tracker;
|
netdevice_tracker dev_tracker;
|
||||||
|
|
||||||
struct Qdisc __rcu *qdisc;
|
struct Qdisc __rcu *qdisc;
|
||||||
struct Qdisc *qdisc_sleeping;
|
struct Qdisc __rcu *qdisc_sleeping;
|
||||||
#ifdef CONFIG_SYSFS
|
#ifdef CONFIG_SYSFS
|
||||||
struct kobject kobj;
|
struct kobject kobj;
|
||||||
#endif
|
#endif
|
||||||
|
@ -545,7 +545,7 @@ static inline struct Qdisc *qdisc_root_bh(const struct Qdisc *qdisc)
|
|||||||
|
|
||||||
static inline struct Qdisc *qdisc_root_sleeping(const struct Qdisc *qdisc)
|
static inline struct Qdisc *qdisc_root_sleeping(const struct Qdisc *qdisc)
|
||||||
{
|
{
|
||||||
return qdisc->dev_queue->qdisc_sleeping;
|
return rcu_dereference_rtnl(qdisc->dev_queue->qdisc_sleeping);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline spinlock_t *qdisc_root_sleeping_lock(const struct Qdisc *qdisc)
|
static inline spinlock_t *qdisc_root_sleeping_lock(const struct Qdisc *qdisc)
|
||||||
@ -754,7 +754,9 @@ static inline bool qdisc_tx_changing(const struct net_device *dev)
|
|||||||
|
|
||||||
for (i = 0; i < dev->num_tx_queues; i++) {
|
for (i = 0; i < dev->num_tx_queues; i++) {
|
||||||
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
|
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
|
||||||
if (rcu_access_pointer(txq->qdisc) != txq->qdisc_sleeping)
|
|
||||||
|
if (rcu_access_pointer(txq->qdisc) !=
|
||||||
|
rcu_access_pointer(txq->qdisc_sleeping))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -10543,7 +10543,7 @@ struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
|
|||||||
return NULL;
|
return NULL;
|
||||||
netdev_init_one_queue(dev, queue, NULL);
|
netdev_init_one_queue(dev, queue, NULL);
|
||||||
RCU_INIT_POINTER(queue->qdisc, &noop_qdisc);
|
RCU_INIT_POINTER(queue->qdisc, &noop_qdisc);
|
||||||
queue->qdisc_sleeping = &noop_qdisc;
|
RCU_INIT_POINTER(queue->qdisc_sleeping, &noop_qdisc);
|
||||||
rcu_assign_pointer(dev->ingress_queue, queue);
|
rcu_assign_pointer(dev->ingress_queue, queue);
|
||||||
#endif
|
#endif
|
||||||
return queue;
|
return queue;
|
||||||
|
@ -309,7 +309,7 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
|
|||||||
|
|
||||||
if (dev_ingress_queue(dev))
|
if (dev_ingress_queue(dev))
|
||||||
q = qdisc_match_from_root(
|
q = qdisc_match_from_root(
|
||||||
dev_ingress_queue(dev)->qdisc_sleeping,
|
rtnl_dereference(dev_ingress_queue(dev)->qdisc_sleeping),
|
||||||
handle);
|
handle);
|
||||||
out:
|
out:
|
||||||
return q;
|
return q;
|
||||||
@ -328,7 +328,8 @@ struct Qdisc *qdisc_lookup_rcu(struct net_device *dev, u32 handle)
|
|||||||
|
|
||||||
nq = dev_ingress_queue_rcu(dev);
|
nq = dev_ingress_queue_rcu(dev);
|
||||||
if (nq)
|
if (nq)
|
||||||
q = qdisc_match_from_root(nq->qdisc_sleeping, handle);
|
q = qdisc_match_from_root(rcu_dereference(nq->qdisc_sleeping),
|
||||||
|
handle);
|
||||||
out:
|
out:
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
@ -634,8 +635,13 @@ EXPORT_SYMBOL(qdisc_watchdog_init);
|
|||||||
void qdisc_watchdog_schedule_range_ns(struct qdisc_watchdog *wd, u64 expires,
|
void qdisc_watchdog_schedule_range_ns(struct qdisc_watchdog *wd, u64 expires,
|
||||||
u64 delta_ns)
|
u64 delta_ns)
|
||||||
{
|
{
|
||||||
if (test_bit(__QDISC_STATE_DEACTIVATED,
|
bool deactivated;
|
||||||
&qdisc_root_sleeping(wd->qdisc)->state))
|
|
||||||
|
rcu_read_lock();
|
||||||
|
deactivated = test_bit(__QDISC_STATE_DEACTIVATED,
|
||||||
|
&qdisc_root_sleeping(wd->qdisc)->state);
|
||||||
|
rcu_read_unlock();
|
||||||
|
if (deactivated)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (hrtimer_is_queued(&wd->timer)) {
|
if (hrtimer_is_queued(&wd->timer)) {
|
||||||
@ -1478,7 +1484,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
|
|||||||
}
|
}
|
||||||
q = qdisc_leaf(p, clid);
|
q = qdisc_leaf(p, clid);
|
||||||
} else if (dev_ingress_queue(dev)) {
|
} else if (dev_ingress_queue(dev)) {
|
||||||
q = dev_ingress_queue(dev)->qdisc_sleeping;
|
q = rtnl_dereference(dev_ingress_queue(dev)->qdisc_sleeping);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
q = rtnl_dereference(dev->qdisc);
|
q = rtnl_dereference(dev->qdisc);
|
||||||
@ -1564,7 +1570,7 @@ replay:
|
|||||||
}
|
}
|
||||||
q = qdisc_leaf(p, clid);
|
q = qdisc_leaf(p, clid);
|
||||||
} else if (dev_ingress_queue_create(dev)) {
|
} else if (dev_ingress_queue_create(dev)) {
|
||||||
q = dev_ingress_queue(dev)->qdisc_sleeping;
|
q = rtnl_dereference(dev_ingress_queue(dev)->qdisc_sleeping);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
q = rtnl_dereference(dev->qdisc);
|
q = rtnl_dereference(dev->qdisc);
|
||||||
@ -1805,8 +1811,8 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
|
|||||||
|
|
||||||
dev_queue = dev_ingress_queue(dev);
|
dev_queue = dev_ingress_queue(dev);
|
||||||
if (dev_queue &&
|
if (dev_queue &&
|
||||||
tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb,
|
tc_dump_qdisc_root(rtnl_dereference(dev_queue->qdisc_sleeping),
|
||||||
&q_idx, s_q_idx, false,
|
skb, cb, &q_idx, s_q_idx, false,
|
||||||
tca[TCA_DUMP_INVISIBLE]) < 0)
|
tca[TCA_DUMP_INVISIBLE]) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
@ -2249,8 +2255,8 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
|
|||||||
|
|
||||||
dev_queue = dev_ingress_queue(dev);
|
dev_queue = dev_ingress_queue(dev);
|
||||||
if (dev_queue &&
|
if (dev_queue &&
|
||||||
tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb,
|
tc_dump_tclass_root(rtnl_dereference(dev_queue->qdisc_sleeping),
|
||||||
&t, s_t, false) < 0)
|
skb, tcm, cb, &t, s_t, false) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -379,6 +379,7 @@ static void fq_pie_timer(struct timer_list *t)
|
|||||||
spinlock_t *root_lock; /* to lock qdisc for probability calculations */
|
spinlock_t *root_lock; /* to lock qdisc for probability calculations */
|
||||||
u32 idx;
|
u32 idx;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
root_lock = qdisc_lock(qdisc_root_sleeping(sch));
|
root_lock = qdisc_lock(qdisc_root_sleeping(sch));
|
||||||
spin_lock(root_lock);
|
spin_lock(root_lock);
|
||||||
|
|
||||||
@ -391,6 +392,7 @@ static void fq_pie_timer(struct timer_list *t)
|
|||||||
mod_timer(&q->adapt_timer, jiffies + q->p_params.tupdate);
|
mod_timer(&q->adapt_timer, jiffies + q->p_params.tupdate);
|
||||||
|
|
||||||
spin_unlock(root_lock);
|
spin_unlock(root_lock);
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fq_pie_init(struct Qdisc *sch, struct nlattr *opt,
|
static int fq_pie_init(struct Qdisc *sch, struct nlattr *opt,
|
||||||
|
@ -648,7 +648,7 @@ struct Qdisc_ops noop_qdisc_ops __read_mostly = {
|
|||||||
|
|
||||||
static struct netdev_queue noop_netdev_queue = {
|
static struct netdev_queue noop_netdev_queue = {
|
||||||
RCU_POINTER_INITIALIZER(qdisc, &noop_qdisc),
|
RCU_POINTER_INITIALIZER(qdisc, &noop_qdisc),
|
||||||
.qdisc_sleeping = &noop_qdisc,
|
RCU_POINTER_INITIALIZER(qdisc_sleeping, &noop_qdisc),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Qdisc noop_qdisc = {
|
struct Qdisc noop_qdisc = {
|
||||||
@ -1103,7 +1103,7 @@ EXPORT_SYMBOL(qdisc_put_unlocked);
|
|||||||
struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
|
struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
|
||||||
struct Qdisc *qdisc)
|
struct Qdisc *qdisc)
|
||||||
{
|
{
|
||||||
struct Qdisc *oqdisc = dev_queue->qdisc_sleeping;
|
struct Qdisc *oqdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||||
spinlock_t *root_lock;
|
spinlock_t *root_lock;
|
||||||
|
|
||||||
root_lock = qdisc_lock(oqdisc);
|
root_lock = qdisc_lock(oqdisc);
|
||||||
@ -1112,7 +1112,7 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
|
|||||||
/* ... and graft new one */
|
/* ... and graft new one */
|
||||||
if (qdisc == NULL)
|
if (qdisc == NULL)
|
||||||
qdisc = &noop_qdisc;
|
qdisc = &noop_qdisc;
|
||||||
dev_queue->qdisc_sleeping = qdisc;
|
rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc);
|
||||||
rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc);
|
rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc);
|
||||||
|
|
||||||
spin_unlock_bh(root_lock);
|
spin_unlock_bh(root_lock);
|
||||||
@ -1125,12 +1125,12 @@ static void shutdown_scheduler_queue(struct net_device *dev,
|
|||||||
struct netdev_queue *dev_queue,
|
struct netdev_queue *dev_queue,
|
||||||
void *_qdisc_default)
|
void *_qdisc_default)
|
||||||
{
|
{
|
||||||
struct Qdisc *qdisc = dev_queue->qdisc_sleeping;
|
struct Qdisc *qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||||
struct Qdisc *qdisc_default = _qdisc_default;
|
struct Qdisc *qdisc_default = _qdisc_default;
|
||||||
|
|
||||||
if (qdisc) {
|
if (qdisc) {
|
||||||
rcu_assign_pointer(dev_queue->qdisc, qdisc_default);
|
rcu_assign_pointer(dev_queue->qdisc, qdisc_default);
|
||||||
dev_queue->qdisc_sleeping = qdisc_default;
|
rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc_default);
|
||||||
|
|
||||||
qdisc_put(qdisc);
|
qdisc_put(qdisc);
|
||||||
}
|
}
|
||||||
@ -1154,7 +1154,7 @@ static void attach_one_default_qdisc(struct net_device *dev,
|
|||||||
|
|
||||||
if (!netif_is_multiqueue(dev))
|
if (!netif_is_multiqueue(dev))
|
||||||
qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
|
qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
|
||||||
dev_queue->qdisc_sleeping = qdisc;
|
rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void attach_default_qdiscs(struct net_device *dev)
|
static void attach_default_qdiscs(struct net_device *dev)
|
||||||
@ -1167,7 +1167,7 @@ static void attach_default_qdiscs(struct net_device *dev)
|
|||||||
if (!netif_is_multiqueue(dev) ||
|
if (!netif_is_multiqueue(dev) ||
|
||||||
dev->priv_flags & IFF_NO_QUEUE) {
|
dev->priv_flags & IFF_NO_QUEUE) {
|
||||||
netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
|
netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
|
||||||
qdisc = txq->qdisc_sleeping;
|
qdisc = rtnl_dereference(txq->qdisc_sleeping);
|
||||||
rcu_assign_pointer(dev->qdisc, qdisc);
|
rcu_assign_pointer(dev->qdisc, qdisc);
|
||||||
qdisc_refcount_inc(qdisc);
|
qdisc_refcount_inc(qdisc);
|
||||||
} else {
|
} else {
|
||||||
@ -1186,7 +1186,7 @@ static void attach_default_qdiscs(struct net_device *dev)
|
|||||||
netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc);
|
netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc);
|
||||||
dev->priv_flags |= IFF_NO_QUEUE;
|
dev->priv_flags |= IFF_NO_QUEUE;
|
||||||
netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
|
netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
|
||||||
qdisc = txq->qdisc_sleeping;
|
qdisc = rtnl_dereference(txq->qdisc_sleeping);
|
||||||
rcu_assign_pointer(dev->qdisc, qdisc);
|
rcu_assign_pointer(dev->qdisc, qdisc);
|
||||||
qdisc_refcount_inc(qdisc);
|
qdisc_refcount_inc(qdisc);
|
||||||
dev->priv_flags ^= IFF_NO_QUEUE;
|
dev->priv_flags ^= IFF_NO_QUEUE;
|
||||||
@ -1202,7 +1202,7 @@ static void transition_one_qdisc(struct net_device *dev,
|
|||||||
struct netdev_queue *dev_queue,
|
struct netdev_queue *dev_queue,
|
||||||
void *_need_watchdog)
|
void *_need_watchdog)
|
||||||
{
|
{
|
||||||
struct Qdisc *new_qdisc = dev_queue->qdisc_sleeping;
|
struct Qdisc *new_qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||||
int *need_watchdog_p = _need_watchdog;
|
int *need_watchdog_p = _need_watchdog;
|
||||||
|
|
||||||
if (!(new_qdisc->flags & TCQ_F_BUILTIN))
|
if (!(new_qdisc->flags & TCQ_F_BUILTIN))
|
||||||
@ -1272,7 +1272,7 @@ static void dev_reset_queue(struct net_device *dev,
|
|||||||
struct Qdisc *qdisc;
|
struct Qdisc *qdisc;
|
||||||
bool nolock;
|
bool nolock;
|
||||||
|
|
||||||
qdisc = dev_queue->qdisc_sleeping;
|
qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||||
if (!qdisc)
|
if (!qdisc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1303,7 +1303,7 @@ static bool some_qdisc_is_busy(struct net_device *dev)
|
|||||||
int val;
|
int val;
|
||||||
|
|
||||||
dev_queue = netdev_get_tx_queue(dev, i);
|
dev_queue = netdev_get_tx_queue(dev, i);
|
||||||
q = dev_queue->qdisc_sleeping;
|
q = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||||
|
|
||||||
root_lock = qdisc_lock(q);
|
root_lock = qdisc_lock(q);
|
||||||
spin_lock_bh(root_lock);
|
spin_lock_bh(root_lock);
|
||||||
@ -1379,7 +1379,7 @@ EXPORT_SYMBOL(dev_deactivate);
|
|||||||
static int qdisc_change_tx_queue_len(struct net_device *dev,
|
static int qdisc_change_tx_queue_len(struct net_device *dev,
|
||||||
struct netdev_queue *dev_queue)
|
struct netdev_queue *dev_queue)
|
||||||
{
|
{
|
||||||
struct Qdisc *qdisc = dev_queue->qdisc_sleeping;
|
struct Qdisc *qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||||
const struct Qdisc_ops *ops = qdisc->ops;
|
const struct Qdisc_ops *ops = qdisc->ops;
|
||||||
|
|
||||||
if (ops->change_tx_queue_len)
|
if (ops->change_tx_queue_len)
|
||||||
@ -1404,7 +1404,7 @@ void mq_change_real_num_tx(struct Qdisc *sch, unsigned int new_real_tx)
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = new_real_tx; i < dev->real_num_tx_queues; i++) {
|
for (i = new_real_tx; i < dev->real_num_tx_queues; i++) {
|
||||||
qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
|
qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc_sleeping);
|
||||||
/* Only update the default qdiscs we created,
|
/* Only update the default qdiscs we created,
|
||||||
* qdiscs with handles are always hashed.
|
* qdiscs with handles are always hashed.
|
||||||
*/
|
*/
|
||||||
@ -1412,7 +1412,7 @@ void mq_change_real_num_tx(struct Qdisc *sch, unsigned int new_real_tx)
|
|||||||
qdisc_hash_del(qdisc);
|
qdisc_hash_del(qdisc);
|
||||||
}
|
}
|
||||||
for (i = dev->real_num_tx_queues; i < new_real_tx; i++) {
|
for (i = dev->real_num_tx_queues; i < new_real_tx; i++) {
|
||||||
qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
|
qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc_sleeping);
|
||||||
if (qdisc != &noop_qdisc && !qdisc->handle)
|
if (qdisc != &noop_qdisc && !qdisc->handle)
|
||||||
qdisc_hash_add(qdisc, false);
|
qdisc_hash_add(qdisc, false);
|
||||||
}
|
}
|
||||||
@ -1449,7 +1449,7 @@ static void dev_init_scheduler_queue(struct net_device *dev,
|
|||||||
struct Qdisc *qdisc = _qdisc;
|
struct Qdisc *qdisc = _qdisc;
|
||||||
|
|
||||||
rcu_assign_pointer(dev_queue->qdisc, qdisc);
|
rcu_assign_pointer(dev_queue->qdisc, qdisc);
|
||||||
dev_queue->qdisc_sleeping = qdisc;
|
rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dev_init_scheduler(struct net_device *dev)
|
void dev_init_scheduler(struct net_device *dev)
|
||||||
|
@ -141,7 +141,7 @@ static int mq_dump(struct Qdisc *sch, struct sk_buff *skb)
|
|||||||
* qdisc totals are added at end.
|
* qdisc totals are added at end.
|
||||||
*/
|
*/
|
||||||
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
|
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
|
||||||
qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping;
|
qdisc = rtnl_dereference(netdev_get_tx_queue(dev, ntx)->qdisc_sleeping);
|
||||||
spin_lock_bh(qdisc_lock(qdisc));
|
spin_lock_bh(qdisc_lock(qdisc));
|
||||||
|
|
||||||
gnet_stats_add_basic(&sch->bstats, qdisc->cpu_bstats,
|
gnet_stats_add_basic(&sch->bstats, qdisc->cpu_bstats,
|
||||||
@ -202,7 +202,7 @@ static struct Qdisc *mq_leaf(struct Qdisc *sch, unsigned long cl)
|
|||||||
{
|
{
|
||||||
struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
|
struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
|
||||||
|
|
||||||
return dev_queue->qdisc_sleeping;
|
return rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long mq_find(struct Qdisc *sch, u32 classid)
|
static unsigned long mq_find(struct Qdisc *sch, u32 classid)
|
||||||
@ -221,7 +221,7 @@ static int mq_dump_class(struct Qdisc *sch, unsigned long cl,
|
|||||||
|
|
||||||
tcm->tcm_parent = TC_H_ROOT;
|
tcm->tcm_parent = TC_H_ROOT;
|
||||||
tcm->tcm_handle |= TC_H_MIN(cl);
|
tcm->tcm_handle |= TC_H_MIN(cl);
|
||||||
tcm->tcm_info = dev_queue->qdisc_sleeping->handle;
|
tcm->tcm_info = rtnl_dereference(dev_queue->qdisc_sleeping)->handle;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ static int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
|
|||||||
{
|
{
|
||||||
struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
|
struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
|
||||||
|
|
||||||
sch = dev_queue->qdisc_sleeping;
|
sch = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||||
if (gnet_stats_copy_basic(d, sch->cpu_bstats, &sch->bstats, true) < 0 ||
|
if (gnet_stats_copy_basic(d, sch->cpu_bstats, &sch->bstats, true) < 0 ||
|
||||||
qdisc_qstats_copy(d, sch) < 0)
|
qdisc_qstats_copy(d, sch) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -557,7 +557,7 @@ static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb)
|
|||||||
* qdisc totals are added at end.
|
* qdisc totals are added at end.
|
||||||
*/
|
*/
|
||||||
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
|
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
|
||||||
qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping;
|
qdisc = rtnl_dereference(netdev_get_tx_queue(dev, ntx)->qdisc_sleeping);
|
||||||
spin_lock_bh(qdisc_lock(qdisc));
|
spin_lock_bh(qdisc_lock(qdisc));
|
||||||
|
|
||||||
gnet_stats_add_basic(&sch->bstats, qdisc->cpu_bstats,
|
gnet_stats_add_basic(&sch->bstats, qdisc->cpu_bstats,
|
||||||
@ -604,7 +604,7 @@ static struct Qdisc *mqprio_leaf(struct Qdisc *sch, unsigned long cl)
|
|||||||
if (!dev_queue)
|
if (!dev_queue)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return dev_queue->qdisc_sleeping;
|
return rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long mqprio_find(struct Qdisc *sch, u32 classid)
|
static unsigned long mqprio_find(struct Qdisc *sch, u32 classid)
|
||||||
@ -637,7 +637,7 @@ static int mqprio_dump_class(struct Qdisc *sch, unsigned long cl,
|
|||||||
tcm->tcm_parent = (tc < 0) ? 0 :
|
tcm->tcm_parent = (tc < 0) ? 0 :
|
||||||
TC_H_MAKE(TC_H_MAJ(sch->handle),
|
TC_H_MAKE(TC_H_MAJ(sch->handle),
|
||||||
TC_H_MIN(tc + TC_H_MIN_PRIORITY));
|
TC_H_MIN(tc + TC_H_MIN_PRIORITY));
|
||||||
tcm->tcm_info = dev_queue->qdisc_sleeping->handle;
|
tcm->tcm_info = rtnl_dereference(dev_queue->qdisc_sleeping)->handle;
|
||||||
} else {
|
} else {
|
||||||
tcm->tcm_parent = TC_H_ROOT;
|
tcm->tcm_parent = TC_H_ROOT;
|
||||||
tcm->tcm_info = 0;
|
tcm->tcm_info = 0;
|
||||||
@ -693,7 +693,7 @@ static int mqprio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
|
|||||||
} else {
|
} else {
|
||||||
struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl);
|
struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl);
|
||||||
|
|
||||||
sch = dev_queue->qdisc_sleeping;
|
sch = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||||
if (gnet_stats_copy_basic(d, sch->cpu_bstats,
|
if (gnet_stats_copy_basic(d, sch->cpu_bstats,
|
||||||
&sch->bstats, true) < 0 ||
|
&sch->bstats, true) < 0 ||
|
||||||
qdisc_qstats_copy(d, sch) < 0)
|
qdisc_qstats_copy(d, sch) < 0)
|
||||||
|
@ -421,8 +421,10 @@ static void pie_timer(struct timer_list *t)
|
|||||||
{
|
{
|
||||||
struct pie_sched_data *q = from_timer(q, t, adapt_timer);
|
struct pie_sched_data *q = from_timer(q, t, adapt_timer);
|
||||||
struct Qdisc *sch = q->sch;
|
struct Qdisc *sch = q->sch;
|
||||||
spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
|
spinlock_t *root_lock;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
root_lock = qdisc_lock(qdisc_root_sleeping(sch));
|
||||||
spin_lock(root_lock);
|
spin_lock(root_lock);
|
||||||
pie_calculate_probability(&q->params, &q->vars, sch->qstats.backlog);
|
pie_calculate_probability(&q->params, &q->vars, sch->qstats.backlog);
|
||||||
|
|
||||||
@ -430,6 +432,7 @@ static void pie_timer(struct timer_list *t)
|
|||||||
if (q->params.tupdate)
|
if (q->params.tupdate)
|
||||||
mod_timer(&q->adapt_timer, jiffies + q->params.tupdate);
|
mod_timer(&q->adapt_timer, jiffies + q->params.tupdate);
|
||||||
spin_unlock(root_lock);
|
spin_unlock(root_lock);
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pie_init(struct Qdisc *sch, struct nlattr *opt,
|
static int pie_init(struct Qdisc *sch, struct nlattr *opt,
|
||||||
|
@ -321,12 +321,15 @@ static inline void red_adaptative_timer(struct timer_list *t)
|
|||||||
{
|
{
|
||||||
struct red_sched_data *q = from_timer(q, t, adapt_timer);
|
struct red_sched_data *q = from_timer(q, t, adapt_timer);
|
||||||
struct Qdisc *sch = q->sch;
|
struct Qdisc *sch = q->sch;
|
||||||
spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
|
spinlock_t *root_lock;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
root_lock = qdisc_lock(qdisc_root_sleeping(sch));
|
||||||
spin_lock(root_lock);
|
spin_lock(root_lock);
|
||||||
red_adaptative_algo(&q->parms, &q->vars);
|
red_adaptative_algo(&q->parms, &q->vars);
|
||||||
mod_timer(&q->adapt_timer, jiffies + HZ/2);
|
mod_timer(&q->adapt_timer, jiffies + HZ/2);
|
||||||
spin_unlock(root_lock);
|
spin_unlock(root_lock);
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int red_init(struct Qdisc *sch, struct nlattr *opt,
|
static int red_init(struct Qdisc *sch, struct nlattr *opt,
|
||||||
|
@ -606,10 +606,12 @@ static void sfq_perturbation(struct timer_list *t)
|
|||||||
{
|
{
|
||||||
struct sfq_sched_data *q = from_timer(q, t, perturb_timer);
|
struct sfq_sched_data *q = from_timer(q, t, perturb_timer);
|
||||||
struct Qdisc *sch = q->sch;
|
struct Qdisc *sch = q->sch;
|
||||||
spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
|
spinlock_t *root_lock;
|
||||||
siphash_key_t nkey;
|
siphash_key_t nkey;
|
||||||
|
|
||||||
get_random_bytes(&nkey, sizeof(nkey));
|
get_random_bytes(&nkey, sizeof(nkey));
|
||||||
|
rcu_read_lock();
|
||||||
|
root_lock = qdisc_lock(qdisc_root_sleeping(sch));
|
||||||
spin_lock(root_lock);
|
spin_lock(root_lock);
|
||||||
q->perturbation = nkey;
|
q->perturbation = nkey;
|
||||||
if (!q->filter_list && q->tail)
|
if (!q->filter_list && q->tail)
|
||||||
@ -618,6 +620,7 @@ static void sfq_perturbation(struct timer_list *t)
|
|||||||
|
|
||||||
if (q->perturb_period)
|
if (q->perturb_period)
|
||||||
mod_timer(&q->perturb_timer, jiffies + q->perturb_period);
|
mod_timer(&q->perturb_timer, jiffies + q->perturb_period);
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
|
static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
|
||||||
|
@ -2358,7 +2358,7 @@ static struct Qdisc *taprio_leaf(struct Qdisc *sch, unsigned long cl)
|
|||||||
if (!dev_queue)
|
if (!dev_queue)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return dev_queue->qdisc_sleeping;
|
return rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long taprio_find(struct Qdisc *sch, u32 classid)
|
static unsigned long taprio_find(struct Qdisc *sch, u32 classid)
|
||||||
@ -2377,7 +2377,7 @@ static int taprio_dump_class(struct Qdisc *sch, unsigned long cl,
|
|||||||
|
|
||||||
tcm->tcm_parent = TC_H_ROOT;
|
tcm->tcm_parent = TC_H_ROOT;
|
||||||
tcm->tcm_handle |= TC_H_MIN(cl);
|
tcm->tcm_handle |= TC_H_MIN(cl);
|
||||||
tcm->tcm_info = dev_queue->qdisc_sleeping->handle;
|
tcm->tcm_info = rtnl_dereference(dev_queue->qdisc_sleeping)->handle;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2389,7 +2389,7 @@ static int taprio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
|
|||||||
{
|
{
|
||||||
struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
|
struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
|
||||||
|
|
||||||
sch = dev_queue->qdisc_sleeping;
|
sch = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||||
if (gnet_stats_copy_basic(d, NULL, &sch->bstats, true) < 0 ||
|
if (gnet_stats_copy_basic(d, NULL, &sch->bstats, true) < 0 ||
|
||||||
qdisc_qstats_copy(d, sch) < 0)
|
qdisc_qstats_copy(d, sch) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -297,7 +297,7 @@ restart:
|
|||||||
struct net_device *slave = qdisc_dev(q);
|
struct net_device *slave = qdisc_dev(q);
|
||||||
struct netdev_queue *slave_txq = netdev_get_tx_queue(slave, 0);
|
struct netdev_queue *slave_txq = netdev_get_tx_queue(slave, 0);
|
||||||
|
|
||||||
if (slave_txq->qdisc_sleeping != q)
|
if (rcu_access_pointer(slave_txq->qdisc_sleeping) != q)
|
||||||
continue;
|
continue;
|
||||||
if (netif_xmit_stopped(netdev_get_tx_queue(slave, subq)) ||
|
if (netif_xmit_stopped(netdev_get_tx_queue(slave, subq)) ||
|
||||||
!netif_running(slave)) {
|
!netif_running(slave)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user