platform.c 7.1 KB
Newer Older
1 2 3
/*
 * Persistent Storage - platform driver interface parts.
 *
4
 * Copyright (C) 2007-2008 Google, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 * Copyright (C) 2010 Intel Corporation <tony.luck@intel.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <linux/atomic.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kmsg_dump.h>
26
#include <linux/console.h>
27 28 29
#include <linux/module.h>
#include <linux/pstore.h>
#include <linux/string.h>
30
#include <linux/timer.h>
31 32
#include <linux/slab.h>
#include <linux/uaccess.h>
33
#include <linux/hardirq.h>
34
#include <linux/jiffies.h>
35
#include <linux/workqueue.h>
36 37 38

#include "internal.h"

39 40 41 42 43
/*
 * We defer making "oops" entries appear in pstore - see
 * whether the system is actually still running well enough
 * to let someone see the entry
 */
44
static int pstore_update_ms = -1;
45 46
module_param_named(update_ms, pstore_update_ms, int, 0600);
MODULE_PARM_DESC(update_ms, "milliseconds before pstore updates its content "
47 48 49
		 "(default is -1, which means runtime updates are disabled; "
		 "enabling this option is not safe, it may lead to further "
		 "corruption on Oopses)");
50 51 52 53 54 55 56 57 58

static int pstore_new_entry;

static void pstore_timefunc(unsigned long);
static DEFINE_TIMER(pstore_timer, pstore_timefunc, 0, 0);

static void pstore_dowork(struct work_struct *);
static DECLARE_WORK(pstore_work, pstore_dowork);

59 60 61 62 63 64 65
/*
 * pstore_lock just protects "psinfo" during
 * calls to pstore_register()
 */
static DEFINE_SPINLOCK(pstore_lock);
static struct pstore_info *psinfo;

66 67
static char *backend;

68
/* How much of the console log to snapshot */
69 70
static unsigned long kmsg_bytes = 10240;

71
void pstore_set_kmsg_bytes(int bytes)
72
{
73
	kmsg_bytes = bytes;
74 75 76 77 78
}

/* Tag each group of saved records with a sequence number */
static int	oopscount;

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
static const char *get_reason_str(enum kmsg_dump_reason reason)
{
	switch (reason) {
	case KMSG_DUMP_PANIC:
		return "Panic";
	case KMSG_DUMP_OOPS:
		return "Oops";
	case KMSG_DUMP_EMERG:
		return "Emergency";
	case KMSG_DUMP_RESTART:
		return "Restart";
	case KMSG_DUMP_HALT:
		return "Halt";
	case KMSG_DUMP_POWEROFF:
		return "Poweroff";
	default:
		return "Unknown";
	}
}
T
Tony Luck 已提交
98

99 100 101 102 103 104
/*
 * callback from kmsg_dump. (s2,l2) has the most recently
 * written bytes, older bytes are in (s1,l1). Save as much
 * as we can from the end of the buffer.
 */
static void pstore_dump(struct kmsg_dumper *dumper,
105
			enum kmsg_dump_reason reason)
106
{
107
	unsigned long	total = 0;
108
	const char	*why;
109
	u64		id;
M
Matthew Garrett 已提交
110
	unsigned int	part = 1;
111 112
	unsigned long	flags = 0;
	int		is_locked = 0;
113
	int		ret;
114

115
	why = get_reason_str(reason);
T
Tony Luck 已提交
116

117 118 119 120 121 122
	if (in_nmi()) {
		is_locked = spin_trylock(&psinfo->buf_lock);
		if (!is_locked)
			pr_err("pstore dump routine blocked in NMI, may corrupt error record\n");
	} else
		spin_lock_irqsave(&psinfo->buf_lock, flags);
123 124
	oopscount++;
	while (total < kmsg_bytes) {
125 126 127 128 129
		char *dst;
		unsigned long size;
		int hsize;
		size_t len;

130
		dst = psinfo->buf;
131
		hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part);
132 133 134
		size = psinfo->bufsize - hsize;
		dst += hsize;

135
		if (!kmsg_dump_get_buffer(dumper, true, dst, size, &len))
136 137
			break;

138
		ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part,
139
				    hsize + len, psinfo);
140
		if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
141
			pstore_new_entry = 1;
142 143

		total += hsize + len;
144
		part++;
145
	}
146 147 148 149 150
	if (in_nmi()) {
		if (is_locked)
			spin_unlock(&psinfo->buf_lock);
	} else
		spin_unlock_irqrestore(&psinfo->buf_lock, flags);
151 152 153 154 155 156
}

static struct kmsg_dumper pstore_dumper = {
	.dump = pstore_dump,
};

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
#ifdef CONFIG_PSTORE_CONSOLE
static void pstore_console_write(struct console *con, const char *s, unsigned c)
{
	const char *e = s + c;

	while (s < e) {
		unsigned long flags;

		if (c > psinfo->bufsize)
			c = psinfo->bufsize;
		spin_lock_irqsave(&psinfo->buf_lock, flags);
		memcpy(psinfo->buf, s, c);
		psinfo->write(PSTORE_TYPE_CONSOLE, 0, NULL, 0, c, psinfo);
		spin_unlock_irqrestore(&psinfo->buf_lock, flags);
		s += c;
		c = e - s;
	}
}

static struct console pstore_console = {
	.name	= "pstore",
	.write	= pstore_console_write,
	.flags	= CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME,
	.index	= -1,
};

static void pstore_register_console(void)
{
	register_console(&pstore_console);
}
#else
static void pstore_register_console(void) {}
#endif

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
/*
 * platform specific persistent storage driver registers with
 * us here. If pstore is already mounted, call the platform
 * read function right away to populate the file system. If not
 * then the pstore mount code will call us later to fill out
 * the file system.
 *
 * Register with kmsg_dump to save last part of console log on panic.
 */
int pstore_register(struct pstore_info *psi)
{
	struct module *owner = psi->owner;

	spin_lock(&pstore_lock);
	if (psinfo) {
		spin_unlock(&pstore_lock);
		return -EBUSY;
	}
209 210 211 212 213 214

	if (backend && strcmp(backend, psi->name)) {
		spin_unlock(&pstore_lock);
		return -EINVAL;
	}

215
	psinfo = psi;
216
	mutex_init(&psinfo->read_mutex);
217 218 219 220 221 222 223 224
	spin_unlock(&pstore_lock);

	if (owner && !try_module_get(owner)) {
		psinfo = NULL;
		return -EINVAL;
	}

	if (pstore_is_mounted())
225
		pstore_get_records(0);
226 227

	kmsg_dump_register(&pstore_dumper);
228
	pstore_register_console();
229

230 231 232 233 234
	if (pstore_update_ms >= 0) {
		pstore_timer.expires = jiffies +
			msecs_to_jiffies(pstore_update_ms);
		add_timer(&pstore_timer);
	}
235

236 237 238 239 240
	return 0;
}
EXPORT_SYMBOL_GPL(pstore_register);

/*
241 242 243 244
 * Read all the records from the persistent store. Create
 * files in our filesystem.  Don't warn about -EEXIST errors
 * when we are re-scanning the backing store looking to add new
 * error records.
245
 */
246
void pstore_get_records(int quiet)
247 248
{
	struct pstore_info *psi = psinfo;
249
	char			*buf = NULL;
250
	ssize_t			size;
251 252 253
	u64			id;
	enum pstore_type_id	type;
	struct timespec		time;
254
	int			failed = 0, rc;
255 256 257 258

	if (!psi)
		return;

259
	mutex_lock(&psi->read_mutex);
260
	if (psi->open && psi->open(psi))
261 262
		goto out;

263 264
	while ((size = psi->read(&id, &type, &time, &buf, psi)) > 0) {
		rc = pstore_mkfile(type, psi->name, id, buf, (size_t)size,
265
				  time, psi);
266 267
		kfree(buf);
		buf = NULL;
268
		if (rc && (rc != -EEXIST || !quiet))
269 270
			failed++;
	}
271 272
	if (psi->close)
		psi->close(psi);
273
out:
274
	mutex_unlock(&psi->read_mutex);
275 276 277 278 279 280

	if (failed)
		printk(KERN_WARNING "pstore: failed to load %d record(s) from '%s'\n",
		       failed, psi->name);
}

281 282 283 284 285 286 287 288 289 290 291 292
static void pstore_dowork(struct work_struct *work)
{
	pstore_get_records(1);
}

static void pstore_timefunc(unsigned long dummy)
{
	if (pstore_new_entry) {
		pstore_new_entry = 0;
		schedule_work(&pstore_work);
	}

293
	mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms));
294 295
}

296 297
module_param(backend, charp, 0444);
MODULE_PARM_DESC(backend, "Pstore backend to use");