|
@@ -668,6 +668,7 @@ static int __noreturn rcu_tasks_kthread(void *arg)
|
|
struct rcu_head *list;
|
|
struct rcu_head *list;
|
|
struct rcu_head *next;
|
|
struct rcu_head *next;
|
|
LIST_HEAD(rcu_tasks_holdouts);
|
|
LIST_HEAD(rcu_tasks_holdouts);
|
|
|
|
+ int fract;
|
|
|
|
|
|
/* Run on housekeeping CPUs by default. Sysadm can move if desired. */
|
|
/* Run on housekeeping CPUs by default. Sysadm can move if desired. */
|
|
housekeeping_affine(current, HK_FLAG_RCU);
|
|
housekeeping_affine(current, HK_FLAG_RCU);
|
|
@@ -749,13 +750,25 @@ static int __noreturn rcu_tasks_kthread(void *arg)
|
|
* holdouts. When the list is empty, we are done.
|
|
* holdouts. When the list is empty, we are done.
|
|
*/
|
|
*/
|
|
lastreport = jiffies;
|
|
lastreport = jiffies;
|
|
- while (!list_empty(&rcu_tasks_holdouts)) {
|
|
|
|
|
|
+
|
|
|
|
+ /* Start off with HZ/10 wait and slowly back off to 1 HZ wait*/
|
|
|
|
+ fract = 10;
|
|
|
|
+
|
|
|
|
+ for (;;) {
|
|
bool firstreport;
|
|
bool firstreport;
|
|
bool needreport;
|
|
bool needreport;
|
|
int rtst;
|
|
int rtst;
|
|
struct task_struct *t1;
|
|
struct task_struct *t1;
|
|
|
|
|
|
- schedule_timeout_interruptible(HZ);
|
|
|
|
|
|
+ if (list_empty(&rcu_tasks_holdouts))
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ /* Slowly back off waiting for holdouts */
|
|
|
|
+ schedule_timeout_interruptible(HZ/fract);
|
|
|
|
+
|
|
|
|
+ if (fract > 1)
|
|
|
|
+ fract--;
|
|
|
|
+
|
|
rtst = READ_ONCE(rcu_task_stall_timeout);
|
|
rtst = READ_ONCE(rcu_task_stall_timeout);
|
|
needreport = rtst > 0 &&
|
|
needreport = rtst > 0 &&
|
|
time_after(jiffies, lastreport + rtst);
|
|
time_after(jiffies, lastreport + rtst);
|