Commit | Line | Data |
---|---|---|
ca01d6dd TL |
1 | /* |
2 | * Persistent Storage - platform driver interface parts. | |
3 | * | |
f29e5956 | 4 | * Copyright (C) 2007-2008 Google, Inc. |
ca01d6dd TL |
5 | * Copyright (C) 2010 Intel Corporation <tony.luck@intel.com> |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | */ | |
20 | ||
21 | #include <linux/atomic.h> | |
22 | #include <linux/types.h> | |
23 | #include <linux/errno.h> | |
24 | #include <linux/init.h> | |
25 | #include <linux/kmsg_dump.h> | |
f29e5956 | 26 | #include <linux/console.h> |
ca01d6dd TL |
27 | #include <linux/module.h> |
28 | #include <linux/pstore.h> | |
b0aad7a9 | 29 | #include <linux/zlib.h> |
ca01d6dd | 30 | #include <linux/string.h> |
6dda9266 | 31 | #include <linux/timer.h> |
ca01d6dd TL |
32 | #include <linux/slab.h> |
33 | #include <linux/uaccess.h> | |
abd4d558 | 34 | #include <linux/hardirq.h> |
a3f5f075 | 35 | #include <linux/jiffies.h> |
6dda9266 | 36 | #include <linux/workqueue.h> |
ca01d6dd TL |
37 | |
38 | #include "internal.h" | |
39 | ||
6dda9266 LT |
40 | /* |
41 | * We defer making "oops" entries appear in pstore - see | |
42 | * whether the system is actually still running well enough | |
43 | * to let someone see the entry | |
44 | */ | |
521f7288 | 45 | static int pstore_update_ms = -1; |
a3f5f075 AV |
46 | module_param_named(update_ms, pstore_update_ms, int, 0600); |
47 | MODULE_PARM_DESC(update_ms, "milliseconds before pstore updates its content " | |
521f7288 AV |
48 | "(default is -1, which means runtime updates are disabled; " |
49 | "enabling this option is not safe, it may lead to further " | |
50 | "corruption on Oopses)"); | |
6dda9266 LT |
51 | |
52 | static int pstore_new_entry; | |
53 | ||
54 | static void pstore_timefunc(unsigned long); | |
55 | static DEFINE_TIMER(pstore_timer, pstore_timefunc, 0, 0); | |
56 | ||
57 | static void pstore_dowork(struct work_struct *); | |
58 | static DECLARE_WORK(pstore_work, pstore_dowork); | |
59 | ||
ca01d6dd TL |
60 | /* |
61 | * pstore_lock just protects "psinfo" during | |
62 | * calls to pstore_register() | |
63 | */ | |
64 | static DEFINE_SPINLOCK(pstore_lock); | |
060287b8 | 65 | struct pstore_info *psinfo; |
ca01d6dd | 66 | |
dee28e72 MG |
67 | static char *backend; |
68 | ||
b0aad7a9 AB |
69 | /* Compression parameters */ |
70 | #define COMPR_LEVEL 6 | |
71 | #define WINDOW_BITS 12 | |
72 | #define MEM_LEVEL 4 | |
73 | static struct z_stream_s stream; | |
74 | ||
75 | static char *big_oops_buf; | |
76 | static size_t big_oops_buf_sz; | |
77 | ||
366f7e7a | 78 | /* How much of the console log to snapshot */ |
ca01d6dd TL |
79 | static unsigned long kmsg_bytes = 10240; |
80 | ||
366f7e7a | 81 | void pstore_set_kmsg_bytes(int bytes) |
ca01d6dd | 82 | { |
366f7e7a | 83 | kmsg_bytes = bytes; |
ca01d6dd TL |
84 | } |
85 | ||
ca01d6dd TL |
86 | /* Tag each group of saved records with a sequence number */ |
87 | static int oopscount; | |
88 | ||
381b872c SA |
89 | static const char *get_reason_str(enum kmsg_dump_reason reason) |
90 | { | |
91 | switch (reason) { | |
92 | case KMSG_DUMP_PANIC: | |
93 | return "Panic"; | |
94 | case KMSG_DUMP_OOPS: | |
95 | return "Oops"; | |
96 | case KMSG_DUMP_EMERG: | |
97 | return "Emergency"; | |
98 | case KMSG_DUMP_RESTART: | |
99 | return "Restart"; | |
100 | case KMSG_DUMP_HALT: | |
101 | return "Halt"; | |
102 | case KMSG_DUMP_POWEROFF: | |
103 | return "Poweroff"; | |
104 | default: | |
105 | return "Unknown"; | |
106 | } | |
107 | } | |
9f6af27f | 108 | |
9f244e9c SA |
109 | bool pstore_cannot_block_path(enum kmsg_dump_reason reason) |
110 | { | |
111 | /* | |
112 | * In case of NMI path, pstore shouldn't be blocked | |
113 | * regardless of reason. | |
114 | */ | |
115 | if (in_nmi()) | |
116 | return true; | |
117 | ||
118 | switch (reason) { | |
119 | /* In panic case, other cpus are stopped by smp_send_stop(). */ | |
120 | case KMSG_DUMP_PANIC: | |
121 | /* Emergency restart shouldn't be blocked by spin lock. */ | |
122 | case KMSG_DUMP_EMERG: | |
123 | return true; | |
124 | default: | |
125 | return false; | |
126 | } | |
127 | } | |
128 | EXPORT_SYMBOL_GPL(pstore_cannot_block_path); | |
129 | ||
b0aad7a9 AB |
130 | /* Derived from logfs_compress() */ |
131 | static int pstore_compress(const void *in, void *out, size_t inlen, | |
132 | size_t outlen) | |
133 | { | |
134 | int err, ret; | |
135 | ||
136 | ret = -EIO; | |
137 | err = zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS, | |
138 | MEM_LEVEL, Z_DEFAULT_STRATEGY); | |
139 | if (err != Z_OK) | |
140 | goto error; | |
141 | ||
142 | stream.next_in = in; | |
143 | stream.avail_in = inlen; | |
144 | stream.total_in = 0; | |
145 | stream.next_out = out; | |
146 | stream.avail_out = outlen; | |
147 | stream.total_out = 0; | |
148 | ||
149 | err = zlib_deflate(&stream, Z_FINISH); | |
150 | if (err != Z_STREAM_END) | |
151 | goto error; | |
152 | ||
153 | err = zlib_deflateEnd(&stream); | |
154 | if (err != Z_OK) | |
155 | goto error; | |
156 | ||
157 | if (stream.total_out >= stream.total_in) | |
158 | goto error; | |
159 | ||
160 | ret = stream.total_out; | |
161 | error: | |
162 | return ret; | |
163 | } | |
164 | ||
adb42f5e AB |
165 | /* Derived from logfs_uncompress */ |
166 | static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen) | |
167 | { | |
168 | int err, ret; | |
169 | ||
170 | ret = -EIO; | |
171 | err = zlib_inflateInit(&stream); | |
172 | if (err != Z_OK) | |
173 | goto error; | |
174 | ||
175 | stream.next_in = in; | |
176 | stream.avail_in = inlen; | |
177 | stream.total_in = 0; | |
178 | stream.next_out = out; | |
179 | stream.avail_out = outlen; | |
180 | stream.total_out = 0; | |
181 | ||
182 | err = zlib_inflate(&stream, Z_FINISH); | |
183 | if (err != Z_STREAM_END) | |
184 | goto error; | |
185 | ||
186 | err = zlib_inflateEnd(&stream); | |
187 | if (err != Z_OK) | |
188 | goto error; | |
189 | ||
190 | ret = stream.total_out; | |
191 | error: | |
192 | return ret; | |
193 | } | |
194 | ||
b0aad7a9 AB |
195 | static void allocate_buf_for_compression(void) |
196 | { | |
197 | size_t size; | |
198 | ||
199 | big_oops_buf_sz = (psinfo->bufsize * 100) / 45; | |
200 | big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL); | |
201 | if (big_oops_buf) { | |
202 | size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL), | |
203 | zlib_inflate_workspacesize()); | |
204 | stream.workspace = kmalloc(size, GFP_KERNEL); | |
205 | if (!stream.workspace) { | |
206 | pr_err("pstore: No memory for compression workspace; " | |
207 | "skipping compression\n"); | |
208 | kfree(big_oops_buf); | |
209 | big_oops_buf = NULL; | |
210 | } | |
211 | } else { | |
212 | pr_err("No memory for uncompressed data; " | |
213 | "skipping compression\n"); | |
214 | stream.workspace = NULL; | |
215 | } | |
216 | ||
217 | } | |
218 | ||
219 | /* | |
220 | * Called when compression fails, since the printk buffer | |
221 | * would be fetched for compression calling it again when | |
222 | * compression fails would have moved the iterator of | |
223 | * printk buffer which results in fetching old contents. | |
224 | * Copy the recent messages from big_oops_buf to psinfo->buf | |
225 | */ | |
226 | static size_t copy_kmsg_to_buffer(int hsize, size_t len) | |
227 | { | |
228 | size_t total_len; | |
229 | size_t diff; | |
230 | ||
231 | total_len = hsize + len; | |
232 | ||
233 | if (total_len > psinfo->bufsize) { | |
234 | diff = total_len - psinfo->bufsize + hsize; | |
235 | memcpy(psinfo->buf, big_oops_buf, hsize); | |
236 | memcpy(psinfo->buf + hsize, big_oops_buf + diff, | |
237 | psinfo->bufsize - hsize); | |
238 | total_len = psinfo->bufsize; | |
239 | } else | |
240 | memcpy(psinfo->buf, big_oops_buf, total_len); | |
241 | ||
242 | return total_len; | |
243 | } | |
244 | ||
ca01d6dd TL |
245 | /* |
246 | * callback from kmsg_dump. (s2,l2) has the most recently | |
247 | * written bytes, older bytes are in (s1,l1). Save as much | |
248 | * as we can from the end of the buffer. | |
249 | */ | |
250 | static void pstore_dump(struct kmsg_dumper *dumper, | |
e2ae715d | 251 | enum kmsg_dump_reason reason) |
ca01d6dd | 252 | { |
e2ae715d | 253 | unsigned long total = 0; |
381b872c | 254 | const char *why; |
ca01d6dd | 255 | u64 id; |
b94fdd07 | 256 | unsigned int part = 1; |
abd4d558 DZ |
257 | unsigned long flags = 0; |
258 | int is_locked = 0; | |
e2ae715d | 259 | int ret; |
ca01d6dd | 260 | |
381b872c | 261 | why = get_reason_str(reason); |
9f6af27f | 262 | |
9f244e9c SA |
263 | if (pstore_cannot_block_path(reason)) { |
264 | is_locked = spin_trylock_irqsave(&psinfo->buf_lock, flags); | |
265 | if (!is_locked) { | |
266 | pr_err("pstore dump routine blocked in %s path, may corrupt error record\n" | |
267 | , in_nmi() ? "NMI" : why); | |
268 | } | |
abd4d558 DZ |
269 | } else |
270 | spin_lock_irqsave(&psinfo->buf_lock, flags); | |
ca01d6dd TL |
271 | oopscount++; |
272 | while (total < kmsg_bytes) { | |
e2ae715d KS |
273 | char *dst; |
274 | unsigned long size; | |
275 | int hsize; | |
b0aad7a9 | 276 | int zipped_len = -1; |
e2ae715d | 277 | size_t len; |
b0aad7a9 AB |
278 | bool compressed; |
279 | size_t total_len; | |
e2ae715d | 280 | |
b0aad7a9 AB |
281 | if (big_oops_buf) { |
282 | dst = big_oops_buf; | |
283 | hsize = sprintf(dst, "%s#%d Part%d\n", why, | |
284 | oopscount, part); | |
285 | size = big_oops_buf_sz - hsize; | |
ca01d6dd | 286 | |
b0aad7a9 AB |
287 | if (!kmsg_dump_get_buffer(dumper, true, dst + hsize, |
288 | size, &len)) | |
289 | break; | |
290 | ||
291 | zipped_len = pstore_compress(dst, psinfo->buf, | |
292 | hsize + len, psinfo->bufsize); | |
293 | ||
294 | if (zipped_len > 0) { | |
295 | compressed = true; | |
296 | total_len = zipped_len; | |
297 | } else { | |
298 | pr_err("pstore: compression failed for Part %d" | |
299 | " returned %d\n", part, zipped_len); | |
300 | pr_err("pstore: Capture uncompressed" | |
301 | " oops/panic report of Part %d\n", part); | |
302 | compressed = false; | |
303 | total_len = copy_kmsg_to_buffer(hsize, len); | |
304 | } | |
305 | } else { | |
306 | dst = psinfo->buf; | |
307 | hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, | |
308 | part); | |
309 | size = psinfo->bufsize - hsize; | |
310 | dst += hsize; | |
311 | ||
312 | if (!kmsg_dump_get_buffer(dumper, true, dst, | |
313 | size, &len)) | |
314 | break; | |
315 | ||
316 | compressed = false; | |
317 | total_len = hsize + len; | |
318 | } | |
ca01d6dd | 319 | |
3d6d8d20 | 320 | ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part, |
b0aad7a9 | 321 | oopscount, compressed, total_len, psinfo); |
b238b8fa | 322 | if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted()) |
6dda9266 | 323 | pstore_new_entry = 1; |
e2ae715d | 324 | |
b0aad7a9 | 325 | total += total_len; |
56280682 | 326 | part++; |
ca01d6dd | 327 | } |
9f244e9c | 328 | if (pstore_cannot_block_path(reason)) { |
abd4d558 | 329 | if (is_locked) |
9f244e9c | 330 | spin_unlock_irqrestore(&psinfo->buf_lock, flags); |
abd4d558 DZ |
331 | } else |
332 | spin_unlock_irqrestore(&psinfo->buf_lock, flags); | |
ca01d6dd TL |
333 | } |
334 | ||
335 | static struct kmsg_dumper pstore_dumper = { | |
336 | .dump = pstore_dump, | |
337 | }; | |
338 | ||
f29e5956 AV |
339 | #ifdef CONFIG_PSTORE_CONSOLE |
340 | static void pstore_console_write(struct console *con, const char *s, unsigned c) | |
341 | { | |
342 | const char *e = s + c; | |
343 | ||
344 | while (s < e) { | |
345 | unsigned long flags; | |
70a6f46d | 346 | u64 id; |
f29e5956 AV |
347 | |
348 | if (c > psinfo->bufsize) | |
349 | c = psinfo->bufsize; | |
80c9d03c CL |
350 | |
351 | if (oops_in_progress) { | |
352 | if (!spin_trylock_irqsave(&psinfo->buf_lock, flags)) | |
353 | break; | |
354 | } else { | |
355 | spin_lock_irqsave(&psinfo->buf_lock, flags); | |
356 | } | |
f29e5956 | 357 | memcpy(psinfo->buf, s, c); |
6bbbca73 | 358 | psinfo->write(PSTORE_TYPE_CONSOLE, 0, &id, 0, 0, 0, c, psinfo); |
f29e5956 AV |
359 | spin_unlock_irqrestore(&psinfo->buf_lock, flags); |
360 | s += c; | |
361 | c = e - s; | |
362 | } | |
363 | } | |
364 | ||
365 | static struct console pstore_console = { | |
366 | .name = "pstore", | |
367 | .write = pstore_console_write, | |
368 | .flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME, | |
369 | .index = -1, | |
370 | }; | |
371 | ||
372 | static void pstore_register_console(void) | |
373 | { | |
374 | register_console(&pstore_console); | |
375 | } | |
376 | #else | |
377 | static void pstore_register_console(void) {} | |
378 | #endif | |
379 | ||
897dba02 AV |
380 | static int pstore_write_compat(enum pstore_type_id type, |
381 | enum kmsg_dump_reason reason, | |
755d4fe4 | 382 | u64 *id, unsigned int part, int count, |
b3b515bb | 383 | bool compressed, size_t size, |
6bbbca73 | 384 | struct pstore_info *psi) |
897dba02 | 385 | { |
b3b515bb | 386 | return psi->write_buf(type, reason, id, part, psinfo->buf, compressed, |
6bbbca73 | 387 | size, psi); |
897dba02 AV |
388 | } |
389 | ||
ca01d6dd TL |
390 | /* |
391 | * platform specific persistent storage driver registers with | |
392 | * us here. If pstore is already mounted, call the platform | |
393 | * read function right away to populate the file system. If not | |
394 | * then the pstore mount code will call us later to fill out | |
395 | * the file system. | |
396 | * | |
397 | * Register with kmsg_dump to save last part of console log on panic. | |
398 | */ | |
399 | int pstore_register(struct pstore_info *psi) | |
400 | { | |
401 | struct module *owner = psi->owner; | |
402 | ||
8e48b1a8 LS |
403 | if (backend && strcmp(backend, psi->name)) |
404 | return -EPERM; | |
405 | ||
ca01d6dd TL |
406 | spin_lock(&pstore_lock); |
407 | if (psinfo) { | |
408 | spin_unlock(&pstore_lock); | |
409 | return -EBUSY; | |
410 | } | |
dee28e72 | 411 | |
897dba02 AV |
412 | if (!psi->write) |
413 | psi->write = pstore_write_compat; | |
ca01d6dd | 414 | psinfo = psi; |
f6f82851 | 415 | mutex_init(&psinfo->read_mutex); |
ca01d6dd TL |
416 | spin_unlock(&pstore_lock); |
417 | ||
418 | if (owner && !try_module_get(owner)) { | |
419 | psinfo = NULL; | |
420 | return -EINVAL; | |
421 | } | |
422 | ||
b0aad7a9 AB |
423 | allocate_buf_for_compression(); |
424 | ||
ca01d6dd | 425 | if (pstore_is_mounted()) |
6dda9266 | 426 | pstore_get_records(0); |
ca01d6dd TL |
427 | |
428 | kmsg_dump_register(&pstore_dumper); | |
f29e5956 | 429 | pstore_register_console(); |
65f8c95e | 430 | pstore_register_ftrace(); |
ca01d6dd | 431 | |
a3f5f075 AV |
432 | if (pstore_update_ms >= 0) { |
433 | pstore_timer.expires = jiffies + | |
434 | msecs_to_jiffies(pstore_update_ms); | |
435 | add_timer(&pstore_timer); | |
436 | } | |
6dda9266 | 437 | |
8e48b1a8 LS |
438 | pr_info("pstore: Registered %s as persistent store backend\n", |
439 | psi->name); | |
440 | ||
ca01d6dd TL |
441 | return 0; |
442 | } | |
443 | EXPORT_SYMBOL_GPL(pstore_register); | |
444 | ||
445 | /* | |
6dda9266 LT |
446 | * Read all the records from the persistent store. Create |
447 | * files in our filesystem. Don't warn about -EEXIST errors | |
448 | * when we are re-scanning the backing store looking to add new | |
449 | * error records. | |
ca01d6dd | 450 | */ |
6dda9266 | 451 | void pstore_get_records(int quiet) |
ca01d6dd TL |
452 | { |
453 | struct pstore_info *psi = psinfo; | |
f6f82851 | 454 | char *buf = NULL; |
8d38d74b | 455 | ssize_t size; |
ca01d6dd | 456 | u64 id; |
755d4fe4 | 457 | int count; |
ca01d6dd TL |
458 | enum pstore_type_id type; |
459 | struct timespec time; | |
06cf91b4 | 460 | int failed = 0, rc; |
9a4e1398 | 461 | bool compressed; |
adb42f5e | 462 | int unzipped_len = -1; |
ca01d6dd TL |
463 | |
464 | if (!psi) | |
465 | return; | |
466 | ||
f6f82851 | 467 | mutex_lock(&psi->read_mutex); |
2174f6df | 468 | if (psi->open && psi->open(psi)) |
06cf91b4 CG |
469 | goto out; |
470 | ||
9a4e1398 AB |
471 | while ((size = psi->read(&id, &type, &count, &time, &buf, &compressed, |
472 | psi)) > 0) { | |
adb42f5e AB |
473 | if (compressed && (type == PSTORE_TYPE_DMESG)) { |
474 | if (big_oops_buf) | |
475 | unzipped_len = pstore_decompress(buf, | |
476 | big_oops_buf, size, | |
477 | big_oops_buf_sz); | |
478 | ||
479 | if (unzipped_len > 0) { | |
480 | buf = big_oops_buf; | |
481 | size = unzipped_len; | |
482 | } else { | |
483 | pr_err("pstore: decompression failed;" | |
484 | "returned %d\n", unzipped_len); | |
485 | } | |
486 | } | |
755d4fe4 SA |
487 | rc = pstore_mkfile(type, psi->name, id, count, buf, |
488 | (size_t)size, time, psi); | |
adb42f5e AB |
489 | if (unzipped_len < 0) { |
490 | /* Free buffer other than big oops */ | |
491 | kfree(buf); | |
492 | buf = NULL; | |
493 | } else | |
494 | unzipped_len = -1; | |
6dda9266 | 495 | if (rc && (rc != -EEXIST || !quiet)) |
ca01d6dd TL |
496 | failed++; |
497 | } | |
2174f6df KC |
498 | if (psi->close) |
499 | psi->close(psi); | |
06cf91b4 | 500 | out: |
f6f82851 | 501 | mutex_unlock(&psi->read_mutex); |
ca01d6dd TL |
502 | |
503 | if (failed) | |
504 | printk(KERN_WARNING "pstore: failed to load %d record(s) from '%s'\n", | |
505 | failed, psi->name); | |
506 | } | |
507 | ||
6dda9266 LT |
508 | static void pstore_dowork(struct work_struct *work) |
509 | { | |
510 | pstore_get_records(1); | |
511 | } | |
512 | ||
513 | static void pstore_timefunc(unsigned long dummy) | |
514 | { | |
515 | if (pstore_new_entry) { | |
516 | pstore_new_entry = 0; | |
517 | schedule_work(&pstore_work); | |
518 | } | |
519 | ||
a3f5f075 | 520 | mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms)); |
6dda9266 LT |
521 | } |
522 | ||
dee28e72 MG |
523 | module_param(backend, charp, 0444); |
524 | MODULE_PARM_DESC(backend, "Pstore backend to use"); |