Skip to content

Commit b0aad7a

Browse files
arunabalaegl
authored andcommitted
pstore: Add compression support to pstore
Add compression support to pstore which will help in capturing more data. Initially, pstore will make a call to kmsg_dump with a bigger buffer and will pass the size of bigger buffer to kmsg_dump and then compress the data to registered buffer of registered size. In case compression fails, pstore will capture the uncompressed data by making a call again to kmsg_dump with registered_buffer of registered size. Pstore will indicate the data is compressed or not with a flag in the write callback. Signed-off-by: Aruna Balakrishnaiah <[email protected]> Reviewed-by: Kees Cook <[email protected]> Signed-off-by: Tony Luck <[email protected]>
1 parent 90ce4ca commit b0aad7a

File tree

1 file changed

+139
-9
lines changed

1 file changed

+139
-9
lines changed

fs/pstore/platform.c

Lines changed: 139 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <linux/console.h>
2727
#include <linux/module.h>
2828
#include <linux/pstore.h>
29+
#include <linux/zlib.h>
2930
#include <linux/string.h>
3031
#include <linux/timer.h>
3132
#include <linux/slab.h>
@@ -65,6 +66,15 @@ struct pstore_info *psinfo;
6566

6667
static char *backend;
6768

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+
6878
/* How much of the console log to snapshot */
6979
static unsigned long kmsg_bytes = 10240;
7080

@@ -117,6 +127,91 @@ bool pstore_cannot_block_path(enum kmsg_dump_reason reason)
117127
}
118128
EXPORT_SYMBOL_GPL(pstore_cannot_block_path);
119129

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+
165+
static void allocate_buf_for_compression(void)
166+
{
167+
size_t size;
168+
169+
big_oops_buf_sz = (psinfo->bufsize * 100) / 45;
170+
big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
171+
if (big_oops_buf) {
172+
size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
173+
zlib_inflate_workspacesize());
174+
stream.workspace = kmalloc(size, GFP_KERNEL);
175+
if (!stream.workspace) {
176+
pr_err("pstore: No memory for compression workspace; "
177+
"skipping compression\n");
178+
kfree(big_oops_buf);
179+
big_oops_buf = NULL;
180+
}
181+
} else {
182+
pr_err("No memory for uncompressed data; "
183+
"skipping compression\n");
184+
stream.workspace = NULL;
185+
}
186+
187+
}
188+
189+
/*
190+
* Called when compression fails, since the printk buffer
191+
* would be fetched for compression calling it again when
192+
* compression fails would have moved the iterator of
193+
* printk buffer which results in fetching old contents.
194+
* Copy the recent messages from big_oops_buf to psinfo->buf
195+
*/
196+
static size_t copy_kmsg_to_buffer(int hsize, size_t len)
197+
{
198+
size_t total_len;
199+
size_t diff;
200+
201+
total_len = hsize + len;
202+
203+
if (total_len > psinfo->bufsize) {
204+
diff = total_len - psinfo->bufsize + hsize;
205+
memcpy(psinfo->buf, big_oops_buf, hsize);
206+
memcpy(psinfo->buf + hsize, big_oops_buf + diff,
207+
psinfo->bufsize - hsize);
208+
total_len = psinfo->bufsize;
209+
} else
210+
memcpy(psinfo->buf, big_oops_buf, total_len);
211+
212+
return total_len;
213+
}
214+
120215
/*
121216
* callback from kmsg_dump. (s2,l2) has the most recently
122217
* written bytes, older bytes are in (s1,l1). Save as much
@@ -148,23 +243,56 @@ static void pstore_dump(struct kmsg_dumper *dumper,
148243
char *dst;
149244
unsigned long size;
150245
int hsize;
246+
int zipped_len = -1;
151247
size_t len;
152-
bool compressed = false;
248+
bool compressed;
249+
size_t total_len;
153250

154-
dst = psinfo->buf;
155-
hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part);
156-
size = psinfo->bufsize - hsize;
157-
dst += hsize;
251+
if (big_oops_buf) {
252+
dst = big_oops_buf;
253+
hsize = sprintf(dst, "%s#%d Part%d\n", why,
254+
oopscount, part);
255+
size = big_oops_buf_sz - hsize;
158256

159-
if (!kmsg_dump_get_buffer(dumper, true, dst, size, &len))
160-
break;
257+
if (!kmsg_dump_get_buffer(dumper, true, dst + hsize,
258+
size, &len))
259+
break;
260+
261+
zipped_len = pstore_compress(dst, psinfo->buf,
262+
hsize + len, psinfo->bufsize);
263+
264+
if (zipped_len > 0) {
265+
compressed = true;
266+
total_len = zipped_len;
267+
} else {
268+
pr_err("pstore: compression failed for Part %d"
269+
" returned %d\n", part, zipped_len);
270+
pr_err("pstore: Capture uncompressed"
271+
" oops/panic report of Part %d\n", part);
272+
compressed = false;
273+
total_len = copy_kmsg_to_buffer(hsize, len);
274+
}
275+
} else {
276+
dst = psinfo->buf;
277+
hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount,
278+
part);
279+
size = psinfo->bufsize - hsize;
280+
dst += hsize;
281+
282+
if (!kmsg_dump_get_buffer(dumper, true, dst,
283+
size, &len))
284+
break;
285+
286+
compressed = false;
287+
total_len = hsize + len;
288+
}
161289

162290
ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part,
163-
oopscount, compressed, hsize + len, psinfo);
291+
oopscount, compressed, total_len, psinfo);
164292
if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
165293
pstore_new_entry = 1;
166294

167-
total += hsize + len;
295+
total += total_len;
168296
part++;
169297
}
170298
if (pstore_cannot_block_path(reason)) {
@@ -262,6 +390,8 @@ int pstore_register(struct pstore_info *psi)
262390
return -EINVAL;
263391
}
264392

393+
allocate_buf_for_compression();
394+
265395
if (pstore_is_mounted())
266396
pstore_get_records(0);
267397

0 commit comments

Comments
 (0)