diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2010-02-22 20:05:01 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-02-25 04:34:57 -0500 |
commit | 20133cfce7d0bbdcc0c398301030c091f5675c88 (patch) | |
tree | 337f242bfc89f5880cf86234fa6b574f52a2f0a5 | |
parent | 1bd22e374b20c2f0ba1d2723c1f585acab2251c5 (diff) |
rcu: Stop overflowing signed integers
The C standard does not specify the result of an operation that
overflows a signed integer, so such operations need to be
avoided. This patch changes the type of several fields from
"long" to "unsigned long" and adjusts operations as needed.
ULONG_CMP_GE() and ULONG_CMP_LT() macros are introduced to do
the modular comparisons that are appropriate given that overflow
is an expected event.
Acked-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: laijs@cn.fujitsu.com
Cc: dipankar@in.ibm.com
Cc: mathieu.desnoyers@polymtl.ca
Cc: josh@joshtriplett.org
Cc: dvhltc@us.ibm.com
Cc: niv@us.ibm.com
Cc: peterz@infradead.org
Cc: rostedt@goodmis.org
Cc: Valdis.Kletnieks@vt.edu
Cc: dhowells@redhat.com
LKML-Reference: <1266887105-1528-17-git-send-email-paulmck@linux.vnet.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | kernel/rcutree.c | 11 | ||||
-rw-r--r-- | kernel/rcutree.h | 33 | ||||
-rw-r--r-- | kernel/rcutree_trace.c | 14 |
3 files changed, 30 insertions, 28 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 29d88c08d875..dd0d31dffcdc 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -500,7 +500,7 @@ static void print_cpu_stall(struct rcu_state *rsp) | |||
500 | trigger_all_cpu_backtrace(); | 500 | trigger_all_cpu_backtrace(); |
501 | 501 | ||
502 | spin_lock_irqsave(&rnp->lock, flags); | 502 | spin_lock_irqsave(&rnp->lock, flags); |
503 | if ((long)(jiffies - rsp->jiffies_stall) >= 0) | 503 | if (ULONG_CMP_GE(jiffies, rsp->jiffies_stall)) |
504 | rsp->jiffies_stall = | 504 | rsp->jiffies_stall = |
505 | jiffies + RCU_SECONDS_TILL_STALL_RECHECK; | 505 | jiffies + RCU_SECONDS_TILL_STALL_RECHECK; |
506 | spin_unlock_irqrestore(&rnp->lock, flags); | 506 | spin_unlock_irqrestore(&rnp->lock, flags); |
@@ -1216,8 +1216,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed) | |||
1216 | rsp->n_force_qs_lh++; /* Inexact, can lose counts. Tough! */ | 1216 | rsp->n_force_qs_lh++; /* Inexact, can lose counts. Tough! */ |
1217 | return; /* Someone else is already on the job. */ | 1217 | return; /* Someone else is already on the job. */ |
1218 | } | 1218 | } |
1219 | if (relaxed && | 1219 | if (relaxed && ULONG_CMP_GE(rsp->jiffies_force_qs, jiffies)) |
1220 | (long)(rsp->jiffies_force_qs - jiffies) >= 0) | ||
1221 | goto unlock_fqs_ret; /* no emergency and done recently. */ | 1220 | goto unlock_fqs_ret; /* no emergency and done recently. */ |
1222 | rsp->n_force_qs++; | 1221 | rsp->n_force_qs++; |
1223 | spin_lock(&rnp->lock); /* irqs already disabled */ | 1222 | spin_lock(&rnp->lock); /* irqs already disabled */ |
@@ -1295,7 +1294,7 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1295 | * If an RCU GP has gone long enough, go check for dyntick | 1294 | * If an RCU GP has gone long enough, go check for dyntick |
1296 | * idle CPUs and, if needed, send resched IPIs. | 1295 | * idle CPUs and, if needed, send resched IPIs. |
1297 | */ | 1296 | */ |
1298 | if ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0) | 1297 | if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies)) |
1299 | force_quiescent_state(rsp, 1); | 1298 | force_quiescent_state(rsp, 1); |
1300 | 1299 | ||
1301 | /* | 1300 | /* |
@@ -1392,7 +1391,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), | |||
1392 | force_quiescent_state(rsp, 0); | 1391 | force_quiescent_state(rsp, 0); |
1393 | rdp->n_force_qs_snap = rsp->n_force_qs; | 1392 | rdp->n_force_qs_snap = rsp->n_force_qs; |
1394 | rdp->qlen_last_fqs_check = rdp->qlen; | 1393 | rdp->qlen_last_fqs_check = rdp->qlen; |
1395 | } else if ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0) | 1394 | } else if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies)) |
1396 | force_quiescent_state(rsp, 1); | 1395 | force_quiescent_state(rsp, 1); |
1397 | local_irq_restore(flags); | 1396 | local_irq_restore(flags); |
1398 | } | 1397 | } |
@@ -1525,7 +1524,7 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp) | |||
1525 | 1524 | ||
1526 | /* Has an RCU GP gone long enough to send resched IPIs &c? */ | 1525 | /* Has an RCU GP gone long enough to send resched IPIs &c? */ |
1527 | if (rcu_gp_in_progress(rsp) && | 1526 | if (rcu_gp_in_progress(rsp) && |
1528 | ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0)) { | 1527 | ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies)) { |
1529 | rdp->n_rp_need_fqs++; | 1528 | rdp->n_rp_need_fqs++; |
1530 | return 1; | 1529 | return 1; |
1531 | } | 1530 | } |
diff --git a/kernel/rcutree.h b/kernel/rcutree.h index d9d032abd665..7495fed49c30 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h | |||
@@ -92,10 +92,10 @@ struct rcu_dynticks { | |||
92 | struct rcu_node { | 92 | struct rcu_node { |
93 | spinlock_t lock; /* Root rcu_node's lock protects some */ | 93 | spinlock_t lock; /* Root rcu_node's lock protects some */ |
94 | /* rcu_state fields as well as following. */ | 94 | /* rcu_state fields as well as following. */ |
95 | long gpnum; /* Current grace period for this node. */ | 95 | unsigned long gpnum; /* Current grace period for this node. */ |
96 | /* This will either be equal to or one */ | 96 | /* This will either be equal to or one */ |
97 | /* behind the root rcu_node's gpnum. */ | 97 | /* behind the root rcu_node's gpnum. */ |
98 | long completed; /* Last grace period completed for this node. */ | 98 | unsigned long completed; /* Last GP completed for this node. */ |
99 | /* This will either be equal to or one */ | 99 | /* This will either be equal to or one */ |
100 | /* behind the root rcu_node's gpnum. */ | 100 | /* behind the root rcu_node's gpnum. */ |
101 | unsigned long qsmask; /* CPUs or groups that need to switch in */ | 101 | unsigned long qsmask; /* CPUs or groups that need to switch in */ |
@@ -161,11 +161,11 @@ struct rcu_node { | |||
161 | /* Per-CPU data for read-copy update. */ | 161 | /* Per-CPU data for read-copy update. */ |
162 | struct rcu_data { | 162 | struct rcu_data { |
163 | /* 1) quiescent-state and grace-period handling : */ | 163 | /* 1) quiescent-state and grace-period handling : */ |
164 | long completed; /* Track rsp->completed gp number */ | 164 | unsigned long completed; /* Track rsp->completed gp number */ |
165 | /* in order to detect GP end. */ | 165 | /* in order to detect GP end. */ |
166 | long gpnum; /* Highest gp number that this CPU */ | 166 | unsigned long gpnum; /* Highest gp number that this CPU */ |
167 | /* is aware of having started. */ | 167 | /* is aware of having started. */ |
168 | long passed_quiesc_completed; | 168 | unsigned long passed_quiesc_completed; |
169 | /* Value of completed at time of qs. */ | 169 | /* Value of completed at time of qs. */ |
170 | bool passed_quiesc; /* User-mode/idle loop etc. */ | 170 | bool passed_quiesc; /* User-mode/idle loop etc. */ |
171 | bool qs_pending; /* Core waits for quiesc state. */ | 171 | bool qs_pending; /* Core waits for quiesc state. */ |
@@ -221,14 +221,14 @@ struct rcu_data { | |||
221 | unsigned long resched_ipi; /* Sent a resched IPI. */ | 221 | unsigned long resched_ipi; /* Sent a resched IPI. */ |
222 | 222 | ||
223 | /* 5) __rcu_pending() statistics. */ | 223 | /* 5) __rcu_pending() statistics. */ |
224 | long n_rcu_pending; /* rcu_pending() calls since boot. */ | 224 | unsigned long n_rcu_pending; /* rcu_pending() calls since boot. */ |
225 | long n_rp_qs_pending; | 225 | unsigned long n_rp_qs_pending; |
226 | long n_rp_cb_ready; | 226 | unsigned long n_rp_cb_ready; |
227 | long n_rp_cpu_needs_gp; | 227 | unsigned long n_rp_cpu_needs_gp; |
228 | long n_rp_gp_completed; | 228 | unsigned long n_rp_gp_completed; |
229 | long n_rp_gp_started; | 229 | unsigned long n_rp_gp_started; |
230 | long n_rp_need_fqs; | 230 | unsigned long n_rp_need_fqs; |
231 | long n_rp_need_nothing; | 231 | unsigned long n_rp_need_nothing; |
232 | 232 | ||
233 | int cpu; | 233 | int cpu; |
234 | }; | 234 | }; |
@@ -255,6 +255,9 @@ struct rcu_data { | |||
255 | 255 | ||
256 | #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ | 256 | #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ |
257 | 257 | ||
258 | #define ULONG_CMP_GE(a, b) (ULONG_MAX / 2 >= (a) - (b)) | ||
259 | #define ULONG_CMP_LT(a, b) (ULONG_MAX / 2 < (a) - (b)) | ||
260 | |||
258 | /* | 261 | /* |
259 | * RCU global state, including node hierarchy. This hierarchy is | 262 | * RCU global state, including node hierarchy. This hierarchy is |
260 | * represented in "heap" form in a dense array. The root (first level) | 263 | * represented in "heap" form in a dense array. The root (first level) |
@@ -283,8 +286,8 @@ struct rcu_state { | |||
283 | /* period because */ | 286 | /* period because */ |
284 | /* force_quiescent_state() */ | 287 | /* force_quiescent_state() */ |
285 | /* was running. */ | 288 | /* was running. */ |
286 | long gpnum; /* Current gp number. */ | 289 | unsigned long gpnum; /* Current gp number. */ |
287 | long completed; /* # of last completed gp. */ | 290 | unsigned long completed; /* # of last completed gp. */ |
288 | 291 | ||
289 | /* End of fields guarded by root rcu_node's lock. */ | 292 | /* End of fields guarded by root rcu_node's lock. */ |
290 | 293 | ||
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 9d2c88423b31..d45db2e35d27 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c | |||
@@ -50,7 +50,7 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) | |||
50 | { | 50 | { |
51 | if (!rdp->beenonline) | 51 | if (!rdp->beenonline) |
52 | return; | 52 | return; |
53 | seq_printf(m, "%3d%cc=%ld g=%ld pq=%d pqc=%ld qp=%d", | 53 | seq_printf(m, "%3d%cc=%lu g=%lu pq=%d pqc=%lu qp=%d", |
54 | rdp->cpu, | 54 | rdp->cpu, |
55 | cpu_is_offline(rdp->cpu) ? '!' : ' ', | 55 | cpu_is_offline(rdp->cpu) ? '!' : ' ', |
56 | rdp->completed, rdp->gpnum, | 56 | rdp->completed, rdp->gpnum, |
@@ -105,7 +105,7 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp) | |||
105 | { | 105 | { |
106 | if (!rdp->beenonline) | 106 | if (!rdp->beenonline) |
107 | return; | 107 | return; |
108 | seq_printf(m, "%d,%s,%ld,%ld,%d,%ld,%d", | 108 | seq_printf(m, "%d,%s,%lu,%lu,%d,%lu,%d", |
109 | rdp->cpu, | 109 | rdp->cpu, |
110 | cpu_is_offline(rdp->cpu) ? "\"N\"" : "\"Y\"", | 110 | cpu_is_offline(rdp->cpu) ? "\"N\"" : "\"Y\"", |
111 | rdp->completed, rdp->gpnum, | 111 | rdp->completed, rdp->gpnum, |
@@ -155,13 +155,13 @@ static const struct file_operations rcudata_csv_fops = { | |||
155 | 155 | ||
156 | static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) | 156 | static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) |
157 | { | 157 | { |
158 | long gpnum; | 158 | unsigned long gpnum; |
159 | int level = 0; | 159 | int level = 0; |
160 | int phase; | 160 | int phase; |
161 | struct rcu_node *rnp; | 161 | struct rcu_node *rnp; |
162 | 162 | ||
163 | gpnum = rsp->gpnum; | 163 | gpnum = rsp->gpnum; |
164 | seq_printf(m, "c=%ld g=%ld s=%d jfq=%ld j=%x " | 164 | seq_printf(m, "c=%lu g=%lu s=%d jfq=%ld j=%x " |
165 | "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld\n", | 165 | "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld\n", |
166 | rsp->completed, gpnum, rsp->signaled, | 166 | rsp->completed, gpnum, rsp->signaled, |
167 | (long)(rsp->jiffies_force_qs - jiffies), | 167 | (long)(rsp->jiffies_force_qs - jiffies), |
@@ -215,12 +215,12 @@ static const struct file_operations rcuhier_fops = { | |||
215 | static int show_rcugp(struct seq_file *m, void *unused) | 215 | static int show_rcugp(struct seq_file *m, void *unused) |
216 | { | 216 | { |
217 | #ifdef CONFIG_TREE_PREEMPT_RCU | 217 | #ifdef CONFIG_TREE_PREEMPT_RCU |
218 | seq_printf(m, "rcu_preempt: completed=%ld gpnum=%ld\n", | 218 | seq_printf(m, "rcu_preempt: completed=%ld gpnum=%lu\n", |
219 | rcu_preempt_state.completed, rcu_preempt_state.gpnum); | 219 | rcu_preempt_state.completed, rcu_preempt_state.gpnum); |
220 | #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ | 220 | #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */ |
221 | seq_printf(m, "rcu_sched: completed=%ld gpnum=%ld\n", | 221 | seq_printf(m, "rcu_sched: completed=%ld gpnum=%lu\n", |
222 | rcu_sched_state.completed, rcu_sched_state.gpnum); | 222 | rcu_sched_state.completed, rcu_sched_state.gpnum); |
223 | seq_printf(m, "rcu_bh: completed=%ld gpnum=%ld\n", | 223 | seq_printf(m, "rcu_bh: completed=%ld gpnum=%lu\n", |
224 | rcu_bh_state.completed, rcu_bh_state.gpnum); | 224 | rcu_bh_state.completed, rcu_bh_state.gpnum); |
225 | return 0; | 225 | return 0; |
226 | } | 226 | } |