[RFC PATCH 4/5] crash dump bitmap: add a proc interface for crash dump bitmap

Jingbai Ma
2013-03-07T14:59:18Z

Add a procfs driver for selecting exclude pages in userspace.
/proc/crash_dump_bitmap/

Signed-off-by: Jingbai Ma <jingbai.ma@hp.com>
---
fs/proc/Makefile | 1
fs/proc/crash_dump_bitmap.c | 221 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 222 insertions(+), 0 deletions(-)
create mode 100644 fs/proc/crash_dump_bitmap.c

diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index 712f24d..2dfcff1 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -27,6 +27,7 @@ proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o
proc-$(CONFIG_NET) += proc_net.o
proc-$(CONFIG_PROC_KCORE) += kcore.o
proc-$(CONFIG_PROC_VMCORE) += vmcore.o
+proc-$(CONFIG_CRASH_DUMP_BITMAP) += crash_dump_bitmap.o
proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o
proc-$(CONFIG_PRINTK) += kmsg.o
proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o
diff --git a/fs/proc/crash_dump_bitmap.c b/fs/proc/crash_dump_bitmap.c
new file mode 100644
index 0000000..77ecaae
--- /dev/null
+++ b/fs/proc/crash_dump_bitmap.c
@@ -0,0 +1,221 @@
+/*
+ * fs/proc/crash_dump_bitmap.c
+ * Interface for controlling the crash dump bitmap from user space.
+ *
+ * (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
+ * Author: Jingbai Ma <jingbai.ma@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/jiffies.h>
+#include <linux/crash_dump.h>
+#include <linux/crash_dump_bitmap.h>
+
+#ifdef CONFIG_CRASH_DUMP_BITMAP
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jingbai Ma <jingbai.ma@hp.com>");
+MODULE_DESCRIPTION("Crash dump bitmap support driver");
+
+static const char *proc_dir_name = "crash_dump_bitmap";
+static const char *proc_page_status_name = "page_status";
+static const char *proc_dump_level_name = "dump_level";
+
+static struct proc_dir_entry *proc_dir, *proc_page_status, *proc_dump_level;
+
+static unsigned int get_dump_level(void)
+{
+ unsigned int dump_level;
+
+ dump_level = crash_dump_bitmap_ctrl.exclude_zero_pages
+ ? CRASH_DUMP_LEVEL_EXCLUDE_ZERO_PAGES : 0;
+ dump_level |= crash_dump_bitmap_ctrl.exclude_cache_pages
+ ? CRASH_DUMP_LEVEL_EXCLUDE_CACHE_PAGES : 0;
+ dump_level |= crash_dump_bitmap_ctrl.exclude_cache_private_pages
+ ? CRASH_DUMP_LEVEL_EXCLUDE_CACHE_PRIVATE_PAGES : 0;
+ dump_level |= crash_dump_bitmap_ctrl.exclude_user_pages
+ ? CRASH_DUMP_LEVEL_EXCLUDE_USER_PAGES : 0;
+ dump_level |= crash_dump_bitmap_ctrl.exclude_free_pages
+ ? CRASH_DUMP_LEVEL_EXCLUDE_FREE_PAGES : 0;
+
+ return dump_level;
+}
+
+static void set_dump_level(unsigned int dump_level)
+{
+ crash_dump_bitmap_ctrl.exclude_zero_pages =
+ (dump_level & CRASH_DUMP_LEVEL_EXCLUDE_ZERO_PAGES) ? 1 : 0;
+ crash_dump_bitmap_ctrl.exclude_cache_pages =
+ (dump_level & CRASH_DUMP_LEVEL_EXCLUDE_CACHE_PAGES) ? 1 : 0;
+ crash_dump_bitmap_ctrl.exclude_cache_private_pages =
+ (dump_level & CRASH_DUMP_LEVEL_EXCLUDE_CACHE_PRIVATE_PAGES)
+ ? 1 : 0;
+ crash_dump_bitmap_ctrl.exclude_user_pages =
+ (dump_level & CRASH_DUMP_LEVEL_EXCLUDE_USER_PAGES) ? 1 : 0;
+ crash_dump_bitmap_ctrl.exclude_free_pages =
+ (dump_level & CRASH_DUMP_LEVEL_EXCLUDE_FREE_PAGES) ? 1 : 0;
+}
+
+static int proc_page_status_show(struct seq_file *m, void *v)
+{
+ u64 start, duration;
+
+ if (!crash_dump_bitmap_mem) {
+ seq_printf(m,
+ "crash_dump_bitmap: crash_dump_bitmap_mem not found!\n");
+
+ return -EINVAL;
+ }
+
+ seq_printf(m, "Exclude page flag status:\n");
+ seq_printf(m, " exclude_dump_bitmap_pages=%d\n",
+ crash_dump_bitmap_ctrl.exclude_crash_dump_bitmap_pages);
+ seq_printf(m, " exclude_zero_pages=%d\n",
+ crash_dump_bitmap_ctrl.exclude_zero_pages);
+ seq_printf(m, " exclude_cache_pages=%d\n",
+ crash_dump_bitmap_ctrl.exclude_cache_pages);
+ seq_printf(m, " exclude_cache_private_pages=%d\n",
+ crash_dump_bitmap_ctrl.exclude_cache_private_pages);
+ seq_printf(m, " exclude_user_pages=%d\n",
+ crash_dump_bitmap_ctrl.exclude_user_pages);
+ seq_printf(m, " exclude_free_pages=%d\n",
+ crash_dump_bitmap_ctrl.exclude_free_pages);
+
+ seq_printf(m, "Scanning all memory pages:\n");
+ start = get_jiffies_64();
+ generate_crash_dump_bitmap();
+ duration = get_jiffies_64() - start;
+ seq_printf(m, " Done. Duration=%dms\n", jiffies_to_msecs(duration));
+
+ seq_printf(m, "Excluded memory page status:\n");
+ seq_printf(m, " cache_pages=%ld\n",
+ crash_dump_bitmap_info.cache_pages);
+ seq_printf(m, " cache_private_pages=%ld\n",
+ crash_dump_bitmap_info.cache_private_pages);
+ seq_printf(m, " user_pages=%ld\n",
+ crash_dump_bitmap_info.user_pages);
+ seq_printf(m, " free_pages=%ld\n",
+ crash_dump_bitmap_info.free_pages);
+ seq_printf(m, " hwpoison_pages=%ld\n",
+ crash_dump_bitmap_info.hwpoison_pages);
+
+ return 0;
+}
+
+static int proc_page_status_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_page_status_show, NULL);
+}
+
+static const struct file_operations proc_page_status_fops = {
+ .open = proc_page_status_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int proc_dump_level_show(struct seq_file *m, void *v)
+{
+ if (!crash_dump_bitmap_mem) {
+ seq_printf(m,
+ "crash_dump_bitmap: crash_dump_bitmap_mem not found!\n");
+
+ return -EINVAL;
+ }
+
+ seq_printf(m, "%d\n", get_dump_level());
+
+ return 0;
+}
+
+static ssize_t proc_dump_level_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
+{
+ int ret;
+ unsigned int dump_level;
+
+ ret = kstrtouint_from_user(buffer, count, 10, &dump_level);
+ if (ret)
+ return -EFAULT;
+
+ set_dump_level(dump_level);
+
+ pr_info("crash_dump_bitmap: new dump_level=%d\n", dump_level);
+
+ return count;
+}
+
+static int proc_dump_level_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_dump_level_show, NULL);
+}
+
+static const struct file_operations proc_dump_level_fops = {
+ .open = proc_dump_level_open,
+ .read = seq_read,
+ .write = proc_dump_level_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+int __init init_proc_crash_dump_bitmap(void)
+{
+ if (is_kdump_kernel() || (crash_dump_bitmap_mem == 0)
+ || (crash_dump_bitmap_mem_size == 0))
+ return 0;
+
+ proc_dir = proc_mkdir(proc_dir_name, NULL);
+ if (proc_dir == NULL) {
+ pr_err("crash_dump_bitmap: proc_mkdir failed!\n");
+ return -EINVAL;
+ }
+
+ proc_page_status = proc_create(proc_page_status_name, 0444,
+ proc_dir, &proc_page_status_fops);
+ if (proc_page_status == NULL) {
+ pr_err("crash_dump_bitmap: create procfs %s failed!\n",
+ proc_page_status_name);
+ remove_proc_entry(proc_dir_name, NULL);
+ return -EINVAL;
+ }
+
+ proc_dump_level = proc_create(proc_dump_level_name, 0644,
+ proc_dir, &proc_dump_level_fops);
+ if (proc_dump_level == NULL) {
+ pr_err("crash_dump_bitmap: create procfs %s failed!\n",
+ proc_dump_level_name);
+ remove_proc_entry(proc_page_status_name, proc_dir);
+ remove_proc_entry(proc_dir_name, NULL);
+ return -EINVAL;
+ }
+
+ pr_info("crash_dump_bitmap: procfs driver initialized successfully!\n");
+
+ return 0;
+}
+
+void __exit cleanup_proc_crash_dump_bitmap(void)
+{
+ remove_proc_entry(proc_dump_level_name, proc_dir);
+ remove_proc_entry(proc_page_status_name, proc_dir);
+ remove_proc_entry(proc_dir_name, NULL);
+
+ pr_info("crash_dump_bitmap: procfs driver unloaded!\n");
+}
+
+module_init(init_proc_crash_dump_bitmap);
+module_exit(cleanup_proc_crash_dump_bitmap);
+
+#endif /* CONFIG_CRASH_DUMP_BITMAP */