aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-04 00:14:06 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-04 00:14:06 -0400
commitf83b0a4e4c33aa31dac0b8b48f1f3a470edc933a (patch)
treefade92500aa68531de6cd4761cc4693ea901540b /fs
parent32dad03d164206ea886885d0740284ba215b0970 (diff)
parent3bd11cf56e4d9c9a79c0c1a4ebe381c674ec9709 (diff)
Merge tag 'please-pull-pstore' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux
Pull pstore changes from Tony Luck: "A big part of this is the addition of compression to the generic pstore layer so that all backends can use the pitiful amounts of storage they control more effectively. Three other small fixes/cleanups too. * tag 'please-pull-pstore' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux: pstore/ram: (really) fix undefined usage of rounddown_pow_of_two pstore/ram: Read and write to the 'compressed' flag of pstore efi-pstore: Read and write to the 'compressed' flag of pstore erst: Read and write to the 'compressed' flag of pstore powerpc/pseries: Read and write to the 'compressed' flag of pstore pstore: Add file extension to pstore file if compressed pstore: Add decompression support to pstore pstore: Introduce new argument 'compressed' in the read callback pstore: Add compression support to pstore pstore/Kconfig: Select ZLIB_DEFLATE and ZLIB_INFLATE when PSTORE is selected pstore: Add new argument 'compressed' in pstore write callback powerpc/pseries: Remove (de)compression in nvram with pstore enabled pstore: d_alloc_name() doesn't return an ERR_PTR acpi/apei/erst: Add missing iounmap() on error in erst_exec_move_data()
Diffstat (limited to 'fs')
-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.c212
-rw-r--r--fs/pstore/ram.c47
5 files changed, 242 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..4ffb7ab5e397 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,121 @@ 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_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;
191error:
192 return ret;
193}
194
195static 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 */
226static 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
120/* 245/*
121 * callback from kmsg_dump. (s2,l2) has the most recently 246 * callback from kmsg_dump. (s2,l2) has the most recently
122 * written bytes, older bytes are in (s1,l1). Save as much 247 * written bytes, older bytes are in (s1,l1). Save as much
@@ -148,22 +273,56 @@ static void pstore_dump(struct kmsg_dumper *dumper,
148 char *dst; 273 char *dst;
149 unsigned long size; 274 unsigned long size;
150 int hsize; 275 int hsize;
276 int zipped_len = -1;
151 size_t len; 277 size_t len;
278 bool compressed;
279 size_t total_len;
152 280
153 dst = psinfo->buf; 281 if (big_oops_buf) {
154 hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part); 282 dst = big_oops_buf;
155 size = psinfo->bufsize - hsize; 283 hsize = sprintf(dst, "%s#%d Part%d\n", why,
156 dst += hsize; 284 oopscount, part);
285 size = big_oops_buf_sz - hsize;
157 286
158 if (!kmsg_dump_get_buffer(dumper, true, dst, size, &len)) 287 if (!kmsg_dump_get_buffer(dumper, true, dst + hsize,
159 break; 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 }
160 319
161 ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part, 320 ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part,
162 oopscount, hsize, hsize + len, psinfo); 321 oopscount, compressed, total_len, psinfo);
163 if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted()) 322 if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
164 pstore_new_entry = 1; 323 pstore_new_entry = 1;
165 324
166 total += hsize + len; 325 total += total_len;
167 part++; 326 part++;
168 } 327 }
169 if (pstore_cannot_block_path(reason)) { 328 if (pstore_cannot_block_path(reason)) {
@@ -221,10 +380,10 @@ static void pstore_register_console(void) {}
221static int pstore_write_compat(enum pstore_type_id type, 380static int pstore_write_compat(enum pstore_type_id type,
222 enum kmsg_dump_reason reason, 381 enum kmsg_dump_reason reason,
223 u64 *id, unsigned int part, int count, 382 u64 *id, unsigned int part, int count,
224 size_t hsize, size_t size, 383 bool compressed, size_t size,
225 struct pstore_info *psi) 384 struct pstore_info *psi)
226{ 385{
227 return psi->write_buf(type, reason, id, part, psinfo->buf, hsize, 386 return psi->write_buf(type, reason, id, part, psinfo->buf, compressed,
228 size, psi); 387 size, psi);
229} 388}
230 389
@@ -261,6 +420,8 @@ int pstore_register(struct pstore_info *psi)
261 return -EINVAL; 420 return -EINVAL;
262 } 421 }
263 422
423 allocate_buf_for_compression();
424
264 if (pstore_is_mounted()) 425 if (pstore_is_mounted())
265 pstore_get_records(0); 426 pstore_get_records(0);
266 427
@@ -297,6 +458,8 @@ void pstore_get_records(int quiet)
297 enum pstore_type_id type; 458 enum pstore_type_id type;
298 struct timespec time; 459 struct timespec time;
299 int failed = 0, rc; 460 int failed = 0, rc;
461 bool compressed;
462 int unzipped_len = -1;
300 463
301 if (!psi) 464 if (!psi)
302 return; 465 return;
@@ -305,11 +468,32 @@ void pstore_get_records(int quiet)
305 if (psi->open && psi->open(psi)) 468 if (psi->open && psi->open(psi))
306 goto out; 469 goto out;
307 470
308 while ((size = psi->read(&id, &type, &count, &time, &buf, psi)) > 0) { 471 while ((size = psi->read(&id, &type, &count, &time, &buf, &compressed,
472 psi)) > 0) {
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 compressed = false;
483 } else {
484 pr_err("pstore: decompression failed;"
485 "returned %d\n", unzipped_len);
486 compressed = true;
487 }
488 }
309 rc = pstore_mkfile(type, psi->name, id, count, buf, 489 rc = pstore_mkfile(type, psi->name, id, count, buf,
310 (size_t)size, time, psi); 490 compressed, (size_t)size, time, psi);
311 kfree(buf); 491 if (unzipped_len < 0) {
312 buf = NULL; 492 /* Free buffer other than big oops */
493 kfree(buf);
494 buf = NULL;
495 } else
496 unzipped_len = -1;
313 if (rc && (rc != -EEXIST || !quiet)) 497 if (rc && (rc != -EEXIST || !quiet))
314 failed++; 498 failed++;
315 } 499 }
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;