|
@@ -1379,6 +1379,66 @@ static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
|
|
int sysctl_stat_interval __read_mostly = HZ;
|
|
int sysctl_stat_interval __read_mostly = HZ;
|
|
static cpumask_var_t cpu_stat_off;
|
|
static cpumask_var_t cpu_stat_off;
|
|
|
|
|
|
|
|
+#ifdef CONFIG_PROC_FS
|
|
|
|
+static void refresh_vm_stats(struct work_struct *work)
|
|
|
|
+{
|
|
|
|
+ refresh_cpu_vm_stats(true);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int vmstat_refresh(struct ctl_table *table, int write,
|
|
|
|
+ void __user *buffer, size_t *lenp, loff_t *ppos)
|
|
|
|
+{
|
|
|
|
+ long val;
|
|
|
|
+ int err;
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * The regular update, every sysctl_stat_interval, may come later
|
|
|
|
+ * than expected: leaving a significant amount in per_cpu buckets.
|
|
|
|
+ * This is particularly misleading when checking a quantity of HUGE
|
|
|
|
+ * pages, immediately after running a test. /proc/sys/vm/stat_refresh,
|
|
|
|
+ * which can equally be echo'ed to or cat'ted from (by root),
|
|
|
|
+ * can be used to update the stats just before reading them.
|
|
|
|
+ *
|
|
|
|
+ * Oh, and since global_page_state() etc. are so careful to hide
|
|
|
|
+ * 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);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+ for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
|
|
|
|
+ val = atomic_long_read(&vm_stat[i]);
|
|
|
|
+ if (val < 0) {
|
|
|
|
+ switch (i) {
|
|
|
|
+ case NR_ALLOC_BATCH:
|
|
|
|
+ case NR_PAGES_SCANNED:
|
|
|
|
+ /*
|
|
|
|
+ * These are often seen to go negative in
|
|
|
|
+ * recent kernels, but not to go permanently
|
|
|
|
+ * negative. Whilst it would be nicer not to
|
|
|
|
+ * have exceptions, rooting them out would be
|
|
|
|
+ * another task, of rather low priority.
|
|
|
|
+ */
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ pr_warn("%s: %s %ld\n",
|
|
|
|
+ __func__, vmstat_text[i], val);
|
|
|
|
+ err = -EINVAL;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+ if (write)
|
|
|
|
+ *ppos += *lenp;
|
|
|
|
+ else
|
|
|
|
+ *lenp = 0;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+#endif /* CONFIG_PROC_FS */
|
|
|
|
+
|
|
static void vmstat_update(struct work_struct *w)
|
|
static void vmstat_update(struct work_struct *w)
|
|
{
|
|
{
|
|
if (refresh_cpu_vm_stats(true)) {
|
|
if (refresh_cpu_vm_stats(true)) {
|