aboutsummaryrefslogtreecommitdiffstats
path: root/fs/pstore
diff options
context:
space:
mode:
Diffstat (limited to 'fs/pstore')
-rw-r--r--fs/pstore/Kconfig2
-rw-r--r--fs/pstore/inode.c10
-rw-r--r--fs/pstore/internal.h5
-rw-r--r--fs/pstore/platform.c229
-rw-r--r--fs/pstore/ram.c47
5 files changed, 259 insertions, 34 deletions
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index ca71db69da07..983d9510becc 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -1,6 +1,8 @@
1config PSTORE 1config PSTORE
2 bool "Persistent store support" 2 bool "Persistent store support"
3 default n 3 default n
4 select ZLIB_DEFLATE
5 select ZLIB_INFLATE
4 help 6 help
5 This option enables generic access to platform level 7 This option enables generic access to platform level
6 persistent storage via "pstore" filesystem that can 8 persistent storage via "pstore" filesystem that can
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 71bf5f4ae84c..12823845d324 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -275,8 +275,8 @@ int pstore_is_mounted(void)
275 * Set the mtime & ctime to the date that this record was originally stored. 275 * Set the mtime & ctime to the date that this record was originally stored.
276 */ 276 */
277int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count, 277int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
278 char *data, size_t size, struct timespec time, 278 char *data, bool compressed, size_t size,
279 struct pstore_info *psi) 279 struct timespec time, struct pstore_info *psi)
280{ 280{
281 struct dentry *root = pstore_sb->s_root; 281 struct dentry *root = pstore_sb->s_root;
282 struct dentry *dentry; 282 struct dentry *dentry;
@@ -315,7 +315,8 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
315 315
316 switch (type) { 316 switch (type) {
317 case PSTORE_TYPE_DMESG: 317 case PSTORE_TYPE_DMESG:
318 sprintf(name, "dmesg-%s-%lld", psname, id); 318 sprintf(name, "dmesg-%s-%lld%s", psname, id,
319 compressed ? ".enc.z" : "");
319 break; 320 break;
320 case PSTORE_TYPE_CONSOLE: 321 case PSTORE_TYPE_CONSOLE:
321 sprintf(name, "console-%s", psname); 322 sprintf(name, "console-%s", psname);
@@ -345,9 +346,8 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
345 346
346 mutex_lock(&root->d_inode->i_mutex); 347 mutex_lock(&root->d_inode->i_mutex);
347 348
348 rc = -ENOSPC;
349 dentry = d_alloc_name(root, name); 349 dentry = d_alloc_name(root, name);
350 if (IS_ERR(dentry)) 350 if (!dentry)
351 goto fail_lockedalloc; 351 goto fail_lockedalloc;
352 352
353 memcpy(private->data, data, size); 353 memcpy(private->data, data, size);
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
index 937d820f273c..3b3d305277c4 100644
--- a/fs/pstore/internal.h
+++ b/fs/pstore/internal.h
@@ -50,8 +50,9 @@ extern struct pstore_info *psinfo;
50extern void pstore_set_kmsg_bytes(int); 50extern void pstore_set_kmsg_bytes(int);
51extern void pstore_get_records(int); 51extern void pstore_get_records(int);
52extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, 52extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id,
53 int count, char *data, size_t size, 53 int count, char *data, bool compressed,
54 struct timespec time, struct pstore_info *psi); 54 size_t size, struct timespec time,
55 struct pstore_info *psi);
55extern int pstore_is_mounted(void); 56extern int pstore_is_mounted(void);
56 57
57#endif 58#endif
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 422962ae9fc2..b8e93a40a5d3 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -26,6 +26,7 @@
26#include <linux/console.h> 26#include <linux/console.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/pstore.h> 28#include <linux/pstore.h>
29#include <linux/zlib.h>
29#include <linux/string.h> 30#include <linux/string.h>
30#include <linux/timer.h> 31#include <linux/timer.h>
31#include <linux/slab.h> 32#include <linux/slab.h>
@@ -65,6 +66,15 @@ struct pstore_info *psinfo;
65 66
66static char *backend; 67static char *backend;
67 68
69/* Compression parameters */
70#define COMPR_LEVEL 6
71#define WINDOW_BITS 12
72#define MEM_LEVEL 4
73static struct z_stream_s stream;
74
75static char *big_oops_buf;
76static size_t big_oops_buf_sz;
77
68/* How much of the console log to snapshot */ 78/* How much of the console log to snapshot */
69static unsigned long kmsg_bytes = 10240; 79static unsigned long kmsg_bytes = 10240;
70 80
@@ -117,6 +127,142 @@ bool pstore_cannot_block_path(enum kmsg_dump_reason reason)
117} 127}
118EXPORT_SYMBOL_GPL(pstore_cannot_block_path); 128EXPORT_SYMBOL_GPL(pstore_cannot_block_path);
119 129
130/* Derived from logfs_compress() */
131static 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;
161error:
162 return ret;
163}
164
165/* Derived from logfs_uncompress */
166static 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_inflateInit2(&stream, WINDOW_BITS);
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;
191error:
192 return ret;
193}
194
195static void allocate_buf_for_compression(void)
196{
197 size_t size;
198 size_t cmpr;
199
200 switch (psinfo->bufsize) {
201 /* buffer range for efivars */
202 case 1000 ... 2000:
203 cmpr = 56;
204 break;
205 case 2001 ... 3000:
206 cmpr = 54;
207 break;
208 case 3001 ... 3999:
209 cmpr = 52;
210 break;
211 /* buffer range for nvram, erst */
212 case 4000 ... 10000:
213 cmpr = 45;
214 break;
215 default:
216 cmpr = 60;
217 break;
218 }
219
220 big_oops_buf_sz = (psinfo->bufsize * 100) / cmpr;
221 big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
222 if (big_oops_buf) {
223 size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
224 zlib_inflate_workspacesize());
225 stream.workspace = kmalloc(size, GFP_KERNEL);
226 if (!stream.workspace) {
227 pr_err("pstore: No memory for compression workspace; "
228 "skipping compression\n");
229 kfree(big_oops_buf);
230 big_oops_buf = NULL;
231 }
232 } else {
233 pr_err("No memory for uncompressed data; "
234 "skipping compression\n");
235 stream.workspace = NULL;
236 }
237
238}
239
240/*
241 * Called when compression fails, since the printk buffer
242 * would be fetched for compression calling it again when
243 * compression fails would have moved the iterator of
244 * printk buffer which results in fetching old contents.
245 * Copy the recent messages from big_oops_buf to psinfo->buf
246 */
247static size_t copy_kmsg_to_buffer(int hsize, size_t len)
248{
249 size_t total_len;
250 size_t diff;
251
252 total_len = hsize + len;
253
254 if (total_len > psinfo->bufsize) {
255 diff = total_len - psinfo->bufsize + hsize;
256 memcpy(psinfo->buf, big_oops_buf, hsize);
257 memcpy(psinfo->buf + hsize, big_oops_buf + diff,
258 psinfo->bufsize - hsize);
259 total_len = psinfo->bufsize;
260 } else
261 memcpy(psinfo->buf, big_oops_buf, total_len);
262
263 return total_len;
264}
265
120/* 266/*
121 * callback from kmsg_dump. (s2,l2) has the most recently 267 * callback from kmsg_dump. (s2,l2) has the most recently
122 * written bytes, older bytes are in (s1,l1). Save as much 268 * written bytes, older bytes are in (s1,l1). Save as much
@@ -148,22 +294,52 @@ static void pstore_dump(struct kmsg_dumper *dumper,
148 char *dst; 294 char *dst;
149 unsigned long size; 295 unsigned long size;
150 int hsize; 296 int hsize;
297 int zipped_len = -1;
151 size_t len; 298 size_t len;
299 bool compressed;
300 size_t total_len;
152 301
153 dst = psinfo->buf; 302 if (big_oops_buf) {
154 hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part); 303 dst = big_oops_buf;
155 size = psinfo->bufsize - hsize; 304 hsize = sprintf(dst, "%s#%d Part%d\n", why,
156 dst += hsize; 305 oopscount, part);
306 size = big_oops_buf_sz - hsize;
157 307
158 if (!kmsg_dump_get_buffer(dumper, true, dst, size, &len)) 308 if (!kmsg_dump_get_buffer(dumper, true, dst + hsize,
159 break; 309 size, &len))
310 break;
311
312 zipped_len = pstore_compress(dst, psinfo->buf,
313 hsize + len, psinfo->bufsize);
314
315 if (zipped_len > 0) {
316 compressed = true;
317 total_len = zipped_len;
318 } else {
319 compressed = false;
320 total_len = copy_kmsg_to_buffer(hsize, len);
321 }
322 } else {
323 dst = psinfo->buf;
324 hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount,
325 part);
326 size = psinfo->bufsize - hsize;
327 dst += hsize;
328
329 if (!kmsg_dump_get_buffer(dumper, true, dst,
330 size, &len))
331 break;
332
333 compressed = false;
334 total_len = hsize + len;
335 }
160 336
161 ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part, 337 ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part,
162 oopscount, hsize, hsize + len, psinfo); 338 oopscount, compressed, total_len, psinfo);
163 if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted()) 339 if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
164 pstore_new_entry = 1; 340 pstore_new_entry = 1;
165 341
166 total += hsize + len; 342 total += total_len;
167 part++; 343 part++;
168 } 344 }
169 if (pstore_cannot_block_path(reason)) { 345 if (pstore_cannot_block_path(reason)) {
@@ -221,10 +397,10 @@ static void pstore_register_console(void) {}
221static int pstore_write_compat(enum pstore_type_id type, 397static int pstore_write_compat(enum pstore_type_id type,
222 enum kmsg_dump_reason reason, 398 enum kmsg_dump_reason reason,
223 u64 *id, unsigned int part, int count, 399 u64 *id, unsigned int part, int count,
224 size_t hsize, size_t size, 400 bool compressed, size_t size,
225 struct pstore_info *psi) 401 struct pstore_info *psi)
226{ 402{
227 return psi->write_buf(type, reason, id, part, psinfo->buf, hsize, 403 return psi->write_buf(type, reason, id, part, psinfo->buf, compressed,
228 size, psi); 404 size, psi);
229} 405}
230 406
@@ -261,6 +437,8 @@ int pstore_register(struct pstore_info *psi)
261 return -EINVAL; 437 return -EINVAL;
262 } 438 }
263 439
440 allocate_buf_for_compression();
441
264 if (pstore_is_mounted()) 442 if (pstore_is_mounted())
265 pstore_get_records(0); 443 pstore_get_records(0);
266 444
@@ -297,6 +475,8 @@ void pstore_get_records(int quiet)
297 enum pstore_type_id type; 475 enum pstore_type_id type;
298 struct timespec time; 476 struct timespec time;
299 int failed = 0, rc; 477 int failed = 0, rc;
478 bool compressed;
479 int unzipped_len = -1;
300 480
301 if (!psi) 481 if (!psi)
302 return; 482 return;
@@ -305,11 +485,32 @@ void pstore_get_records(int quiet)
305 if (psi->open && psi->open(psi)) 485 if (psi->open && psi->open(psi))
306 goto out; 486 goto out;
307 487
308 while ((size = psi->read(&id, &type, &count, &time, &buf, psi)) > 0) { 488 while ((size = psi->read(&id, &type, &count, &time, &buf, &compressed,
489 psi)) > 0) {
490 if (compressed && (type == PSTORE_TYPE_DMESG)) {
491 if (big_oops_buf)
492 unzipped_len = pstore_decompress(buf,
493 big_oops_buf, size,
494 big_oops_buf_sz);
495
496 if (unzipped_len > 0) {
497 buf = big_oops_buf;
498 size = unzipped_len;
499 compressed = false;
500 } else {
501 pr_err("pstore: decompression failed;"
502 "returned %d\n", unzipped_len);
503 compressed = true;
504 }
505 }
309 rc = pstore_mkfile(type, psi->name, id, count, buf, 506 rc = pstore_mkfile(type, psi->name, id, count, buf,
310 (size_t)size, time, psi); 507 compressed, (size_t)size, time, psi);
311 kfree(buf); 508 if (unzipped_len < 0) {
312 buf = NULL; 509 /* Free buffer other than big oops */
510 kfree(buf);
511 buf = NULL;
512 } else
513 unzipped_len = -1;
313 if (rc && (rc != -EEXIST || !quiet)) 514 if (rc && (rc != -EEXIST || !quiet))
314 failed++; 515 failed++;
315 } 516 }
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index a6119f9469e2..fa8cef2cca3a 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -131,9 +131,31 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max,
131 return prz; 131 return prz;
132} 132}
133 133
134static void ramoops_read_kmsg_hdr(char *buffer, struct timespec *time,
135 bool *compressed)
136{
137 char data_type;
138
139 if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lu.%lu-%c\n",
140 &time->tv_sec, &time->tv_nsec, &data_type) == 3) {
141 if (data_type == 'C')
142 *compressed = true;
143 else
144 *compressed = false;
145 } else if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
146 &time->tv_sec, &time->tv_nsec) == 2) {
147 *compressed = false;
148 } else {
149 time->tv_sec = 0;
150 time->tv_nsec = 0;
151 *compressed = false;
152 }
153}
154
134static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, 155static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
135 int *count, struct timespec *time, 156 int *count, struct timespec *time,
136 char **buf, struct pstore_info *psi) 157 char **buf, bool *compressed,
158 struct pstore_info *psi)
137{ 159{
138 ssize_t size; 160 ssize_t size;
139 ssize_t ecc_notice_size; 161 ssize_t ecc_notice_size;
@@ -152,10 +174,6 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
152 if (!prz) 174 if (!prz)
153 return 0; 175 return 0;
154 176
155 /* TODO(kees): Bogus time for the moment. */
156 time->tv_sec = 0;
157 time->tv_nsec = 0;
158
159 size = persistent_ram_old_size(prz); 177 size = persistent_ram_old_size(prz);
160 178
161 /* ECC correction notice */ 179 /* ECC correction notice */
@@ -166,12 +184,14 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
166 return -ENOMEM; 184 return -ENOMEM;
167 185
168 memcpy(*buf, persistent_ram_old(prz), size); 186 memcpy(*buf, persistent_ram_old(prz), size);
187 ramoops_read_kmsg_hdr(*buf, time, compressed);
169 persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1); 188 persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1);
170 189
171 return size + ecc_notice_size; 190 return size + ecc_notice_size;
172} 191}
173 192
174static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) 193static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz,
194 bool compressed)
175{ 195{
176 char *hdr; 196 char *hdr;
177 struct timespec timestamp; 197 struct timespec timestamp;
@@ -182,8 +202,9 @@ static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz)
182 timestamp.tv_sec = 0; 202 timestamp.tv_sec = 0;
183 timestamp.tv_nsec = 0; 203 timestamp.tv_nsec = 0;
184 } 204 }
185 hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n", 205 hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu-%c\n",
186 (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000)); 206 (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000),
207 compressed ? 'C' : 'D');
187 WARN_ON_ONCE(!hdr); 208 WARN_ON_ONCE(!hdr);
188 len = hdr ? strlen(hdr) : 0; 209 len = hdr ? strlen(hdr) : 0;
189 persistent_ram_write(prz, hdr, len); 210 persistent_ram_write(prz, hdr, len);
@@ -196,7 +217,7 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
196 enum kmsg_dump_reason reason, 217 enum kmsg_dump_reason reason,
197 u64 *id, unsigned int part, 218 u64 *id, unsigned int part,
198 const char *buf, 219 const char *buf,
199 size_t hsize, size_t size, 220 bool compressed, size_t size,
200 struct pstore_info *psi) 221 struct pstore_info *psi)
201{ 222{
202 struct ramoops_context *cxt = psi->data; 223 struct ramoops_context *cxt = psi->data;
@@ -242,7 +263,7 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
242 263
243 prz = cxt->przs[cxt->dump_write_cnt]; 264 prz = cxt->przs[cxt->dump_write_cnt];
244 265
245 hlen = ramoops_write_kmsg_hdr(prz); 266 hlen = ramoops_write_kmsg_hdr(prz, compressed);
246 if (size + hlen > prz->buffer_size) 267 if (size + hlen > prz->buffer_size)
247 size = prz->buffer_size - hlen; 268 size = prz->buffer_size - hlen;
248 persistent_ram_write(prz, buf, size); 269 persistent_ram_write(prz, buf, size);
@@ -400,11 +421,11 @@ static int ramoops_probe(struct platform_device *pdev)
400 goto fail_out; 421 goto fail_out;
401 } 422 }
402 423
403 if (!is_power_of_2(pdata->record_size)) 424 if (pdata->record_size && !is_power_of_2(pdata->record_size))
404 pdata->record_size = rounddown_pow_of_two(pdata->record_size); 425 pdata->record_size = rounddown_pow_of_two(pdata->record_size);
405 if (!is_power_of_2(pdata->console_size)) 426 if (pdata->console_size && !is_power_of_2(pdata->console_size))
406 pdata->console_size = rounddown_pow_of_two(pdata->console_size); 427 pdata->console_size = rounddown_pow_of_two(pdata->console_size);
407 if (!is_power_of_2(pdata->ftrace_size)) 428 if (pdata->ftrace_size && !is_power_of_2(pdata->ftrace_size))
408 pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size); 429 pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size);
409 430
410 cxt->dump_read_cnt = 0; 431 cxt->dump_read_cnt = 0;