From: Torsten Duwe <duwe@suse.de>
Subject: pstore: automatically dump and clean dmesg entries
Patch-mainline: not yet, <NEEDS A REASON>
References: fate#315232

Dump a previous oops or panic, which has made it to pstore,
to the new syslog after reboot, optionally deleting it.
This can happen automatically, without user land interaction.

Signed-off-by: Torsten Duwe <duwe@suse.de>
---
 fs/pstore/inode.c    |    2 +-
 fs/pstore/internal.h |    9 ++++++++-
 fs/pstore/platform.c |   37 ++++++++++++++++++++++++++++++-------
 3 files changed, 39 insertions(+), 9 deletions(-)

--- a/fs/pstore/internal.h.orig
+++ b/fs/pstore/internal.h
@@ -48,7 +48,14 @@ static inline void pstore_register_ftrac
 extern struct pstore_info *psinfo;
 
 extern void	pstore_set_kmsg_bytes(int);
-extern void	pstore_get_records(int);
+extern void	pstore_get_records(unsigned);
+/* Flags for the pstore iterator pstore_get_records() */
+#define PGR_QUIET	0
+#define PGR_VERBOSE	1
+#define PGR_POPULATE	2
+#define PGR_SYSLOG	4
+#define PGR_CLEAR	8
+
 extern int	pstore_mkfile(enum pstore_type_id, char *psname, u64 id,
 			      int count, char *data, bool compressed,
 			      size_t size, struct timespec time,
--- a/fs/pstore/inode.c.orig
+++ b/fs/pstore/inode.c
@@ -406,7 +406,7 @@ static int pstore_fill_super(struct supe
 	if (!sb->s_root)
 		return -ENOMEM;
 
-	pstore_get_records(0);
+	pstore_get_records(PGR_VERBOSE|PGR_POPULATE);
 
 	return 0;
 }
--- a/fs/pstore/platform.c.orig
+++ b/fs/pstore/platform.c
@@ -65,6 +65,10 @@ static DEFINE_SPINLOCK(pstore_lock);
 struct pstore_info *psinfo;
 
 static char *backend;
+static int auto_action=0;
+module_param(auto_action, int, 0664);
+MODULE_PARM_DESC(auto_action, "action to take on backend "
+		 "registration: 0=nothing, 1=print, 2=print+clear");
 
 /* Compression parameters */
 #define COMPR_LEVEL 6
@@ -77,6 +81,8 @@ static size_t big_oops_buf_sz;
 
 /* How much of the console log to snapshot */
 static unsigned long kmsg_bytes = 10240;
+module_param(kmsg_bytes, ulong, 0644);
+MODULE_PARM_DESC(kmsg_bytes, "maximum size to save of a crash dump");
 
 void pstore_set_kmsg_bytes(int bytes)
 {
@@ -448,7 +454,11 @@ int pstore_register(struct pstore_info *
 	allocate_buf_for_compression();
 
 	if (pstore_is_mounted())
-		pstore_get_records(0);
+		pstore_get_records(PGR_VERBOSE|PGR_POPULATE);
+
+	if (auto_action)
+		pstore_get_records(PGR_SYSLOG|
+				   ((auto_action>1)?PGR_CLEAR:0));
 
 	pstore_register_kmsg();
 
@@ -473,7 +483,7 @@ EXPORT_SYMBOL_GPL(pstore_register);
  * when we are re-scanning the backing store looking to add new
  * error records.
  */
-void pstore_get_records(int quiet)
+void pstore_get_records(unsigned flags)
 {
 	struct pstore_info *psi = psinfo;
 	char			*buf = NULL;
@@ -482,7 +492,7 @@ void pstore_get_records(int quiet)
 	int			count;
 	enum pstore_type_id	type;
 	struct timespec		time;
-	int			failed = 0, rc;
+	int			failed = 0, rc = 0;
 	bool			compressed;
 	int			unzipped_len = -1;
 
@@ -511,15 +521,28 @@ void pstore_get_records(int quiet)
 				compressed = true;
 			}
 		}
-		rc = pstore_mkfile(type, psi->name, id, count, buf,
-				  compressed, (size_t)size, time, psi);
+
+		if (flags & PGR_POPULATE)
+			rc = pstore_mkfile(type, psi->name, id, count, buf,
+					   compressed, (size_t)size, time, psi);
+
+		if (type == PSTORE_TYPE_DMESG) {
+			if (flags & PGR_SYSLOG) {
+				pr_notice("---------- pstore: ----------\n");
+				pr_notice("%.*s\n", (int)size, buf);
+				pr_notice("-----------------------------\n");
+			}
+			if (flags & PGR_CLEAR && psi->erase)
+				psi->erase(type, id, size, time, psi);
+		}
+
 		if (unzipped_len < 0) {
 			/* Free buffer other than big oops */
 			kfree(buf);
 			buf = NULL;
 		} else
 			unzipped_len = -1;
-		if (rc && (rc != -EEXIST || !quiet))
+		if (rc && (rc != -EEXIST || (flags & PGR_VERBOSE)))
 			failed++;
 	}
 	if (psi->close)
@@ -534,7 +557,7 @@ out:
 
 static void pstore_dowork(struct work_struct *work)
 {
-	pstore_get_records(1);
+	pstore_get_records(PGR_QUIET|PGR_POPULATE);
 }
 
 static void pstore_timefunc(unsigned long dummy)
