Skip to content

Commit d636fc5

Browse files
edumazetdavem330
authored andcommitted
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: 3a7d0d0 ("net: sched: extend Qdisc with rcu") Reported-by: syzbot <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Cc: Vlad Buslov <[email protected]> Acked-by: Jamal Hadi Salim<[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e3144ff commit d636fc5

File tree

13 files changed

+63
-44
lines changed

13 files changed

+63
-44
lines changed

include/linux/netdevice.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ struct netdev_queue {
620620
netdevice_tracker dev_tracker;
621621

622622
struct Qdisc __rcu *qdisc;
623-
struct Qdisc *qdisc_sleeping;
623+
struct Qdisc __rcu *qdisc_sleeping;
624624
#ifdef CONFIG_SYSFS
625625
struct kobject kobj;
626626
#endif

include/net/sch_generic.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ static inline struct Qdisc *qdisc_root_bh(const struct Qdisc *qdisc)
545545

546546
static inline struct Qdisc *qdisc_root_sleeping(const struct Qdisc *qdisc)
547547
{
548-
return qdisc->dev_queue->qdisc_sleeping;
548+
return rcu_dereference_rtnl(qdisc->dev_queue->qdisc_sleeping);
549549
}
550550

551551
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)
754754

755755
for (i = 0; i < dev->num_tx_queues; i++) {
756756
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
757-
if (rcu_access_pointer(txq->qdisc) != txq->qdisc_sleeping)
757+
758+
if (rcu_access_pointer(txq->qdisc) !=
759+
rcu_access_pointer(txq->qdisc_sleeping))
758760
return true;
759761
}
760762
return false;

net/core/dev.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10543,7 +10543,7 @@ struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
1054310543
return NULL;
1054410544
netdev_init_one_queue(dev, queue, NULL);
1054510545
RCU_INIT_POINTER(queue->qdisc, &noop_qdisc);
10546-
queue->qdisc_sleeping = &noop_qdisc;
10546+
RCU_INIT_POINTER(queue->qdisc_sleeping, &noop_qdisc);
1054710547
rcu_assign_pointer(dev->ingress_queue, queue);
1054810548
#endif
1054910549
return queue;

net/sched/sch_api.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
309309

310310
if (dev_ingress_queue(dev))
311311
q = qdisc_match_from_root(
312-
dev_ingress_queue(dev)->qdisc_sleeping,
312+
rtnl_dereference(dev_ingress_queue(dev)->qdisc_sleeping),
313313
handle);
314314
out:
315315
return q;
@@ -328,7 +328,8 @@ struct Qdisc *qdisc_lookup_rcu(struct net_device *dev, u32 handle)
328328

329329
nq = dev_ingress_queue_rcu(dev);
330330
if (nq)
331-
q = qdisc_match_from_root(nq->qdisc_sleeping, handle);
331+
q = qdisc_match_from_root(rcu_dereference(nq->qdisc_sleeping),
332+
handle);
332333
out:
333334
return q;
334335
}
@@ -634,8 +635,13 @@ EXPORT_SYMBOL(qdisc_watchdog_init);
634635
void qdisc_watchdog_schedule_range_ns(struct qdisc_watchdog *wd, u64 expires,
635636
u64 delta_ns)
636637
{
637-
if (test_bit(__QDISC_STATE_DEACTIVATED,
638-
&qdisc_root_sleeping(wd->qdisc)->state))
638+
bool deactivated;
639+
640+
rcu_read_lock();
641+
deactivated = test_bit(__QDISC_STATE_DEACTIVATED,
642+
&qdisc_root_sleeping(wd->qdisc)->state);
643+
rcu_read_unlock();
644+
if (deactivated)
639645
return;
640646

641647
if (hrtimer_is_queued(&wd->timer)) {
@@ -1478,7 +1484,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
14781484
}
14791485
q = qdisc_leaf(p, clid);
14801486
} else if (dev_ingress_queue(dev)) {
1481-
q = dev_ingress_queue(dev)->qdisc_sleeping;
1487+
q = rtnl_dereference(dev_ingress_queue(dev)->qdisc_sleeping);
14821488
}
14831489
} else {
14841490
q = rtnl_dereference(dev->qdisc);
@@ -1564,7 +1570,7 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
15641570
}
15651571
q = qdisc_leaf(p, clid);
15661572
} else if (dev_ingress_queue_create(dev)) {
1567-
q = dev_ingress_queue(dev)->qdisc_sleeping;
1573+
q = rtnl_dereference(dev_ingress_queue(dev)->qdisc_sleeping);
15681574
}
15691575
} else {
15701576
q = rtnl_dereference(dev->qdisc);
@@ -1805,8 +1811,8 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
18051811

18061812
dev_queue = dev_ingress_queue(dev);
18071813
if (dev_queue &&
1808-
tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb,
1809-
&q_idx, s_q_idx, false,
1814+
tc_dump_qdisc_root(rtnl_dereference(dev_queue->qdisc_sleeping),
1815+
skb, cb, &q_idx, s_q_idx, false,
18101816
tca[TCA_DUMP_INVISIBLE]) < 0)
18111817
goto done;
18121818

@@ -2249,8 +2255,8 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
22492255

22502256
dev_queue = dev_ingress_queue(dev);
22512257
if (dev_queue &&
2252-
tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb,
2253-
&t, s_t, false) < 0)
2258+
tc_dump_tclass_root(rtnl_dereference(dev_queue->qdisc_sleeping),
2259+
skb, tcm, cb, &t, s_t, false) < 0)
22542260
goto done;
22552261

22562262
done:

net/sched/sch_fq_pie.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ static void fq_pie_timer(struct timer_list *t)
379379
spinlock_t *root_lock; /* to lock qdisc for probability calculations */
380380
u32 idx;
381381

382+
rcu_read_lock();
382383
root_lock = qdisc_lock(qdisc_root_sleeping(sch));
383384
spin_lock(root_lock);
384385

@@ -391,6 +392,7 @@ static void fq_pie_timer(struct timer_list *t)
391392
mod_timer(&q->adapt_timer, jiffies + q->p_params.tupdate);
392393

393394
spin_unlock(root_lock);
395+
rcu_read_unlock();
394396
}
395397

396398
static int fq_pie_init(struct Qdisc *sch, struct nlattr *opt,

net/sched/sch_generic.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ struct Qdisc_ops noop_qdisc_ops __read_mostly = {
648648

649649
static struct netdev_queue noop_netdev_queue = {
650650
RCU_POINTER_INITIALIZER(qdisc, &noop_qdisc),
651-
.qdisc_sleeping = &noop_qdisc,
651+
RCU_POINTER_INITIALIZER(qdisc_sleeping, &noop_qdisc),
652652
};
653653

654654
struct Qdisc noop_qdisc = {
@@ -1103,7 +1103,7 @@ EXPORT_SYMBOL(qdisc_put_unlocked);
11031103
struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
11041104
struct Qdisc *qdisc)
11051105
{
1106-
struct Qdisc *oqdisc = dev_queue->qdisc_sleeping;
1106+
struct Qdisc *oqdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
11071107
spinlock_t *root_lock;
11081108

11091109
root_lock = qdisc_lock(oqdisc);
@@ -1112,7 +1112,7 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
11121112
/* ... and graft new one */
11131113
if (qdisc == NULL)
11141114
qdisc = &noop_qdisc;
1115-
dev_queue->qdisc_sleeping = qdisc;
1115+
rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc);
11161116
rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc);
11171117

11181118
spin_unlock_bh(root_lock);
@@ -1125,12 +1125,12 @@ static void shutdown_scheduler_queue(struct net_device *dev,
11251125
struct netdev_queue *dev_queue,
11261126
void *_qdisc_default)
11271127
{
1128-
struct Qdisc *qdisc = dev_queue->qdisc_sleeping;
1128+
struct Qdisc *qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
11291129
struct Qdisc *qdisc_default = _qdisc_default;
11301130

11311131
if (qdisc) {
11321132
rcu_assign_pointer(dev_queue->qdisc, qdisc_default);
1133-
dev_queue->qdisc_sleeping = qdisc_default;
1133+
rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc_default);
11341134

11351135
qdisc_put(qdisc);
11361136
}
@@ -1154,7 +1154,7 @@ static void attach_one_default_qdisc(struct net_device *dev,
11541154

11551155
if (!netif_is_multiqueue(dev))
11561156
qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
1157-
dev_queue->qdisc_sleeping = qdisc;
1157+
rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc);
11581158
}
11591159

11601160
static void attach_default_qdiscs(struct net_device *dev)
@@ -1167,7 +1167,7 @@ static void attach_default_qdiscs(struct net_device *dev)
11671167
if (!netif_is_multiqueue(dev) ||
11681168
dev->priv_flags & IFF_NO_QUEUE) {
11691169
netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
1170-
qdisc = txq->qdisc_sleeping;
1170+
qdisc = rtnl_dereference(txq->qdisc_sleeping);
11711171
rcu_assign_pointer(dev->qdisc, qdisc);
11721172
qdisc_refcount_inc(qdisc);
11731173
} else {
@@ -1186,7 +1186,7 @@ static void attach_default_qdiscs(struct net_device *dev)
11861186
netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc);
11871187
dev->priv_flags |= IFF_NO_QUEUE;
11881188
netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
1189-
qdisc = txq->qdisc_sleeping;
1189+
qdisc = rtnl_dereference(txq->qdisc_sleeping);
11901190
rcu_assign_pointer(dev->qdisc, qdisc);
11911191
qdisc_refcount_inc(qdisc);
11921192
dev->priv_flags ^= IFF_NO_QUEUE;
@@ -1202,7 +1202,7 @@ static void transition_one_qdisc(struct net_device *dev,
12021202
struct netdev_queue *dev_queue,
12031203
void *_need_watchdog)
12041204
{
1205-
struct Qdisc *new_qdisc = dev_queue->qdisc_sleeping;
1205+
struct Qdisc *new_qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
12061206
int *need_watchdog_p = _need_watchdog;
12071207

12081208
if (!(new_qdisc->flags & TCQ_F_BUILTIN))
@@ -1272,7 +1272,7 @@ static void dev_reset_queue(struct net_device *dev,
12721272
struct Qdisc *qdisc;
12731273
bool nolock;
12741274

1275-
qdisc = dev_queue->qdisc_sleeping;
1275+
qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
12761276
if (!qdisc)
12771277
return;
12781278

@@ -1303,7 +1303,7 @@ static bool some_qdisc_is_busy(struct net_device *dev)
13031303
int val;
13041304

13051305
dev_queue = netdev_get_tx_queue(dev, i);
1306-
q = dev_queue->qdisc_sleeping;
1306+
q = rtnl_dereference(dev_queue->qdisc_sleeping);
13071307

13081308
root_lock = qdisc_lock(q);
13091309
spin_lock_bh(root_lock);
@@ -1379,7 +1379,7 @@ EXPORT_SYMBOL(dev_deactivate);
13791379
static int qdisc_change_tx_queue_len(struct net_device *dev,
13801380
struct netdev_queue *dev_queue)
13811381
{
1382-
struct Qdisc *qdisc = dev_queue->qdisc_sleeping;
1382+
struct Qdisc *qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
13831383
const struct Qdisc_ops *ops = qdisc->ops;
13841384

13851385
if (ops->change_tx_queue_len)
@@ -1404,15 +1404,15 @@ void mq_change_real_num_tx(struct Qdisc *sch, unsigned int new_real_tx)
14041404
unsigned int i;
14051405

14061406
for (i = new_real_tx; i < dev->real_num_tx_queues; i++) {
1407-
qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
1407+
qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc_sleeping);
14081408
/* Only update the default qdiscs we created,
14091409
* qdiscs with handles are always hashed.
14101410
*/
14111411
if (qdisc != &noop_qdisc && !qdisc->handle)
14121412
qdisc_hash_del(qdisc);
14131413
}
14141414
for (i = dev->real_num_tx_queues; i < new_real_tx; i++) {
1415-
qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
1415+
qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc_sleeping);
14161416
if (qdisc != &noop_qdisc && !qdisc->handle)
14171417
qdisc_hash_add(qdisc, false);
14181418
}
@@ -1449,7 +1449,7 @@ static void dev_init_scheduler_queue(struct net_device *dev,
14491449
struct Qdisc *qdisc = _qdisc;
14501450

14511451
rcu_assign_pointer(dev_queue->qdisc, qdisc);
1452-
dev_queue->qdisc_sleeping = qdisc;
1452+
rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc);
14531453
}
14541454

14551455
void dev_init_scheduler(struct net_device *dev)

net/sched/sch_mq.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ static int mq_dump(struct Qdisc *sch, struct sk_buff *skb)
141141
* qdisc totals are added at end.
142142
*/
143143
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
144-
qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping;
144+
qdisc = rtnl_dereference(netdev_get_tx_queue(dev, ntx)->qdisc_sleeping);
145145
spin_lock_bh(qdisc_lock(qdisc));
146146

147147
gnet_stats_add_basic(&sch->bstats, qdisc->cpu_bstats,
@@ -202,7 +202,7 @@ static struct Qdisc *mq_leaf(struct Qdisc *sch, unsigned long cl)
202202
{
203203
struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
204204

205-
return dev_queue->qdisc_sleeping;
205+
return rtnl_dereference(dev_queue->qdisc_sleeping);
206206
}
207207

208208
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,
221221

222222
tcm->tcm_parent = TC_H_ROOT;
223223
tcm->tcm_handle |= TC_H_MIN(cl);
224-
tcm->tcm_info = dev_queue->qdisc_sleeping->handle;
224+
tcm->tcm_info = rtnl_dereference(dev_queue->qdisc_sleeping)->handle;
225225
return 0;
226226
}
227227

@@ -230,7 +230,7 @@ static int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
230230
{
231231
struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
232232

233-
sch = dev_queue->qdisc_sleeping;
233+
sch = rtnl_dereference(dev_queue->qdisc_sleeping);
234234
if (gnet_stats_copy_basic(d, sch->cpu_bstats, &sch->bstats, true) < 0 ||
235235
qdisc_qstats_copy(d, sch) < 0)
236236
return -1;

net/sched/sch_mqprio.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb)
557557
* qdisc totals are added at end.
558558
*/
559559
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
560-
qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping;
560+
qdisc = rtnl_dereference(netdev_get_tx_queue(dev, ntx)->qdisc_sleeping);
561561
spin_lock_bh(qdisc_lock(qdisc));
562562

563563
gnet_stats_add_basic(&sch->bstats, qdisc->cpu_bstats,
@@ -604,7 +604,7 @@ static struct Qdisc *mqprio_leaf(struct Qdisc *sch, unsigned long cl)
604604
if (!dev_queue)
605605
return NULL;
606606

607-
return dev_queue->qdisc_sleeping;
607+
return rtnl_dereference(dev_queue->qdisc_sleeping);
608608
}
609609

610610
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,
637637
tcm->tcm_parent = (tc < 0) ? 0 :
638638
TC_H_MAKE(TC_H_MAJ(sch->handle),
639639
TC_H_MIN(tc + TC_H_MIN_PRIORITY));
640-
tcm->tcm_info = dev_queue->qdisc_sleeping->handle;
640+
tcm->tcm_info = rtnl_dereference(dev_queue->qdisc_sleeping)->handle;
641641
} else {
642642
tcm->tcm_parent = TC_H_ROOT;
643643
tcm->tcm_info = 0;
@@ -693,7 +693,7 @@ static int mqprio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
693693
} else {
694694
struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl);
695695

696-
sch = dev_queue->qdisc_sleeping;
696+
sch = rtnl_dereference(dev_queue->qdisc_sleeping);
697697
if (gnet_stats_copy_basic(d, sch->cpu_bstats,
698698
&sch->bstats, true) < 0 ||
699699
qdisc_qstats_copy(d, sch) < 0)

net/sched/sch_pie.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,15 +421,18 @@ static void pie_timer(struct timer_list *t)
421421
{
422422
struct pie_sched_data *q = from_timer(q, t, adapt_timer);
423423
struct Qdisc *sch = q->sch;
424-
spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
424+
spinlock_t *root_lock;
425425

426+
rcu_read_lock();
427+
root_lock = qdisc_lock(qdisc_root_sleeping(sch));
426428
spin_lock(root_lock);
427429
pie_calculate_probability(&q->params, &q->vars, sch->qstats.backlog);
428430

429431
/* reset the timer to fire after 'tupdate'. tupdate is in jiffies. */
430432
if (q->params.tupdate)
431433
mod_timer(&q->adapt_timer, jiffies + q->params.tupdate);
432434
spin_unlock(root_lock);
435+
rcu_read_unlock();
433436
}
434437

435438
static int pie_init(struct Qdisc *sch, struct nlattr *opt,

net/sched/sch_red.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,12 +321,15 @@ static inline void red_adaptative_timer(struct timer_list *t)
321321
{
322322
struct red_sched_data *q = from_timer(q, t, adapt_timer);
323323
struct Qdisc *sch = q->sch;
324-
spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
324+
spinlock_t *root_lock;
325325

326+
rcu_read_lock();
327+
root_lock = qdisc_lock(qdisc_root_sleeping(sch));
326328
spin_lock(root_lock);
327329
red_adaptative_algo(&q->parms, &q->vars);
328330
mod_timer(&q->adapt_timer, jiffies + HZ/2);
329331
spin_unlock(root_lock);
332+
rcu_read_unlock();
330333
}
331334

332335
static int red_init(struct Qdisc *sch, struct nlattr *opt,

0 commit comments

Comments
 (0)