blob: 19aaefeb052ff611ec988f2879136e099ff8c0ed [file] [log] [blame]
Tony Luckca01d6d2010-12-28 14:25:21 -08001/*
2 * Persistent Storage - platform driver interface parts.
3 *
Anton Vorontsovf29e5952012-05-26 06:20:19 -07004 * Copyright (C) 2007-2008 Google, Inc.
Tony Luckca01d6d2010-12-28 14:25:21 -08005 * 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
Fabian Frederickef748852014-06-06 14:37:31 -070021#define pr_fmt(fmt) "pstore: " fmt
22
Tony Luckca01d6d2010-12-28 14:25:21 -080023#include <linux/atomic.h>
24#include <linux/types.h>
25#include <linux/errno.h>
26#include <linux/init.h>
27#include <linux/kmsg_dump.h>
Anton Vorontsovf29e5952012-05-26 06:20:19 -070028#include <linux/console.h>
Tony Luckca01d6d2010-12-28 14:25:21 -080029#include <linux/module.h>
30#include <linux/pstore.h>
Geliang Tang8cfc8dd2016-02-18 22:04:22 +080031#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -070032#include <linux/zlib.h>
Geliang Tang8cfc8dd2016-02-18 22:04:22 +080033#endif
34#ifdef CONFIG_PSTORE_LZO_COMPRESS
35#include <linux/lzo.h>
36#endif
Geliang Tang239b7162018-02-13 14:40:39 +080037#if defined(CONFIG_PSTORE_LZ4_COMPRESS) || defined(CONFIG_PSTORE_LZ4HC_COMPRESS)
Geliang Tang8cfc8dd2016-02-18 22:04:22 +080038#include <linux/lz4.h>
39#endif
Geliang Tang239b7162018-02-13 14:40:39 +080040#ifdef CONFIG_PSTORE_842_COMPRESS
41#include <linux/sw842.h>
42#endif
Tony Luckca01d6d2010-12-28 14:25:21 -080043#include <linux/string.h>
Luck, Tony6dda9262011-08-11 15:14:39 -070044#include <linux/timer.h>
Tony Luckca01d6d2010-12-28 14:25:21 -080045#include <linux/slab.h>
46#include <linux/uaccess.h>
Anton Vorontsova3f5f072012-05-26 06:20:28 -070047#include <linux/jiffies.h>
Luck, Tony6dda9262011-08-11 15:14:39 -070048#include <linux/workqueue.h>
Tony Luckca01d6d2010-12-28 14:25:21 -080049
50#include "internal.h"
51
52/*
Luck, Tony6dda9262011-08-11 15:14:39 -070053 * We defer making "oops" entries appear in pstore - see
54 * whether the system is actually still running well enough
55 * to let someone see the entry
56 */
Anton Vorontsov521f72882012-05-26 06:20:29 -070057static int pstore_update_ms = -1;
Anton Vorontsova3f5f072012-05-26 06:20:28 -070058module_param_named(update_ms, pstore_update_ms, int, 0600);
59MODULE_PARM_DESC(update_ms, "milliseconds before pstore updates its content "
Anton Vorontsov521f72882012-05-26 06:20:29 -070060 "(default is -1, which means runtime updates are disabled; "
61 "enabling this option is not safe, it may lead to further "
62 "corruption on Oopses)");
Luck, Tony6dda9262011-08-11 15:14:39 -070063
64static int pstore_new_entry;
65
Kees Cook24ed9602017-08-28 11:28:21 -070066static void pstore_timefunc(struct timer_list *);
Kees Cook1d27e3e2017-10-04 16:27:04 -070067static DEFINE_TIMER(pstore_timer, pstore_timefunc);
Luck, Tony6dda9262011-08-11 15:14:39 -070068
69static void pstore_dowork(struct work_struct *);
70static DECLARE_WORK(pstore_work, pstore_dowork);
71
72/*
Tony Luckca01d6d2010-12-28 14:25:21 -080073 * pstore_lock just protects "psinfo" during
74 * calls to pstore_register()
75 */
76static DEFINE_SPINLOCK(pstore_lock);
Anton Vorontsov060287b2012-07-09 17:10:41 -070077struct pstore_info *psinfo;
Tony Luckca01d6d2010-12-28 14:25:21 -080078
Matthew Garrettdee28e72011-07-21 16:57:55 -040079static char *backend;
80
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -070081/* Compression parameters */
Geliang Tang8cfc8dd2016-02-18 22:04:22 +080082#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -070083#define COMPR_LEVEL 6
84#define WINDOW_BITS 12
85#define MEM_LEVEL 4
86static struct z_stream_s stream;
Geliang Tang8cfc8dd2016-02-18 22:04:22 +080087#else
88static unsigned char *workspace;
89#endif
90
91struct pstore_zbackend {
92 int (*compress)(const void *in, void *out, size_t inlen, size_t outlen);
93 int (*decompress)(void *in, void *out, size_t inlen, size_t outlen);
94 void (*allocate)(void);
95 void (*free)(void);
96
97 const char *name;
98};
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -070099
100static char *big_oops_buf;
101static size_t big_oops_buf_sz;
102
Luck, Tony366f7e72011-03-18 15:33:43 -0700103/* How much of the console log to snapshot */
David Howells349d7432017-07-05 16:24:34 +0100104unsigned long kmsg_bytes = PSTORE_DEFAULT_KMSG_BYTES;
Tony Luckca01d6d2010-12-28 14:25:21 -0800105
Luck, Tony366f7e72011-03-18 15:33:43 -0700106void pstore_set_kmsg_bytes(int bytes)
Tony Luckca01d6d2010-12-28 14:25:21 -0800107{
Luck, Tony366f7e72011-03-18 15:33:43 -0700108 kmsg_bytes = bytes;
Tony Luckca01d6d2010-12-28 14:25:21 -0800109}
110
Tony Luckca01d6d2010-12-28 14:25:21 -0800111/* Tag each group of saved records with a sequence number */
112static int oopscount;
113
Seiji Aguchi381b8722012-03-16 15:36:59 -0700114static const char *get_reason_str(enum kmsg_dump_reason reason)
115{
116 switch (reason) {
117 case KMSG_DUMP_PANIC:
118 return "Panic";
119 case KMSG_DUMP_OOPS:
120 return "Oops";
121 case KMSG_DUMP_EMERG:
122 return "Emergency";
123 case KMSG_DUMP_RESTART:
124 return "Restart";
125 case KMSG_DUMP_HALT:
126 return "Halt";
127 case KMSG_DUMP_POWEROFF:
128 return "Poweroff";
129 default:
130 return "Unknown";
131 }
132}
Tony Luck9f6af272011-03-22 16:01:49 -0700133
Seiji Aguchi9f244e92013-01-11 18:09:41 +0000134bool pstore_cannot_block_path(enum kmsg_dump_reason reason)
135{
136 /*
137 * In case of NMI path, pstore shouldn't be blocked
138 * regardless of reason.
139 */
140 if (in_nmi())
141 return true;
142
143 switch (reason) {
144 /* In panic case, other cpus are stopped by smp_send_stop(). */
145 case KMSG_DUMP_PANIC:
146 /* Emergency restart shouldn't be blocked by spin lock. */
147 case KMSG_DUMP_EMERG:
148 return true;
149 default:
150 return false;
151 }
152}
153EXPORT_SYMBOL_GPL(pstore_cannot_block_path);
154
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800155#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700156/* Derived from logfs_compress() */
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800157static int compress_zlib(const void *in, void *out, size_t inlen, size_t outlen)
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700158{
159 int err, ret;
160
161 ret = -EIO;
162 err = zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
163 MEM_LEVEL, Z_DEFAULT_STRATEGY);
164 if (err != Z_OK)
165 goto error;
166
167 stream.next_in = in;
168 stream.avail_in = inlen;
169 stream.total_in = 0;
170 stream.next_out = out;
171 stream.avail_out = outlen;
172 stream.total_out = 0;
173
174 err = zlib_deflate(&stream, Z_FINISH);
175 if (err != Z_STREAM_END)
176 goto error;
177
178 err = zlib_deflateEnd(&stream);
179 if (err != Z_OK)
180 goto error;
181
182 if (stream.total_out >= stream.total_in)
183 goto error;
184
185 ret = stream.total_out;
186error:
187 return ret;
188}
189
Aruna Balakrishnaiahadb42f52013-08-16 13:53:28 -0700190/* Derived from logfs_uncompress */
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800191static int decompress_zlib(void *in, void *out, size_t inlen, size_t outlen)
Aruna Balakrishnaiahadb42f52013-08-16 13:53:28 -0700192{
193 int err, ret;
194
195 ret = -EIO;
Aruna Balakrishnaiahb61edf82013-09-11 10:58:03 -0700196 err = zlib_inflateInit2(&stream, WINDOW_BITS);
Aruna Balakrishnaiahadb42f52013-08-16 13:53:28 -0700197 if (err != Z_OK)
198 goto error;
199
200 stream.next_in = in;
201 stream.avail_in = inlen;
202 stream.total_in = 0;
203 stream.next_out = out;
204 stream.avail_out = outlen;
205 stream.total_out = 0;
206
207 err = zlib_inflate(&stream, Z_FINISH);
208 if (err != Z_STREAM_END)
209 goto error;
210
211 err = zlib_inflateEnd(&stream);
212 if (err != Z_OK)
213 goto error;
214
215 ret = stream.total_out;
216error:
217 return ret;
218}
219
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800220static void allocate_zlib(void)
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700221{
222 size_t size;
Aruna Balakrishnaiah7de8fe22013-09-11 10:57:41 -0700223 size_t cmpr;
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700224
Aruna Balakrishnaiah7de8fe22013-09-11 10:57:41 -0700225 switch (psinfo->bufsize) {
226 /* buffer range for efivars */
227 case 1000 ... 2000:
228 cmpr = 56;
229 break;
230 case 2001 ... 3000:
231 cmpr = 54;
232 break;
233 case 3001 ... 3999:
234 cmpr = 52;
235 break;
236 /* buffer range for nvram, erst */
237 case 4000 ... 10000:
238 cmpr = 45;
239 break;
240 default:
241 cmpr = 60;
242 break;
243 }
244
245 big_oops_buf_sz = (psinfo->bufsize * 100) / cmpr;
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700246 big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
247 if (big_oops_buf) {
248 size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
249 zlib_inflate_workspacesize());
250 stream.workspace = kmalloc(size, GFP_KERNEL);
251 if (!stream.workspace) {
Fabian Frederickef748852014-06-06 14:37:31 -0700252 pr_err("No memory for compression workspace; skipping compression\n");
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700253 kfree(big_oops_buf);
254 big_oops_buf = NULL;
255 }
256 } else {
Fabian Frederickef748852014-06-06 14:37:31 -0700257 pr_err("No memory for uncompressed data; skipping compression\n");
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700258 stream.workspace = NULL;
259 }
260
261}
262
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800263static void free_zlib(void)
Geliang Tangee1d2672015-10-20 00:39:03 -0700264{
265 kfree(stream.workspace);
266 stream.workspace = NULL;
267 kfree(big_oops_buf);
268 big_oops_buf = NULL;
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800269 big_oops_buf_sz = 0;
270}
271
Bhumika Goyal3faf9352017-02-19 15:07:53 +0530272static const struct pstore_zbackend backend_zlib = {
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800273 .compress = compress_zlib,
274 .decompress = decompress_zlib,
275 .allocate = allocate_zlib,
276 .free = free_zlib,
277 .name = "zlib",
278};
279#endif
280
281#ifdef CONFIG_PSTORE_LZO_COMPRESS
282static int compress_lzo(const void *in, void *out, size_t inlen, size_t outlen)
283{
284 int ret;
285
286 ret = lzo1x_1_compress(in, inlen, out, &outlen, workspace);
287 if (ret != LZO_E_OK) {
288 pr_err("lzo_compress error, ret = %d!\n", ret);
289 return -EIO;
290 }
291
292 return outlen;
293}
294
295static int decompress_lzo(void *in, void *out, size_t inlen, size_t outlen)
296{
297 int ret;
298
299 ret = lzo1x_decompress_safe(in, inlen, out, &outlen);
300 if (ret != LZO_E_OK) {
301 pr_err("lzo_decompress error, ret = %d!\n", ret);
302 return -EIO;
303 }
304
305 return outlen;
306}
307
308static void allocate_lzo(void)
309{
310 big_oops_buf_sz = lzo1x_worst_compress(psinfo->bufsize);
311 big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
312 if (big_oops_buf) {
313 workspace = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
314 if (!workspace) {
315 pr_err("No memory for compression workspace; skipping compression\n");
316 kfree(big_oops_buf);
317 big_oops_buf = NULL;
318 }
319 } else {
320 pr_err("No memory for uncompressed data; skipping compression\n");
321 workspace = NULL;
322 }
323}
324
325static void free_lzo(void)
326{
327 kfree(workspace);
328 kfree(big_oops_buf);
329 big_oops_buf = NULL;
330 big_oops_buf_sz = 0;
331}
332
Bhumika Goyal3faf9352017-02-19 15:07:53 +0530333static const struct pstore_zbackend backend_lzo = {
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800334 .compress = compress_lzo,
335 .decompress = decompress_lzo,
336 .allocate = allocate_lzo,
337 .free = free_lzo,
338 .name = "lzo",
339};
340#endif
341
Geliang Tang239b7162018-02-13 14:40:39 +0800342#if defined(CONFIG_PSTORE_LZ4_COMPRESS) || defined(CONFIG_PSTORE_LZ4HC_COMPRESS)
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800343static int decompress_lz4(void *in, void *out, size_t inlen, size_t outlen)
344{
345 int ret;
346
Sven Schmidtd21b5ff122017-02-24 15:01:22 -0800347 ret = LZ4_decompress_safe(in, out, inlen, outlen);
348 if (ret < 0) {
349 /*
350 * LZ4_decompress_safe will return an error code
351 * (< 0) if decompression failed
352 */
353 pr_err("LZ4_decompress_safe error, ret = %d!\n", ret);
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800354 return -EIO;
355 }
356
Sven Schmidtd21b5ff122017-02-24 15:01:22 -0800357 return ret;
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800358}
359
Geliang Tang239b7162018-02-13 14:40:39 +0800360static void free_lz4(void)
361{
362 kfree(workspace);
363 kfree(big_oops_buf);
364 big_oops_buf = NULL;
365 big_oops_buf_sz = 0;
366}
367#endif
368
369#ifdef CONFIG_PSTORE_LZ4_COMPRESS
370static int compress_lz4(const void *in, void *out, size_t inlen, size_t outlen)
371{
372 int ret;
373
374 ret = LZ4_compress_default(in, out, inlen, outlen, workspace);
375 if (!ret) {
376 pr_err("LZ4_compress_default error; compression failed!\n");
377 return -EIO;
378 }
379
380 return ret;
381}
382
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800383static void allocate_lz4(void)
384{
Sven Schmidtd21b5ff122017-02-24 15:01:22 -0800385 big_oops_buf_sz = LZ4_compressBound(psinfo->bufsize);
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800386 big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
387 if (big_oops_buf) {
388 workspace = kmalloc(LZ4_MEM_COMPRESS, GFP_KERNEL);
389 if (!workspace) {
390 pr_err("No memory for compression workspace; skipping compression\n");
391 kfree(big_oops_buf);
392 big_oops_buf = NULL;
393 }
394 } else {
395 pr_err("No memory for uncompressed data; skipping compression\n");
396 workspace = NULL;
397 }
398}
399
Geliang Tang239b7162018-02-13 14:40:39 +0800400static const struct pstore_zbackend backend_lz4 = {
401 .compress = compress_lz4,
402 .decompress = decompress_lz4,
403 .allocate = allocate_lz4,
404 .free = free_lz4,
405 .name = "lz4",
406};
407#endif
408
409#ifdef CONFIG_PSTORE_LZ4HC_COMPRESS
410static int compress_lz4hc(const void *in, void *out,
411 size_t inlen, size_t outlen)
412{
413 int ret;
414
415 ret = LZ4_compress_HC(in, out, inlen, outlen,
416 LZ4HC_DEFAULT_CLEVEL, workspace);
417 if (!ret) {
418 pr_err("LZ4_compress_HC error; compression failed!\n");
419 return -EIO;
420 }
421
422 return ret;
423}
424
425static void allocate_lz4hc(void)
426{
427 big_oops_buf_sz = LZ4_compressBound(psinfo->bufsize);
428 big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
429 if (big_oops_buf) {
430 workspace = kmalloc(LZ4HC_MEM_COMPRESS, GFP_KERNEL);
431 if (!workspace) {
432 pr_err("No memory for compression workspace; skipping compression\n");
433 kfree(big_oops_buf);
434 big_oops_buf = NULL;
435 }
436 } else {
437 pr_err("No memory for uncompressed data; skipping compression\n");
438 workspace = NULL;
439 }
440}
441
442static const struct pstore_zbackend backend_lz4hc = {
443 .compress = compress_lz4hc,
444 .decompress = decompress_lz4,
445 .allocate = allocate_lz4hc,
446 .free = free_lz4,
447 .name = "lz4hc",
448};
449#endif
450
451#ifdef CONFIG_PSTORE_842_COMPRESS
452static int compress_842(const void *in, void *out, size_t inlen, size_t outlen)
453{
454 int ret;
455
456 ret = sw842_compress(in, inlen, out, (unsigned int *)&outlen, workspace);
457 if (ret) {
458 pr_err("sw842_compress error; compression failed!\n");
459 return ret;
460 }
461
462 return outlen;
463}
464
465static int decompress_842(void *in, void *out, size_t inlen, size_t outlen)
466{
467 int ret;
468
469 ret = sw842_decompress(in, inlen, out, (unsigned int *)&outlen);
470 if (ret) {
471 pr_err("sw842_decompress error, ret = %d!\n", ret);
472 return ret;
473 }
474
475 return outlen;
476}
477
478static void allocate_842(void)
479{
480 big_oops_buf_sz = psinfo->bufsize;
481 big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
482 if (big_oops_buf) {
483 workspace = kmalloc(SW842_MEM_COMPRESS, GFP_KERNEL);
484 if (!workspace) {
485 kfree(big_oops_buf);
486 big_oops_buf = NULL;
487 }
488 } else {
489 pr_err("No memory for uncompressed data; skipping compression\n");
490 workspace = NULL;
491 }
492}
493
494static void free_842(void)
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800495{
496 kfree(workspace);
497 kfree(big_oops_buf);
498 big_oops_buf = NULL;
499 big_oops_buf_sz = 0;
500}
501
Geliang Tang239b7162018-02-13 14:40:39 +0800502static const struct pstore_zbackend backend_842 = {
503 .compress = compress_842,
504 .decompress = decompress_842,
505 .allocate = allocate_842,
506 .free = free_842,
507 .name = "842",
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800508};
509#endif
510
Bhumika Goyal3faf9352017-02-19 15:07:53 +0530511static const struct pstore_zbackend *zbackend =
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800512#if defined(CONFIG_PSTORE_ZLIB_COMPRESS)
513 &backend_zlib;
514#elif defined(CONFIG_PSTORE_LZO_COMPRESS)
515 &backend_lzo;
516#elif defined(CONFIG_PSTORE_LZ4_COMPRESS)
517 &backend_lz4;
Geliang Tang239b7162018-02-13 14:40:39 +0800518#elif defined(CONFIG_PSTORE_LZ4HC_COMPRESS)
519 &backend_lz4hc;
520#elif defined(CONFIG_PSTORE_842_COMPRESS)
521 &backend_842;
Geliang Tang8cfc8dd2016-02-18 22:04:22 +0800522#else
523 NULL;
524#endif
525
526static int pstore_compress(const void *in, void *out,
527 size_t inlen, size_t outlen)
528{
529 if (zbackend)
530 return zbackend->compress(in, out, inlen, outlen);
531 else
532 return -EIO;
533}
534
535static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen)
536{
537 if (zbackend)
538 return zbackend->decompress(in, out, inlen, outlen);
539 else
540 return -EIO;
541}
542
543static void allocate_buf_for_compression(void)
544{
545 if (zbackend) {
546 pr_info("using %s compression\n", zbackend->name);
547 zbackend->allocate();
548 } else {
549 pr_err("allocate compression buffer error!\n");
550 }
551}
552
553static void free_buf_for_compression(void)
554{
555 if (zbackend)
556 zbackend->free();
557 else
558 pr_err("free compression buffer error!\n");
Geliang Tangee1d2672015-10-20 00:39:03 -0700559}
560
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700561/*
562 * Called when compression fails, since the printk buffer
563 * would be fetched for compression calling it again when
564 * compression fails would have moved the iterator of
565 * printk buffer which results in fetching old contents.
566 * Copy the recent messages from big_oops_buf to psinfo->buf
567 */
568static size_t copy_kmsg_to_buffer(int hsize, size_t len)
569{
570 size_t total_len;
571 size_t diff;
572
573 total_len = hsize + len;
574
575 if (total_len > psinfo->bufsize) {
576 diff = total_len - psinfo->bufsize + hsize;
577 memcpy(psinfo->buf, big_oops_buf, hsize);
578 memcpy(psinfo->buf + hsize, big_oops_buf + diff,
579 psinfo->bufsize - hsize);
580 total_len = psinfo->bufsize;
581 } else
582 memcpy(psinfo->buf, big_oops_buf, total_len);
583
584 return total_len;
585}
586
Kees Cooke581ca82017-05-19 15:10:31 -0700587void pstore_record_init(struct pstore_record *record,
588 struct pstore_info *psinfo)
589{
590 memset(record, 0, sizeof(*record));
591
592 record->psi = psinfo;
Kees Cookc7f3c5952017-05-19 15:29:10 -0700593
594 /* Report zeroed timestamp if called before timekeeping has resumed. */
Arnd Bergmanndf270672017-11-10 16:25:04 +0100595 record->time = ns_to_timespec(ktime_get_real_fast_ns());
Kees Cooke581ca82017-05-19 15:10:31 -0700596}
597
Tony Luckca01d6d2010-12-28 14:25:21 -0800598/*
599 * callback from kmsg_dump. (s2,l2) has the most recently
600 * written bytes, older bytes are in (s1,l1). Save as much
601 * as we can from the end of the buffer.
602 */
603static void pstore_dump(struct kmsg_dumper *dumper,
Kay Sieverse2ae7152012-06-15 14:07:51 +0200604 enum kmsg_dump_reason reason)
Tony Luckca01d6d2010-12-28 14:25:21 -0800605{
Kay Sieverse2ae7152012-06-15 14:07:51 +0200606 unsigned long total = 0;
Seiji Aguchi381b8722012-03-16 15:36:59 -0700607 const char *why;
Matthew Garrettb94fdd02011-07-21 16:57:54 -0400608 unsigned int part = 1;
Don Zickusabd4d552011-08-12 10:54:51 -0700609 unsigned long flags = 0;
Namhyung Kim98e44fda2016-05-18 21:00:05 +0900610 int is_locked;
Kay Sieverse2ae7152012-06-15 14:07:51 +0200611 int ret;
Tony Luckca01d6d2010-12-28 14:25:21 -0800612
Seiji Aguchi381b8722012-03-16 15:36:59 -0700613 why = get_reason_str(reason);
Tony Luck9f6af272011-03-22 16:01:49 -0700614
Seiji Aguchi9f244e92013-01-11 18:09:41 +0000615 if (pstore_cannot_block_path(reason)) {
616 is_locked = spin_trylock_irqsave(&psinfo->buf_lock, flags);
617 if (!is_locked) {
618 pr_err("pstore dump routine blocked in %s path, may corrupt error record\n"
619 , in_nmi() ? "NMI" : why);
Li Pengcheng959217c2016-11-05 10:15:59 +0800620 return;
Seiji Aguchi9f244e92013-01-11 18:09:41 +0000621 }
Namhyung Kim98e44fda2016-05-18 21:00:05 +0900622 } else {
Don Zickusabd4d552011-08-12 10:54:51 -0700623 spin_lock_irqsave(&psinfo->buf_lock, flags);
Namhyung Kim98e44fda2016-05-18 21:00:05 +0900624 is_locked = 1;
625 }
Tony Luckca01d6d2010-12-28 14:25:21 -0800626 oopscount++;
627 while (total < kmsg_bytes) {
Kay Sieverse2ae7152012-06-15 14:07:51 +0200628 char *dst;
Kees Cook76cc9582017-03-03 23:28:53 -0800629 size_t dst_size;
630 int header_size;
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700631 int zipped_len = -1;
Kees Cook76cc9582017-03-03 23:28:53 -0800632 size_t dump_size;
Kees Cooke581ca82017-05-19 15:10:31 -0700633 struct pstore_record record;
634
635 pstore_record_init(&record, psinfo);
636 record.type = PSTORE_TYPE_DMESG;
637 record.count = oopscount;
638 record.reason = reason;
639 record.part = part;
640 record.buf = psinfo->buf;
Kay Sieverse2ae7152012-06-15 14:07:51 +0200641
Konstantin Khlebnikovf0e2efc2015-05-21 09:26:19 -0700642 if (big_oops_buf && is_locked) {
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700643 dst = big_oops_buf;
Kees Cook76cc9582017-03-03 23:28:53 -0800644 dst_size = big_oops_buf_sz;
Namhyung Kim235f6d12016-05-18 21:00:06 +0900645 } else {
646 dst = psinfo->buf;
Kees Cook76cc9582017-03-03 23:28:53 -0800647 dst_size = psinfo->bufsize;
Namhyung Kim235f6d12016-05-18 21:00:06 +0900648 }
Tony Luckca01d6d2010-12-28 14:25:21 -0800649
Kees Cook76cc9582017-03-03 23:28:53 -0800650 /* Write dump header. */
651 header_size = snprintf(dst, dst_size, "%s#%d Part%u\n", why,
652 oopscount, part);
653 dst_size -= header_size;
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700654
Kees Cook76cc9582017-03-03 23:28:53 -0800655 /* Write dump contents. */
656 if (!kmsg_dump_get_buffer(dumper, true, dst + header_size,
657 dst_size, &dump_size))
Namhyung Kim235f6d12016-05-18 21:00:06 +0900658 break;
659
660 if (big_oops_buf && is_locked) {
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700661 zipped_len = pstore_compress(dst, psinfo->buf,
Kees Cook76cc9582017-03-03 23:28:53 -0800662 header_size + dump_size,
663 psinfo->bufsize);
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700664
665 if (zipped_len > 0) {
Kees Cook76cc9582017-03-03 23:28:53 -0800666 record.compressed = true;
667 record.size = zipped_len;
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700668 } else {
Kees Cook76cc9582017-03-03 23:28:53 -0800669 record.size = copy_kmsg_to_buffer(header_size,
670 dump_size);
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700671 }
672 } else {
Kees Cook76cc9582017-03-03 23:28:53 -0800673 record.size = header_size + dump_size;
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700674 }
Tony Luckca01d6d2010-12-28 14:25:21 -0800675
Kees Cook76cc9582017-03-03 23:28:53 -0800676 ret = psinfo->write(&record);
Chen Gongb238b8f2011-10-12 09:17:24 -0700677 if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
Luck, Tony6dda9262011-08-11 15:14:39 -0700678 pstore_new_entry = 1;
Kay Sieverse2ae7152012-06-15 14:07:51 +0200679
Kees Cook76cc9582017-03-03 23:28:53 -0800680 total += record.size;
Matthew Garrett56280682011-07-21 16:57:53 -0400681 part++;
Tony Luckca01d6d2010-12-28 14:25:21 -0800682 }
Namhyung Kim98e44fda2016-05-18 21:00:05 +0900683 if (is_locked)
Don Zickusabd4d552011-08-12 10:54:51 -0700684 spin_unlock_irqrestore(&psinfo->buf_lock, flags);
Tony Luckca01d6d2010-12-28 14:25:21 -0800685}
686
687static struct kmsg_dumper pstore_dumper = {
688 .dump = pstore_dump,
689};
690
Geliang Tang306e5c22015-10-31 23:23:15 +0800691/*
692 * Register with kmsg_dump to save last part of console log on panic.
693 */
Geliang Tang18730412015-10-20 00:39:02 -0700694static void pstore_register_kmsg(void)
695{
696 kmsg_dump_register(&pstore_dumper);
697}
698
Geliang Tangee1d2672015-10-20 00:39:03 -0700699static void pstore_unregister_kmsg(void)
700{
701 kmsg_dump_unregister(&pstore_dumper);
702}
703
Anton Vorontsovf29e5952012-05-26 06:20:19 -0700704#ifdef CONFIG_PSTORE_CONSOLE
705static void pstore_console_write(struct console *con, const char *s, unsigned c)
706{
707 const char *e = s + c;
708
709 while (s < e) {
Kees Cooke581ca82017-05-19 15:10:31 -0700710 struct pstore_record record;
Anton Vorontsovf29e5952012-05-26 06:20:19 -0700711 unsigned long flags;
712
Kees Cooke581ca82017-05-19 15:10:31 -0700713 pstore_record_init(&record, psinfo);
714 record.type = PSTORE_TYPE_CONSOLE;
715
Anton Vorontsovf29e5952012-05-26 06:20:19 -0700716 if (c > psinfo->bufsize)
717 c = psinfo->bufsize;
Chuansheng Liu80c9d032012-09-18 01:43:44 +0800718
719 if (oops_in_progress) {
720 if (!spin_trylock_irqsave(&psinfo->buf_lock, flags))
721 break;
722 } else {
723 spin_lock_irqsave(&psinfo->buf_lock, flags);
724 }
Kees Cookb10b4712017-03-05 00:27:54 -0800725 record.buf = (char *)s;
726 record.size = c;
Kees Cook4c9ec212017-03-05 22:41:10 -0800727 psinfo->write(&record);
Anton Vorontsovf29e5952012-05-26 06:20:19 -0700728 spin_unlock_irqrestore(&psinfo->buf_lock, flags);
729 s += c;
730 c = e - s;
731 }
732}
733
734static struct console pstore_console = {
735 .name = "pstore",
736 .write = pstore_console_write,
737 .flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME,
738 .index = -1,
739};
740
741static void pstore_register_console(void)
742{
743 register_console(&pstore_console);
744}
Geliang Tangee1d2672015-10-20 00:39:03 -0700745
746static void pstore_unregister_console(void)
747{
748 unregister_console(&pstore_console);
749}
Anton Vorontsovf29e5952012-05-26 06:20:19 -0700750#else
751static void pstore_register_console(void) {}
Geliang Tangee1d2672015-10-20 00:39:03 -0700752static void pstore_unregister_console(void) {}
Anton Vorontsovf29e5952012-05-26 06:20:19 -0700753#endif
754
Kees Cook4c9ec212017-03-05 22:41:10 -0800755static int pstore_write_user_compat(struct pstore_record *record,
756 const char __user *buf)
Mark Salyzyn5bf6d1b2016-09-01 08:13:46 -0700757{
Kees Cook30800d92017-03-07 13:57:11 -0800758 int ret = 0;
Mark Salyzyn5bf6d1b2016-09-01 08:13:46 -0700759
Kees Cook30800d92017-03-07 13:57:11 -0800760 if (record->buf)
761 return -EINVAL;
Mark Salyzyn5bf6d1b2016-09-01 08:13:46 -0700762
Geliang Tang077090a2017-04-29 09:45:16 +0800763 record->buf = memdup_user(buf, record->size);
Hirofumi Nakagawadfd6fa32017-09-26 03:21:27 +0900764 if (IS_ERR(record->buf)) {
Geliang Tang077090a2017-04-29 09:45:16 +0800765 ret = PTR_ERR(record->buf);
Kees Cook30800d92017-03-07 13:57:11 -0800766 goto out;
Mark Salyzyn5bf6d1b2016-09-01 08:13:46 -0700767 }
Kees Cook30800d92017-03-07 13:57:11 -0800768
769 ret = record->psi->write(record);
770
Kees Cook30800d92017-03-07 13:57:11 -0800771 kfree(record->buf);
Geliang Tang077090a2017-04-29 09:45:16 +0800772out:
Kees Cook30800d92017-03-07 13:57:11 -0800773 record->buf = NULL;
774
775 return unlikely(ret < 0) ? ret : record->size;
Mark Salyzyn5bf6d1b2016-09-01 08:13:46 -0700776}
777
Tony Luckca01d6d2010-12-28 14:25:21 -0800778/*
779 * platform specific persistent storage driver registers with
780 * us here. If pstore is already mounted, call the platform
781 * read function right away to populate the file system. If not
782 * then the pstore mount code will call us later to fill out
783 * the file system.
Tony Luckca01d6d2010-12-28 14:25:21 -0800784 */
785int pstore_register(struct pstore_info *psi)
786{
787 struct module *owner = psi->owner;
788
Kees Cook0d7cd092017-03-03 12:11:40 -0800789 if (backend && strcmp(backend, psi->name)) {
790 pr_warn("ignoring unexpected backend '%s'\n", psi->name);
Lenny Szubowicz8e48b1a2013-06-28 17:11:33 -0400791 return -EPERM;
Kees Cook0d7cd092017-03-03 12:11:40 -0800792 }
Lenny Szubowicz8e48b1a2013-06-28 17:11:33 -0400793
Kees Cook4c9ec212017-03-05 22:41:10 -0800794 /* Sanity check flags. */
795 if (!psi->flags) {
796 pr_warn("backend '%s' must support at least one frontend\n",
797 psi->name);
798 return -EINVAL;
799 }
800
801 /* Check for required functions. */
802 if (!psi->read || !psi->write) {
803 pr_warn("backend '%s' must implement read() and write()\n",
804 psi->name);
805 return -EINVAL;
806 }
807
Tony Luckca01d6d2010-12-28 14:25:21 -0800808 spin_lock(&pstore_lock);
809 if (psinfo) {
Kees Cook0d7cd092017-03-03 12:11:40 -0800810 pr_warn("backend '%s' already loaded: ignoring '%s'\n",
811 psinfo->name, psi->name);
Tony Luckca01d6d2010-12-28 14:25:21 -0800812 spin_unlock(&pstore_lock);
813 return -EBUSY;
814 }
Matthew Garrettdee28e72011-07-21 16:57:55 -0400815
Kees Cook4c9ec212017-03-05 22:41:10 -0800816 if (!psi->write_user)
817 psi->write_user = pstore_write_user_compat;
Tony Luckca01d6d2010-12-28 14:25:21 -0800818 psinfo = psi;
Kees Cookf6f82852011-11-17 12:58:07 -0800819 mutex_init(&psinfo->read_mutex);
Tony Luckca01d6d2010-12-28 14:25:21 -0800820 spin_unlock(&pstore_lock);
821
822 if (owner && !try_module_get(owner)) {
823 psinfo = NULL;
824 return -EINVAL;
825 }
826
Aruna Balakrishnaiahb0aad7a2013-08-16 13:53:10 -0700827 allocate_buf_for_compression();
828
Tony Luckca01d6d2010-12-28 14:25:21 -0800829 if (pstore_is_mounted())
Luck, Tony6dda9262011-08-11 15:14:39 -0700830 pstore_get_records(0);
Tony Luckca01d6d2010-12-28 14:25:21 -0800831
Namhyung Kimc950fd62016-07-28 00:08:25 +0900832 if (psi->flags & PSTORE_FLAGS_DMESG)
833 pstore_register_kmsg();
834 if (psi->flags & PSTORE_FLAGS_CONSOLE)
Luck, Tonydf36ac12013-12-18 15:17:10 -0800835 pstore_register_console();
Namhyung Kimc950fd62016-07-28 00:08:25 +0900836 if (psi->flags & PSTORE_FLAGS_FTRACE)
Luck, Tonydf36ac12013-12-18 15:17:10 -0800837 pstore_register_ftrace();
Namhyung Kimc950fd62016-07-28 00:08:25 +0900838 if (psi->flags & PSTORE_FLAGS_PMSG)
Mark Salyzyn9d5438f2015-01-16 16:01:10 -0800839 pstore_register_pmsg();
Tony Luckca01d6d2010-12-28 14:25:21 -0800840
Kees Cook6330d552017-03-06 12:42:12 -0800841 /* Start watching for new records, if desired. */
Anton Vorontsova3f5f072012-05-26 06:20:28 -0700842 if (pstore_update_ms >= 0) {
843 pstore_timer.expires = jiffies +
844 msecs_to_jiffies(pstore_update_ms);
845 add_timer(&pstore_timer);
846 }
Luck, Tony6dda9262011-08-11 15:14:39 -0700847
Wang Long42222c22015-05-21 09:34:22 -0700848 /*
849 * Update the module parameter backend, so it is visible
850 * through /sys/module/pstore/parameters/backend
851 */
852 backend = psi->name;
853
Fabian Frederickef748852014-06-06 14:37:31 -0700854 pr_info("Registered %s as persistent store backend\n", psi->name);
Lenny Szubowicz8e48b1a2013-06-28 17:11:33 -0400855
Kees Cook1344dd82017-03-03 17:45:38 -0800856 module_put(owner);
857
Tony Luckca01d6d2010-12-28 14:25:21 -0800858 return 0;
859}
860EXPORT_SYMBOL_GPL(pstore_register);
861
Geliang Tangee1d2672015-10-20 00:39:03 -0700862void pstore_unregister(struct pstore_info *psi)
863{
Kees Cook6330d552017-03-06 12:42:12 -0800864 /* Stop timer and make sure all work has finished. */
865 pstore_update_ms = -1;
866 del_timer_sync(&pstore_timer);
867 flush_work(&pstore_work);
868
Namhyung Kimc950fd62016-07-28 00:08:25 +0900869 if (psi->flags & PSTORE_FLAGS_PMSG)
Kees Cooka1db8062016-05-19 10:59:03 -0400870 pstore_unregister_pmsg();
Namhyung Kimc950fd62016-07-28 00:08:25 +0900871 if (psi->flags & PSTORE_FLAGS_FTRACE)
Kees Cooka1db8062016-05-19 10:59:03 -0400872 pstore_unregister_ftrace();
Namhyung Kimc950fd62016-07-28 00:08:25 +0900873 if (psi->flags & PSTORE_FLAGS_CONSOLE)
Kees Cooka1db8062016-05-19 10:59:03 -0400874 pstore_unregister_console();
Namhyung Kimc950fd62016-07-28 00:08:25 +0900875 if (psi->flags & PSTORE_FLAGS_DMESG)
876 pstore_unregister_kmsg();
Geliang Tangee1d2672015-10-20 00:39:03 -0700877
878 free_buf_for_compression();
879
880 psinfo = NULL;
881 backend = NULL;
882}
883EXPORT_SYMBOL_GPL(pstore_unregister);
884
Kees Cook634f8f52017-03-03 17:35:25 -0800885static void decompress_record(struct pstore_record *record)
886{
887 int unzipped_len;
Kees Cook7e8cc8d2017-03-04 22:28:46 -0800888 char *decompressed;
Kees Cook634f8f52017-03-03 17:35:25 -0800889
Ankit Kumar4a16d1c2017-05-23 11:16:52 +0530890 if (!record->compressed)
891 return;
892
Kees Cook634f8f52017-03-03 17:35:25 -0800893 /* Only PSTORE_TYPE_DMESG support compression. */
Ankit Kumar4a16d1c2017-05-23 11:16:52 +0530894 if (record->type != PSTORE_TYPE_DMESG) {
Kees Cook634f8f52017-03-03 17:35:25 -0800895 pr_warn("ignored compressed record type %d\n", record->type);
896 return;
897 }
898
899 /* No compression method has created the common buffer. */
900 if (!big_oops_buf) {
901 pr_warn("no decompression buffer allocated\n");
902 return;
903 }
904
905 unzipped_len = pstore_decompress(record->buf, big_oops_buf,
906 record->size, big_oops_buf_sz);
Kees Cook7e8cc8d2017-03-04 22:28:46 -0800907 if (unzipped_len <= 0) {
Kees Cook634f8f52017-03-03 17:35:25 -0800908 pr_err("decompression failed: %d\n", unzipped_len);
Kees Cook7e8cc8d2017-03-04 22:28:46 -0800909 return;
910 }
911
912 /* Build new buffer for decompressed contents. */
913 decompressed = kmalloc(unzipped_len + record->ecc_notice_size,
914 GFP_KERNEL);
915 if (!decompressed) {
916 pr_err("decompression ran out of memory\n");
917 return;
918 }
919 memcpy(decompressed, big_oops_buf, unzipped_len);
920
921 /* Append ECC notice to decompressed buffer. */
922 memcpy(decompressed + unzipped_len, record->buf + record->size,
923 record->ecc_notice_size);
924
925 /* Swap out compresed contents with decompressed contents. */
926 kfree(record->buf);
927 record->buf = decompressed;
928 record->size = unzipped_len;
929 record->compressed = false;
Kees Cook634f8f52017-03-03 17:35:25 -0800930}
931
Tony Luckca01d6d2010-12-28 14:25:21 -0800932/*
Kees Cook3a7d2fd2017-04-27 15:53:21 -0700933 * Read all the records from one persistent store backend. Create
Luck, Tony6dda9262011-08-11 15:14:39 -0700934 * files in our filesystem. Don't warn about -EEXIST errors
935 * when we are re-scanning the backing store looking to add new
936 * error records.
Tony Luckca01d6d2010-12-28 14:25:21 -0800937 */
Kees Cook3a7d2fd2017-04-27 15:53:21 -0700938void pstore_get_backend_records(struct pstore_info *psi,
939 struct dentry *root, int quiet)
Tony Luckca01d6d2010-12-28 14:25:21 -0800940{
Kees Cook2a2b0ac2017-03-04 22:57:26 -0800941 int failed = 0;
Kees Cook656de422017-05-16 12:03:31 -0700942 unsigned int stop_loop = 65536;
Tony Luckca01d6d2010-12-28 14:25:21 -0800943
Kees Cook3a7d2fd2017-04-27 15:53:21 -0700944 if (!psi || !root)
Tony Luckca01d6d2010-12-28 14:25:21 -0800945 return;
946
Kees Cookf6f82852011-11-17 12:58:07 -0800947 mutex_lock(&psi->read_mutex);
Kees Cook2174f6d2011-11-18 13:49:00 -0800948 if (psi->open && psi->open(psi))
Chen Gong06cf91b2011-05-16 11:00:27 -0700949 goto out;
950
Kees Cook1dfff7d2017-03-04 22:46:41 -0800951 /*
952 * Backend callback read() allocates record.buf. decompress_record()
953 * may reallocate record.buf. On success, pstore_mkfile() will keep
954 * the record.buf, so free it only on failure.
955 */
Kees Cook656de422017-05-16 12:03:31 -0700956 for (; stop_loop; stop_loop--) {
Kees Cook2a2b0ac2017-03-04 22:57:26 -0800957 struct pstore_record *record;
958 int rc;
959
960 record = kzalloc(sizeof(*record), GFP_KERNEL);
961 if (!record) {
962 pr_err("out of memory creating record\n");
963 break;
964 }
Kees Cooke581ca82017-05-19 15:10:31 -0700965 pstore_record_init(record, psi);
Kees Cook2a2b0ac2017-03-04 22:57:26 -0800966
967 record->size = psi->read(record);
968
969 /* No more records left in backend? */
Douglas Andersonf6525b92017-05-30 15:50:38 -0700970 if (record->size <= 0) {
971 kfree(record);
Kees Cook2a2b0ac2017-03-04 22:57:26 -0800972 break;
Douglas Andersonf6525b92017-05-30 15:50:38 -0700973 }
Kees Cook2a2b0ac2017-03-04 22:57:26 -0800974
975 decompress_record(record);
Kees Cook3a7d2fd2017-04-27 15:53:21 -0700976 rc = pstore_mkfile(root, record);
Kees Cook1dfff7d2017-03-04 22:46:41 -0800977 if (rc) {
Kees Cook83f70f02017-03-04 23:12:24 -0800978 /* pstore_mkfile() did not take record, so free it. */
Kees Cook2a2b0ac2017-03-04 22:57:26 -0800979 kfree(record->buf);
Kees Cook83f70f02017-03-04 23:12:24 -0800980 kfree(record);
Kees Cook1dfff7d2017-03-04 22:46:41 -0800981 if (rc != -EEXIST || !quiet)
982 failed++;
983 }
Tony Luckca01d6d2010-12-28 14:25:21 -0800984 }
Kees Cook2174f6d2011-11-18 13:49:00 -0800985 if (psi->close)
986 psi->close(psi);
Chen Gong06cf91b2011-05-16 11:00:27 -0700987out:
Kees Cookf6f82852011-11-17 12:58:07 -0800988 mutex_unlock(&psi->read_mutex);
Tony Luckca01d6d2010-12-28 14:25:21 -0800989
990 if (failed)
Kees Cook656de422017-05-16 12:03:31 -0700991 pr_warn("failed to create %d record(s) from '%s'\n",
Fabian Frederickef748852014-06-06 14:37:31 -0700992 failed, psi->name);
Kees Cook656de422017-05-16 12:03:31 -0700993 if (!stop_loop)
994 pr_err("looping? Too many records seen from '%s'\n",
995 psi->name);
Tony Luckca01d6d2010-12-28 14:25:21 -0800996}
997
Luck, Tony6dda9262011-08-11 15:14:39 -0700998static void pstore_dowork(struct work_struct *work)
999{
1000 pstore_get_records(1);
1001}
1002
Kees Cook24ed9602017-08-28 11:28:21 -07001003static void pstore_timefunc(struct timer_list *unused)
Luck, Tony6dda9262011-08-11 15:14:39 -07001004{
1005 if (pstore_new_entry) {
1006 pstore_new_entry = 0;
1007 schedule_work(&pstore_work);
1008 }
1009
Kees Cook6330d552017-03-06 12:42:12 -08001010 if (pstore_update_ms >= 0)
1011 mod_timer(&pstore_timer,
1012 jiffies + msecs_to_jiffies(pstore_update_ms));
Luck, Tony6dda9262011-08-11 15:14:39 -07001013}
1014
Matthew Garrettdee28e72011-07-21 16:57:55 -04001015module_param(backend, charp, 0444);
1016MODULE_PARM_DESC(backend, "Pstore backend to use");