Refresh per-CPU stats remotely, instead of queueing
work items, for the stat_refresh procfs method.
This fixes sosreport hang (which uses vmstat_refresh) with
spinning SCHED_FIFO process.
Signed-off-by: Marcelo Tosatti <[email protected]>
Index: linux-2.6/mm/vmstat.c
===================================================================
--- linux-2.6.orig/mm/vmstat.c
+++ linux-2.6/mm/vmstat.c
@@ -1865,11 +1865,21 @@ static DEFINE_PER_CPU(struct delayed_wor
int sysctl_stat_interval __read_mostly = HZ;
#ifdef CONFIG_PROC_FS
+
+#ifdef CONFIG_HAVE_CMPXCHG_LOCAL
+static int refresh_all_vm_stats(void);
+#else
static void refresh_vm_stats(struct work_struct *work)
{
refresh_cpu_vm_stats();
}
+static int refresh_all_vm_stats(void)
+{
+ return schedule_on_each_cpu(refresh_vm_stats);
+}
+#endif
+
int vmstat_refresh(struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
@@ -1889,7 +1899,7 @@ int vmstat_refresh(struct ctl_table *tab
* transiently negative values, report an error here if any of
* the stats is negative, so we know to go looking for imbalance.
*/
- err = schedule_on_each_cpu(refresh_vm_stats);
+ err = refresh_all_vm_stats();
if (err)
return err;
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
@@ -2009,7 +2019,7 @@ static DECLARE_DEFERRABLE_WORK(shepherd,
#ifdef CONFIG_HAVE_CMPXCHG_LOCAL
/* Flush counters remotely if CPU uses cmpxchg to update its per-CPU counters */
-static void vmstat_shepherd(struct work_struct *w)
+static int refresh_all_vm_stats(void)
{
int cpu;
@@ -2019,7 +2029,12 @@ static void vmstat_shepherd(struct work_
cond_resched();
}
cpus_read_unlock();
+ return 0;
+}
+static void vmstat_shepherd(struct work_struct *w)
+{
+ refresh_all_vm_stats();
schedule_delayed_work(&shepherd,
round_jiffies_relative(sysctl_stat_interval));
}