diff options
| -rw-r--r-- | kernel/rcutree.h | 19 | ||||
| -rw-r--r-- | kernel/rcutree_plugin.h | 42 | ||||
| -rw-r--r-- | kernel/rcutree_trace.c | 68 |
3 files changed, 125 insertions, 4 deletions
diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 8db0cdc7f450..d49046c79c59 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h | |||
| @@ -152,6 +152,25 @@ struct rcu_node { | |||
| 152 | wait_queue_head_t boost_wq; | 152 | wait_queue_head_t boost_wq; |
| 153 | /* Wait queue on which to park the boost */ | 153 | /* Wait queue on which to park the boost */ |
| 154 | /* kthread. */ | 154 | /* kthread. */ |
| 155 | unsigned long n_tasks_boosted; | ||
| 156 | /* Total number of tasks boosted. */ | ||
| 157 | unsigned long n_exp_boosts; | ||
| 158 | /* Number of tasks boosted for expedited GP. */ | ||
| 159 | unsigned long n_normal_boosts; | ||
| 160 | /* Number of tasks boosted for normal GP. */ | ||
| 161 | unsigned long n_balk_blkd_tasks; | ||
| 162 | /* Refused to boost: no blocked tasks. */ | ||
| 163 | unsigned long n_balk_exp_gp_tasks; | ||
| 164 | /* Refused to boost: nothing blocking GP. */ | ||
| 165 | unsigned long n_balk_boost_tasks; | ||
| 166 | /* Refused to boost: already boosting. */ | ||
| 167 | unsigned long n_balk_notblocked; | ||
| 168 | /* Refused to boost: RCU RS CS still running. */ | ||
| 169 | unsigned long n_balk_notyet; | ||
| 170 | /* Refused to boost: not yet time. */ | ||
| 171 | unsigned long n_balk_nos; | ||
| 172 | /* Refused to boost: not sure why, though. */ | ||
| 173 | /* This can happen due to race conditions. */ | ||
| 155 | #endif /* #ifdef CONFIG_RCU_BOOST */ | 174 | #endif /* #ifdef CONFIG_RCU_BOOST */ |
| 156 | struct task_struct *node_kthread_task; | 175 | struct task_struct *node_kthread_task; |
| 157 | /* kthread that takes care of this rcu_node */ | 176 | /* kthread that takes care of this rcu_node */ |
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h index 4e486255df63..07d346445d12 100644 --- a/kernel/rcutree_plugin.h +++ b/kernel/rcutree_plugin.h | |||
| @@ -1073,6 +1073,33 @@ static void __init __rcu_init_preempt(void) | |||
| 1073 | 1073 | ||
| 1074 | #include "rtmutex_common.h" | 1074 | #include "rtmutex_common.h" |
| 1075 | 1075 | ||
| 1076 | #ifdef CONFIG_RCU_TRACE | ||
| 1077 | |||
| 1078 | static void rcu_initiate_boost_trace(struct rcu_node *rnp) | ||
| 1079 | { | ||
| 1080 | if (list_empty(&rnp->blkd_tasks)) | ||
| 1081 | rnp->n_balk_blkd_tasks++; | ||
| 1082 | else if (rnp->exp_tasks == NULL && rnp->gp_tasks == NULL) | ||
| 1083 | rnp->n_balk_exp_gp_tasks++; | ||
| 1084 | else if (rnp->gp_tasks != NULL && rnp->boost_tasks != NULL) | ||
| 1085 | rnp->n_balk_boost_tasks++; | ||
| 1086 | else if (rnp->gp_tasks != NULL && rnp->qsmask != 0) | ||
| 1087 | rnp->n_balk_notblocked++; | ||
| 1088 | else if (rnp->gp_tasks != NULL && | ||
| 1089 | ULONG_CMP_GE(jiffies, rnp->boost_time)) | ||
| 1090 | rnp->n_balk_notyet++; | ||
| 1091 | else | ||
| 1092 | rnp->n_balk_nos++; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | #else /* #ifdef CONFIG_RCU_TRACE */ | ||
| 1096 | |||
| 1097 | static void rcu_initiate_boost_trace(struct rcu_node *rnp) | ||
| 1098 | { | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | #endif /* #else #ifdef CONFIG_RCU_TRACE */ | ||
| 1102 | |||
| 1076 | /* | 1103 | /* |
| 1077 | * Carry out RCU priority boosting on the task indicated by ->exp_tasks | 1104 | * Carry out RCU priority boosting on the task indicated by ->exp_tasks |
| 1078 | * or ->boost_tasks, advancing the pointer to the next task in the | 1105 | * or ->boost_tasks, advancing the pointer to the next task in the |
| @@ -1108,10 +1135,14 @@ static int rcu_boost(struct rcu_node *rnp) | |||
| 1108 | * expedited grace period must boost all blocked tasks, including | 1135 | * expedited grace period must boost all blocked tasks, including |
| 1109 | * those blocking the pre-existing normal grace period. | 1136 | * those blocking the pre-existing normal grace period. |
| 1110 | */ | 1137 | */ |
| 1111 | if (rnp->exp_tasks != NULL) | 1138 | if (rnp->exp_tasks != NULL) { |
| 1112 | tb = rnp->exp_tasks; | 1139 | tb = rnp->exp_tasks; |
| 1113 | else | 1140 | rnp->n_exp_boosts++; |
| 1141 | } else { | ||
| 1114 | tb = rnp->boost_tasks; | 1142 | tb = rnp->boost_tasks; |
| 1143 | rnp->n_normal_boosts++; | ||
| 1144 | } | ||
| 1145 | rnp->n_tasks_boosted++; | ||
| 1115 | 1146 | ||
| 1116 | /* | 1147 | /* |
| 1117 | * We boost task t by manufacturing an rt_mutex that appears to | 1148 | * We boost task t by manufacturing an rt_mutex that appears to |
| @@ -1197,8 +1228,10 @@ static void rcu_initiate_boost(struct rcu_node *rnp) | |||
| 1197 | { | 1228 | { |
| 1198 | struct task_struct *t; | 1229 | struct task_struct *t; |
| 1199 | 1230 | ||
| 1200 | if (!rcu_preempt_blocked_readers_cgp(rnp) && rnp->exp_tasks == NULL) | 1231 | if (!rcu_preempt_blocked_readers_cgp(rnp) && rnp->exp_tasks == NULL) { |
| 1232 | rnp->n_balk_exp_gp_tasks++; | ||
| 1201 | return; | 1233 | return; |
| 1234 | } | ||
| 1202 | if (rnp->exp_tasks != NULL || | 1235 | if (rnp->exp_tasks != NULL || |
| 1203 | (rnp->gp_tasks != NULL && | 1236 | (rnp->gp_tasks != NULL && |
| 1204 | rnp->boost_tasks == NULL && | 1237 | rnp->boost_tasks == NULL && |
| @@ -1209,7 +1242,8 @@ static void rcu_initiate_boost(struct rcu_node *rnp) | |||
| 1209 | t = rnp->boost_kthread_task; | 1242 | t = rnp->boost_kthread_task; |
| 1210 | if (t != NULL) | 1243 | if (t != NULL) |
| 1211 | wake_up_process(t); | 1244 | wake_up_process(t); |
| 1212 | } | 1245 | } else |
| 1246 | rcu_initiate_boost_trace(rnp); | ||
| 1213 | } | 1247 | } |
| 1214 | 1248 | ||
| 1215 | /* | 1249 | /* |
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 1cedf94e2c4f..ead5736f99b5 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c | |||
| @@ -157,6 +157,71 @@ static const struct file_operations rcudata_csv_fops = { | |||
| 157 | .release = single_release, | 157 | .release = single_release, |
| 158 | }; | 158 | }; |
| 159 | 159 | ||
| 160 | #ifdef CONFIG_RCU_BOOST | ||
| 161 | |||
| 162 | static void print_one_rcu_node_boost(struct seq_file *m, struct rcu_node *rnp) | ||
| 163 | { | ||
| 164 | seq_printf(m, "%d:%d tasks=%c%c%c%c ntb=%lu neb=%lu nnb=%lu " | ||
| 165 | "j=%04x bt=%04x\n", | ||
| 166 | rnp->grplo, rnp->grphi, | ||
| 167 | "T."[list_empty(&rnp->blkd_tasks)], | ||
| 168 | "N."[!rnp->gp_tasks], | ||
| 169 | "E."[!rnp->exp_tasks], | ||
| 170 | "B."[!rnp->boost_tasks], | ||
| 171 | rnp->n_tasks_boosted, rnp->n_exp_boosts, | ||
| 172 | rnp->n_normal_boosts, | ||
| 173 | (int)(jiffies & 0xffff), | ||
| 174 | (int)(rnp->boost_time & 0xffff)); | ||
| 175 | seq_printf(m, "%s: nt=%lu egt=%lu bt=%lu nb=%lu ny=%lu nos=%lu\n", | ||
| 176 | " balk", | ||
| 177 | rnp->n_balk_blkd_tasks, | ||
| 178 | rnp->n_balk_exp_gp_tasks, | ||
| 179 | rnp->n_balk_boost_tasks, | ||
| 180 | rnp->n_balk_notblocked, | ||
| 181 | rnp->n_balk_notyet, | ||
| 182 | rnp->n_balk_nos); | ||
| 183 | } | ||
| 184 | |||
| 185 | static int show_rcu_node_boost(struct seq_file *m, void *unused) | ||
| 186 | { | ||
| 187 | struct rcu_node *rnp; | ||
| 188 | |||
| 189 | rcu_for_each_leaf_node(&rcu_preempt_state, rnp) | ||
| 190 | print_one_rcu_node_boost(m, rnp); | ||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | |||
| 194 | static int rcu_node_boost_open(struct inode *inode, struct file *file) | ||
| 195 | { | ||
| 196 | return single_open(file, show_rcu_node_boost, NULL); | ||
| 197 | } | ||
| 198 | |||
| 199 | static const struct file_operations rcu_node_boost_fops = { | ||
| 200 | .owner = THIS_MODULE, | ||
| 201 | .open = rcu_node_boost_open, | ||
| 202 | .read = seq_read, | ||
| 203 | .llseek = seq_lseek, | ||
| 204 | .release = single_release, | ||
| 205 | }; | ||
| 206 | |||
| 207 | /* | ||
| 208 | * Create the rcuboost debugfs entry. Standard error return. | ||
| 209 | */ | ||
| 210 | static int rcu_boost_trace_create_file(struct dentry *rcudir) | ||
| 211 | { | ||
| 212 | return !debugfs_create_file("rcuboost", 0444, rcudir, NULL, | ||
| 213 | &rcu_node_boost_fops); | ||
| 214 | } | ||
| 215 | |||
| 216 | #else /* #ifdef CONFIG_RCU_BOOST */ | ||
| 217 | |||
| 218 | static int rcu_boost_trace_create_file(struct dentry *rcudir) | ||
| 219 | { | ||
| 220 | return 0; /* There cannot be an error if we didn't create it! */ | ||
| 221 | } | ||
| 222 | |||
| 223 | #endif /* #else #ifdef CONFIG_RCU_BOOST */ | ||
| 224 | |||
| 160 | static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) | 225 | static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) |
| 161 | { | 226 | { |
| 162 | unsigned long gpnum; | 227 | unsigned long gpnum; |
| @@ -315,6 +380,9 @@ static int __init rcutree_trace_init(void) | |||
| 315 | if (!retval) | 380 | if (!retval) |
| 316 | goto free_out; | 381 | goto free_out; |
| 317 | 382 | ||
| 383 | if (rcu_boost_trace_create_file(rcudir)) | ||
| 384 | goto free_out; | ||
| 385 | |||
| 318 | retval = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops); | ||
