Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b3956a89 authored by Nathan Zimmer's avatar Nathan Zimmer Committed by Thomas Gleixner
Browse files

timer_list: Convert timer list to be a proper seq_file



When running with 4096 cores attemping to read /proc/timer_list will fail
with an ENOMEM condition.  On a sufficantly large systems the total amount
of data is more then 4mb, so it won't fit into a single buffer.  The
failure can also occur on smaller systems when memory fragmentation is
high as reported by Dave Jones.

Convert /proc/timer_list to a proper seq_file with its own iterator.  This
is a little more complex given that we have to make two passes with two
separate headers.

sysrq_timer_list_show also needed to be updated to reflect the fact that
now timer_list_show only does one cpu at at time.

Signed-off-by: default avatarNathan Zimmer <nzimmer@sgi.com>
Reported-by: default avatarDave Jones <davej@redhat.com>
Cc: John Stultz <johnstul@us.ibm.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Link: http://lkml.kernel.org/r/1364345790-14577-3-git-send-email-nzimmer@sgi.com


Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 60cf7ea8
Loading
Loading
Loading
Loading
+77 −12
Original line number Diff line number Diff line
@@ -20,6 +20,13 @@

#include <asm/uaccess.h>


struct timer_list_iter {
	int cpu;
	bool second_pass;
	u64 now;
};

typedef void (*print_fn_t)(struct seq_file *m, unsigned int *classes);

DECLARE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases);
@@ -247,43 +254,101 @@ static void timer_list_show_tickdevices_header(struct seq_file *m)
}
#endif

static int timer_list_show(struct seq_file *m, void *v)
static inline void timer_list_header(struct seq_file *m, u64 now)
{
	u64 now = ktime_to_ns(ktime_get());
	int cpu;

	SEQ_printf(m, "Timer List Version: v0.7\n");
	SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES);
	SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now);
	SEQ_printf(m, "\n");
}

	for_each_online_cpu(cpu)
		print_cpu(m, cpu, now);
static int timer_list_show(struct seq_file *m, void *v)
{
	struct timer_list_iter *iter = v;
	u64 now = ktime_to_ns(ktime_get());

	if (iter->cpu == -1 && !iter->second_pass)
		timer_list_header(m, now);
	else if (!iter->second_pass)
		print_cpu(m, iter->cpu, iter->now);
#ifdef CONFIG_GENERIC_CLOCKEVENTS
	else if (iter->cpu == -1 && iter->second_pass)
		timer_list_show_tickdevices_header(m);
	for_each_online_cpu(cpu)
		print_tickdevice(m, tick_get_device(cpu), cpu);
	else
		print_tickdevice(m, tick_get_device(iter->cpu), iter->cpu);
#endif

	return 0;
}

void sysrq_timer_list_show(void)
{
	timer_list_show(NULL, NULL);
	u64 now = ktime_to_ns(ktime_get());
	int cpu;

	timer_list_header(NULL, now);

	for_each_online_cpu(cpu)
		print_cpu(NULL, cpu, now);

#ifdef CONFIG_GENERIC_CLOCKEVENTS
	timer_list_show_tickdevices_header(NULL);
	for_each_online_cpu(cpu)
		print_tickdevice(NULL, tick_get_device(cpu), cpu);
#endif
	return;
}

static void *timer_list_start(struct seq_file *file, loff_t *offset)
{
	struct timer_list_iter *iter = file->private;

	if (!*offset) {
		iter->cpu = -1;
		iter->now = ktime_to_ns(ktime_get());
	} else if (iter->cpu >= nr_cpu_ids) {
#ifdef CONFIG_GENERIC_CLOCKEVENTS
		if (!iter->second_pass) {
			iter->cpu = -1;
			iter->second_pass = true;
		} else
			return NULL;
#else
		return NULL;
#endif
	}
	return iter;
}

static void *timer_list_next(struct seq_file *file, void *v, loff_t *offset)
{
	struct timer_list_iter *iter = file->private;
	iter->cpu = cpumask_next(iter->cpu, cpu_online_mask);
	++*offset;
	return timer_list_start(file, offset);
}

static void timer_list_stop(struct seq_file *seq, void *v)
{
}

static const struct seq_operations timer_list_sops = {
	.start = timer_list_start,
	.next = timer_list_next,
	.stop = timer_list_stop,
	.show = timer_list_show,
};

static int timer_list_open(struct inode *inode, struct file *filp)
{
	return single_open(filp, timer_list_show, NULL);
	return seq_open_private(filp, &timer_list_sops,
			sizeof(struct timer_list_iter));
}

static const struct file_operations timer_list_fops = {
	.open		= timer_list_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
	.release	= seq_release_private,
};

static int __init init_timer_list_procfs(void)