diff options
Diffstat (limited to 'kernel/rcu/tree.c')
| -rw-r--r-- | kernel/rcu/tree.c | 104 |
1 files changed, 92 insertions, 12 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 0dda57a28276..12838a9a128e 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c | |||
| @@ -1207,6 +1207,22 @@ static int rcu_is_cpu_rrupt_from_idle(void) | |||
| 1207 | } | 1207 | } |
| 1208 | 1208 | ||
| 1209 | /* | 1209 | /* |
| 1210 | * We are reporting a quiescent state on behalf of some other CPU, so | ||
| 1211 | * it is our responsibility to check for and handle potential overflow | ||
| 1212 | * of the rcu_node ->gpnum counter with respect to the rcu_data counters. | ||
| 1213 | * After all, the CPU might be in deep idle state, and thus executing no | ||
| 1214 | * code whatsoever. | ||
| 1215 | */ | ||
| 1216 | static void rcu_gpnum_ovf(struct rcu_node *rnp, struct rcu_data *rdp) | ||
| 1217 | { | ||
| 1218 | lockdep_assert_held(&rnp->lock); | ||
| 1219 | if (ULONG_CMP_LT(READ_ONCE(rdp->gpnum) + ULONG_MAX / 4, rnp->gpnum)) | ||
| 1220 | WRITE_ONCE(rdp->gpwrap, true); | ||
| 1221 | if (ULONG_CMP_LT(rdp->rcu_iw_gpnum + ULONG_MAX / 4, rnp->gpnum)) | ||
| 1222 | rdp->rcu_iw_gpnum = rnp->gpnum + ULONG_MAX / 4; | ||
| 1223 | } | ||
| 1224 | |||
| 1225 | /* | ||
| 1210 | * Snapshot the specified CPU's dynticks counter so that we can later | 1226 | * Snapshot the specified CPU's dynticks counter so that we can later |
| 1211 | * credit them with an implicit quiescent state. Return 1 if this CPU | 1227 | * credit them with an implicit quiescent state. Return 1 if this CPU |
| 1212 | * is in dynticks idle mode, which is an extended quiescent state. | 1228 | * is in dynticks idle mode, which is an extended quiescent state. |
| @@ -1216,15 +1232,34 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp) | |||
| 1216 | rdp->dynticks_snap = rcu_dynticks_snap(rdp->dynticks); | 1232 | rdp->dynticks_snap = rcu_dynticks_snap(rdp->dynticks); |
| 1217 | if (rcu_dynticks_in_eqs(rdp->dynticks_snap)) { | 1233 | if (rcu_dynticks_in_eqs(rdp->dynticks_snap)) { |
| 1218 | trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("dti")); | 1234 | trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("dti")); |
| 1219 | if (ULONG_CMP_LT(READ_ONCE(rdp->gpnum) + ULONG_MAX / 4, | 1235 | rcu_gpnum_ovf(rdp->mynode, rdp); |
| 1220 | rdp->mynode->gpnum)) | ||
| 1221 | WRITE_ONCE(rdp->gpwrap, true); | ||
| 1222 | return 1; | 1236 | return 1; |
| 1223 | } | 1237 | } |
| 1224 | return 0; | 1238 | return 0; |
| 1225 | } | 1239 | } |
| 1226 | 1240 | ||
| 1227 | /* | 1241 | /* |
| 1242 | * Handler for the irq_work request posted when a grace period has | ||
| 1243 | * gone on for too long, but not yet long enough for an RCU CPU | ||
| 1244 | * stall warning. Set state appropriately, but just complain if | ||
| 1245 | * there is unexpected state on entry. | ||
| 1246 | */ | ||
| 1247 | static void rcu_iw_handler(struct irq_work *iwp) | ||
| 1248 | { | ||
| 1249 | struct rcu_data *rdp; | ||
| 1250 | struct rcu_node *rnp; | ||
| 1251 | |||
| 1252 | rdp = container_of(iwp, struct rcu_data, rcu_iw); | ||
| 1253 | rnp = rdp->mynode; | ||
| 1254 | raw_spin_lock_rcu_node(rnp); | ||
| 1255 | if (!WARN_ON_ONCE(!rdp->rcu_iw_pending)) { | ||
| 1256 | rdp->rcu_iw_gpnum = rnp->gpnum; | ||
| 1257 | rdp->rcu_iw_pending = false; | ||
| 1258 | } | ||
| 1259 | raw_spin_unlock_rcu_node(rnp); | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | /* | ||
| 1228 | * Return true if the specified CPU has passed through a quiescent | 1263 | * Return true if the specified CPU has passed through a quiescent |
| 1229 | * state by virtue of being in or having passed through an dynticks | 1264 | * state by virtue of being in or having passed through an dynticks |
| 1230 | * idle state since the last call to dyntick_save_progress_counter() | 1265 | * idle state since the last call to dyntick_save_progress_counter() |
| @@ -1235,7 +1270,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) | |||
| 1235 | unsigned long jtsq; | 1270 | unsigned long jtsq; |
| 1236 | bool *rnhqp; | 1271 | bool *rnhqp; |
| 1237 | bool *ruqp; | 1272 | bool *ruqp; |
| 1238 | struct rcu_node *rnp; | 1273 | struct rcu_node *rnp = rdp->mynode; |
| 1239 | 1274 | ||
| 1240 | /* | 1275 | /* |
| 1241 | * If the CPU passed through or entered a dynticks idle phase with | 1276 | * If the CPU passed through or entered a dynticks idle phase with |
| @@ -1248,6 +1283,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) | |||
| 1248 | if (rcu_dynticks_in_eqs_since(rdp->dynticks, rdp->dynticks_snap)) { | 1283 | if (rcu_dynticks_in_eqs_since(rdp->dynticks, rdp->dynticks_snap)) { |
| 1249 | trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("dti")); | 1284 | trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("dti")); |
| 1250 | rdp->dynticks_fqs++; | 1285 | rdp->dynticks_fqs++; |
| 1286 | rcu_gpnum_ovf(rnp, rdp); | ||
| 1251 | return 1; | 1287 | return 1; |
| 1252 | } | 1288 | } |
| 1253 | 1289 | ||
| @@ -1258,12 +1294,12 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) | |||
| 1258 | * might not be the case for nohz_full CPUs looping in the kernel. | 1294 | * might not be the case for nohz_full CPUs looping in the kernel. |
| 1259 | */ | 1295 | */ |
| 1260 | jtsq = jiffies_till_sched_qs; | 1296 | jtsq = jiffies_till_sched_qs; |
| 1261 | rnp = rdp->mynode; | ||
| 1262 | ruqp = per_cpu_ptr(&rcu_dynticks.rcu_urgent_qs, rdp->cpu); | 1297 | ruqp = per_cpu_ptr(&rcu_dynticks.rcu_urgent_qs, rdp->cpu); |
| 1263 | if (time_after(jiffies, rdp->rsp->gp_start + jtsq) && | 1298 | if (time_after(jiffies, rdp->rsp->gp_start + jtsq) && |
| 1264 | READ_ONCE(rdp->rcu_qs_ctr_snap) != per_cpu(rcu_dynticks.rcu_qs_ctr, rdp->cpu) && | 1299 | READ_ONCE(rdp->rcu_qs_ctr_snap) != per_cpu(rcu_dynticks.rcu_qs_ctr, rdp->cpu) && |
| 1265 | READ_ONCE(rdp->gpnum) == rnp->gpnum && !rdp->gpwrap) { | 1300 | READ_ONCE(rdp->gpnum) == rnp->gpnum && !rdp->gpwrap) { |
| 1266 | trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("rqc")); | 1301 | trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("rqc")); |
| 1302 | rcu_gpnum_ovf(rnp, rdp); | ||
| 1267 | return 1; | 1303 | return 1; |
| 1268 | } else if (time_after(jiffies, rdp->rsp->gp_start + jtsq)) { | 1304 | } else if (time_after(jiffies, rdp->rsp->gp_start + jtsq)) { |
| 1269 | /* Load rcu_qs_ctr before store to rcu_urgent_qs. */ | 1305 | /* Load rcu_qs_ctr before store to rcu_urgent_qs. */ |
| @@ -1274,6 +1310,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) | |||
| 1274 | if (!(rdp->grpmask & rcu_rnp_online_cpus(rnp))) { | 1310 | if (!(rdp->grpmask & rcu_rnp_online_cpus(rnp))) { |
| 1275 | trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("ofl")); | 1311 | trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("ofl")); |
| 1276 | rdp->offline_fqs++; | 1312 | rdp->offline_fqs++; |
| 1313 | rcu_gpnum_ovf(rnp, rdp); | ||
| 1277 | return 1; | 1314 | return 1; |
| 1278 | } | 1315 | } |
| 1279 | 1316 | ||
| @@ -1305,11 +1342,22 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp) | |||
| 1305 | } | 1342 | } |
| 1306 | 1343 | ||
| 1307 | /* | 1344 | /* |
| 1308 | * If more than halfway to RCU CPU stall-warning time, do | 1345 | * If more than halfway to RCU CPU stall-warning time, do a |
| 1309 | * a resched_cpu() to try to loosen things up a bit. | 1346 | * resched_cpu() to try to loosen things up a bit. Also check to |
| 1347 | * see if the CPU is getting hammered with interrupts, but only | ||
| 1348 | * once per grace period, just to keep the IPIs down to a dull roar. | ||
| 1310 | */ | 1349 | */ |
| 1311 | if (jiffies - rdp->rsp->gp_start > rcu_jiffies_till_stall_check() / 2) | 1350 | if (jiffies - rdp->rsp->gp_start > rcu_jiffies_till_stall_check() / 2) { |
| 1312 | resched_cpu(rdp->cpu); | 1351 | resched_cpu(rdp->cpu); |
| 1352 | if (IS_ENABLED(CONFIG_IRQ_WORK) && | ||
| 1353 | !rdp->rcu_iw_pending && rdp->rcu_iw_gpnum != rnp->gpnum && | ||
| 1354 | (rnp->ffmask & rdp->grpmask)) { | ||
| 1355 | init_irq_work(&rdp->rcu_iw, rcu_iw_handler); | ||
| 1356 | rdp->rcu_iw_pending = true; | ||
| 1357 | rdp->rcu_iw_gpnum = rnp->gpnum; | ||
| 1358 | irq_work_queue_on(&rdp->rcu_iw, rdp->cpu); | ||
| 1359 | } | ||
| 1360 | } | ||
| 1313 | 1361 | ||
| 1314 | return 0; | 1362 | return 0; |
| 1315 | } | 1363 | } |
| @@ -1498,6 +1546,7 @@ static void print_cpu_stall(struct rcu_state *rsp) | |||
| 1498 | { | 1546 | { |
| 1499 | int cpu; | 1547 | int cpu; |
| 1500 | unsigned long flags; | 1548 | unsigned long flags; |
| 1549 | struct rcu_data *rdp = this_cpu_ptr(rsp->rda); | ||
| 1501 | struct rcu_node *rnp = rcu_get_root(rsp); | 1550 | struct rcu_node *rnp = rcu_get_root(rsp); |
| 1502 | long totqlen = 0; | 1551 | long totqlen = 0; |
| 1503 | 1552 | ||
| @@ -1513,7 +1562,9 @@ static void print_cpu_stall(struct rcu_state *rsp) | |||
| 1513 | */ | 1562 | */ |
| 1514 | pr_err("INFO: %s self-detected stall on CPU", rsp->name); | 1563 | pr_err("INFO: %s self-detected stall on CPU", rsp->name); |
| 1515 | print_cpu_stall_info_begin(); | 1564 | print_cpu_stall_info_begin(); |
| 1565 | raw_spin_lock_irqsave_rcu_node(rdp->mynode, flags); | ||
| 1516 | print_cpu_stall_info(rsp, smp_processor_id()); | 1566 | print_cpu_stall_info(rsp, smp_processor_id()); |
| 1567 | raw_spin_unlock_irqrestore_rcu_node(rdp->mynode, flags); | ||
| 1517 | print_cpu_stall_info_end(); | 1568 | print_cpu_stall_info_end(); |
| 1518 | for_each_possible_cpu(cpu) | 1569 | for_each_possible_cpu(cpu) |
| 1519 | totqlen += rcu_segcblist_n_cbs(&per_cpu_ptr(rsp->rda, | 1570 | totqlen += rcu_segcblist_n_cbs(&per_cpu_ptr(rsp->rda, |
| @@ -1907,6 +1958,7 @@ static bool __note_gp_changes(struct rcu_state *rsp, struct rcu_node *rnp, | |||
| 1907 | rdp->core_needs_qs = need_gp; | 1958 | rdp->core_needs_qs = need_gp; |
| 1908 | zero_cpu_stall_ticks(rdp); | 1959 | zero_cpu_stall_ticks(rdp); |
| 1909 | WRITE_ONCE(rdp->gpwrap, false); | 1960 | WRITE_ONCE(rdp->gpwrap, false); |
| 1961 | rcu_gpnum_ovf(rnp, rdp); | ||
| 1910 | } | 1962 | } |
| 1911 | return ret; | 1963 | return ret; |
| 1912 | } | 1964 | } |
| @@ -3685,6 +3737,8 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp) | |||
| 3685 | rdp->cpu_no_qs.b.norm = true; | 3737 | rdp->cpu_no_qs.b.norm = true; |
| 3686 | rdp->rcu_qs_ctr_snap = per_cpu(rcu_dynticks.rcu_qs_ctr, cpu); | 3738 | rdp->rcu_qs_ctr_snap = per_cpu(rcu_dynticks.rcu_qs_ctr, cpu); |
| 3687 | rdp->core_needs_qs = false; | 3739 | rdp->core_needs_qs = false; |
| 3740 | rdp->rcu_iw_pending = false; | ||
| 3741 | rdp->rcu_iw_gpnum = rnp->gpnum - 1; | ||
| 3688 | trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("cpuonl")); | 3742 | trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("cpuonl")); |
| 3689 | raw_spin_unlock_irqrestore_rcu_node(rnp, flags); | 3743 | raw_spin_unlock_irqrestore_rcu_node(rnp, flags); |
| 3690 | } | 3744 | } |
| @@ -3722,10 +3776,24 @@ static void rcutree_affinity_setting(unsigned int cpu, int outgoing) | |||
| 3722 | */ | 3776 | */ |
| 3723 | int rcutree_online_cpu(unsigned int cpu) | 3777 | int rcutree_online_cpu(unsigned int cpu) |
| 3724 | { | 3778 | { |
| 3725 | sync_sched_exp_online_cleanup(cpu); | 3779 | unsigned long flags; |
| 3726 | rcutree_affinity_setting(cpu, -1); | 3780 | struct rcu_data *rdp; |
| 3781 | struct rcu_node *rnp; | ||
| 3782 | struct rcu_state *rsp; | ||
| 3783 | |||
| 3784 | for_each_rcu_flavor(rsp) { | ||
| 3785 | rdp = per_cpu_ptr(rsp->rda, cpu); | ||
| 3786 | rnp = rdp->mynode; | ||
| 3787 | raw_spin_lock_irqsave_rcu_node(rnp, flags); | ||
| 3788 | rnp->ffmask |= rdp->grpmask; | ||
| 3789 | raw_spin_unlock_irqrestore_rcu_node(rnp, flags); | ||
| 3790 | } | ||
| 3727 | if (IS_ENABLED(CONFIG_TREE_SRCU)) | 3791 | if (IS_ENABLED(CONFIG_TREE_SRCU)) |
| 3728 | srcu_online_cpu(cpu); | 3792 | srcu_online_cpu(cpu); |
| 3793 | if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE) | ||
| 3794 | return 0; /* Too early in boot for scheduler work. */ | ||
| 3795 | sync_sched_exp_online_cleanup(cpu); | ||
| 3796 | rcutree_affinity_setting(cpu, -1); | ||
| 3729 | return 0; | 3797 | return 0; |
| 3730 | } | 3798 | } |
| 3731 | 3799 | ||
| @@ -3735,6 +3803,19 @@ int rcutree_online_cpu(unsigned int cpu) | |||
| 3735 | */ | 3803 | */ |
| 3736 | int rcutree_offline_cpu(unsigned int cpu) | 3804 | int rcutree_offline_cpu(unsigned int cpu) |
| 3737 | { | 3805 | { |
| 3806 | unsigned long flags; | ||
| 3807 | struct rcu_data *rdp; | ||
| 3808 | struct rcu_node *rnp; | ||
| 3809 | struct rcu_state *rsp; | ||
| 3810 | |||
| 3811 | for_each_rcu_flavor(rsp) { | ||
| 3812 | rdp = per_cpu_ptr(rsp->rda, cpu); | ||
| 3813 | rnp = rdp->mynode; | ||
| 3814 | raw_spin_lock_irqsave_rcu_node(rnp, flags); | ||
| 3815 | rnp->ffmask &= ~rdp->grpmask; | ||
| 3816 | raw_spin_unlock_irqrestore_rcu_node(rnp, flags); | ||
| 3817 | } | ||
| 3818 | |||
| 3738 | rcutree_affinity_setting(cpu, cpu); | 3819 | rcutree_affinity_setting(cpu, cpu); |
| 3739 | if (IS_ENABLED(CONFIG_TREE_SRCU)) | 3820 | if (IS_ENABLED(CONFIG_TREE_SRCU)) |
| 3740 | srcu_offline_cpu(cpu); | 3821 | srcu_offline_cpu(cpu); |
| @@ -4183,8 +4264,7 @@ void __init rcu_init(void) | |||
| 4183 | for_each_online_cpu(cpu) { | 4264 | for_each_online_cpu(cpu) { |
| 4184 | rcutree_prepare_cpu(cpu); | 4265 | rcutree_prepare_cpu(cpu); |
| 4185 | rcu_cpu_starting(cpu); | 4266 | rcu_cpu_starting(cpu); |
| 4186 | if (IS_ENABLED(CONFIG_TREE_SRCU)) | 4267 | rcutree_online_cpu(cpu); |
| 4187 | srcu_online_cpu(cpu); | ||
| 4188 | } | 4268 | } |
| 4189 | } | 4269 | } |
| 4190 | 4270 | ||
