diff options
author | Anton Vorontsov <anton.vorontsov@linaro.org> | 2012-05-26 09:20:23 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-06-13 19:59:28 -0400 |
commit | b5d38e9bf1b0c4db19e336b59b38dfb5d28bf1bf (patch) | |
tree | 4265e0a8df54cb1ffa196c1f98d9f789165e7970 /fs/pstore/ram.c | |
parent | 755d66b48fe5a1f2a07802fcc8704e8b9e775e7d (diff) |
pstore/ram: Add console messages handling
The console log size is configurable via ramoops.console_size
module option, and the log itself is available via
<pstore-mount>/console-ramoops file.
Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/pstore/ram.c')
-rw-r--r-- | fs/pstore/ram.c | 100 |
1 files changed, 86 insertions, 14 deletions
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index d770d7266e96..c7acf94ff475 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c | |||
@@ -41,6 +41,10 @@ module_param(record_size, ulong, 0400); | |||
41 | MODULE_PARM_DESC(record_size, | 41 | MODULE_PARM_DESC(record_size, |
42 | "size of each dump done on oops/panic"); | 42 | "size of each dump done on oops/panic"); |
43 | 43 | ||
44 | static ulong ramoops_console_size = MIN_MEM_SIZE; | ||
45 | module_param_named(console_size, ramoops_console_size, ulong, 0400); | ||
46 | MODULE_PARM_DESC(console_size, "size of kernel console log"); | ||
47 | |||
44 | static ulong mem_address; | 48 | static ulong mem_address; |
45 | module_param(mem_address, ulong, 0400); | 49 | module_param(mem_address, ulong, 0400); |
46 | MODULE_PARM_DESC(mem_address, | 50 | MODULE_PARM_DESC(mem_address, |
@@ -63,14 +67,17 @@ MODULE_PARM_DESC(ramoops_ecc, | |||
63 | 67 | ||
64 | struct ramoops_context { | 68 | struct ramoops_context { |
65 | struct persistent_ram_zone **przs; | 69 | struct persistent_ram_zone **przs; |
70 | struct persistent_ram_zone *cprz; | ||
66 | phys_addr_t phys_addr; | 71 | phys_addr_t phys_addr; |
67 | unsigned long size; | 72 | unsigned long size; |
68 | size_t record_size; | 73 | size_t record_size; |
74 | size_t console_size; | ||
69 | int dump_oops; | 75 | int dump_oops; |
70 | bool ecc; | 76 | bool ecc; |
71 | unsigned int max_dump_cnt; | 77 | unsigned int max_dump_cnt; |
72 | unsigned int dump_write_cnt; | 78 | unsigned int dump_write_cnt; |
73 | unsigned int dump_read_cnt; | 79 | unsigned int dump_read_cnt; |
80 | unsigned int console_read_cnt; | ||
74 | struct pstore_info pstore; | 81 | struct pstore_info pstore; |
75 | }; | 82 | }; |
76 | 83 | ||
@@ -82,6 +89,7 @@ static int ramoops_pstore_open(struct pstore_info *psi) | |||
82 | struct ramoops_context *cxt = psi->data; | 89 | struct ramoops_context *cxt = psi->data; |
83 | 90 | ||
84 | cxt->dump_read_cnt = 0; | 91 | cxt->dump_read_cnt = 0; |
92 | cxt->console_read_cnt = 0; | ||
85 | return 0; | 93 | return 0; |
86 | } | 94 | } |
87 | 95 | ||
@@ -125,6 +133,9 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, | |||
125 | cxt->max_dump_cnt, id, type, | 133 | cxt->max_dump_cnt, id, type, |
126 | PSTORE_TYPE_DMESG, 1); | 134 | PSTORE_TYPE_DMESG, 1); |
127 | if (!prz) | 135 | if (!prz) |
136 | prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt, | ||
137 | 1, id, type, PSTORE_TYPE_CONSOLE, 0); | ||
138 | if (!prz) | ||
128 | return 0; | 139 | return 0; |
129 | 140 | ||
130 | /* TODO(kees): Bogus time for the moment. */ | 141 | /* TODO(kees): Bogus time for the moment. */ |
@@ -167,7 +178,13 @@ static int ramoops_pstore_write(enum pstore_type_id type, | |||
167 | struct persistent_ram_zone *prz = cxt->przs[cxt->dump_write_cnt]; | 178 | struct persistent_ram_zone *prz = cxt->przs[cxt->dump_write_cnt]; |
168 | size_t hlen; | 179 | size_t hlen; |
169 | 180 | ||
170 | /* Currently ramoops is designed to only store dmesg dumps. */ | 181 | if (type == PSTORE_TYPE_CONSOLE) { |
182 | if (!cxt->cprz) | ||
183 | return -ENOMEM; | ||
184 | persistent_ram_write(cxt->cprz, cxt->pstore.buf, size); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
171 | if (type != PSTORE_TYPE_DMESG) | 188 | if (type != PSTORE_TYPE_DMESG) |
172 | return -EINVAL; | 189 | return -EINVAL; |
173 | 190 | ||
@@ -204,12 +221,23 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, | |||
204 | struct pstore_info *psi) | 221 | struct pstore_info *psi) |
205 | { | 222 | { |
206 | struct ramoops_context *cxt = psi->data; | 223 | struct ramoops_context *cxt = psi->data; |
224 | struct persistent_ram_zone *prz; | ||
207 | 225 | ||
208 | if (id >= cxt->max_dump_cnt) | 226 | switch (type) { |
227 | case PSTORE_TYPE_DMESG: | ||
228 | if (id >= cxt->max_dump_cnt) | ||
229 | return -EINVAL; | ||
230 | prz = cxt->przs[id]; | ||
231 | break; | ||
232 | case PSTORE_TYPE_CONSOLE: | ||
233 | prz = cxt->cprz; | ||
234 | break; | ||
235 | default: | ||
209 | return -EINVAL; | 236 | return -EINVAL; |
237 | } | ||
210 | 238 | ||
211 | persistent_ram_free_old(cxt->przs[id]); | 239 | persistent_ram_free_old(prz); |
212 | persistent_ram_zap(cxt->przs[id]); | 240 | persistent_ram_zap(prz); |
213 | 241 | ||
214 | return 0; | 242 | return 0; |
215 | } | 243 | } |
@@ -276,6 +304,32 @@ fail_prz: | |||
276 | return err; | 304 | return err; |
277 | } | 305 | } |
278 | 306 | ||
307 | static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt, | ||
308 | struct persistent_ram_zone **prz, | ||
309 | phys_addr_t *paddr, size_t sz) | ||
310 | { | ||
311 | if (!sz) | ||
312 | return 0; | ||
313 | |||
314 | if (*paddr + sz > *paddr + cxt->size) | ||
315 | return -ENOMEM; | ||
316 | |||
317 | *prz = persistent_ram_new(*paddr, sz, cxt->ecc); | ||
318 | if (IS_ERR(*prz)) { | ||
319 | int err = PTR_ERR(*prz); | ||
320 | |||
321 | dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", | ||
322 | sz, (unsigned long long)*paddr, err); | ||
323 | return err; | ||
324 | } | ||
325 | |||
326 | persistent_ram_zap(*prz); | ||
327 | |||
328 | *paddr += sz; | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
279 | static int __init ramoops_probe(struct platform_device *pdev) | 333 | static int __init ramoops_probe(struct platform_device *pdev) |
280 | { | 334 | { |
281 | struct device *dev = &pdev->dev; | 335 | struct device *dev = &pdev->dev; |
@@ -291,34 +345,50 @@ static int __init ramoops_probe(struct platform_device *pdev) | |||
291 | if (cxt->max_dump_cnt) | 345 | if (cxt->max_dump_cnt) |
292 | goto fail_out; | 346 | goto fail_out; |
293 | 347 | ||
294 | if (!pdata->mem_size || !pdata->record_size) { | 348 | if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size)) { |
295 | pr_err("The memory size and the record size must be " | 349 | pr_err("The memory size and the record/console size must be " |
296 | "non-zero\n"); | 350 | "non-zero\n"); |
297 | goto fail_out; | 351 | goto fail_out; |
298 | } | 352 | } |
299 | 353 | ||
300 | pdata->mem_size = rounddown_pow_of_two(pdata->mem_size); | 354 | pdata->mem_size = rounddown_pow_of_two(pdata->mem_size); |
301 | pdata->record_size = rounddown_pow_of_two(pdata->record_size); | 355 | pdata->record_size = rounddown_pow_of_two(pdata->record_size); |
356 | pdata->console_size = rounddown_pow_of_two(pdata->console_size); | ||
302 | 357 | ||
303 | cxt->dump_read_cnt = 0; | 358 | cxt->dump_read_cnt = 0; |
304 | cxt->size = pdata->mem_size; | 359 | cxt->size = pdata->mem_size; |
305 | cxt->phys_addr = pdata->mem_address; | 360 | cxt->phys_addr = pdata->mem_address; |
306 | cxt->record_size = pdata->record_size; | 361 | cxt->record_size = pdata->record_size; |
362 | cxt->console_size = pdata->console_size; | ||
307 | cxt->dump_oops = pdata->dump_oops; | 363 | cxt->dump_oops = pdata->dump_oops; |
308 | cxt->ecc = pdata->ecc; | 364 | cxt->ecc = pdata->ecc; |
309 | 365 | ||
310 | paddr = cxt->phys_addr; | 366 | paddr = cxt->phys_addr; |
311 | 367 | ||
312 | dump_mem_sz = cxt->size; | 368 | dump_mem_sz = cxt->size - cxt->console_size; |
313 | err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); | 369 | err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); |
314 | if (err) { | 370 | if (err) |
371 | goto fail_out; | ||
372 | |||
373 | err = ramoops_init_prz(dev, cxt, &cxt->cprz, &paddr, cxt->console_size); | ||
374 | if (err) | ||
375 | goto fail_init_cprz; | ||
376 | |||
377 | if (!cxt->przs && !cxt->cprz) { | ||
315 | pr_err("memory size too small, minimum is %lu\n", | 378 | pr_err("memory size too small, minimum is %lu\n", |
316 | cxt->record_size); | 379 | cxt->console_size + cxt->record_size); |
317 | goto fail_count; | 380 | goto fail_cnt; |
318 | } | 381 | } |
319 | 382 | ||
320 | cxt->pstore.data = cxt; | 383 | cxt->pstore.data = cxt; |
321 | cxt->pstore.bufsize = cxt->przs[0]->buffer_size; | 384 | /* |
385 | * Console can handle any buffer size, so prefer dumps buffer | ||
386 | * size since usually it is smaller. | ||
387 | */ | ||
388 | if (cxt->przs) | ||
389 | cxt->pstore.bufsize = cxt->przs[0]->buffer_size; | ||
390 | else | ||
391 | cxt->pstore.bufsize = cxt->cprz->buffer_size; | ||
322 | cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL); | 392 | cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL); |
323 | spin_lock_init(&cxt->pstore.buf_lock); | 393 | spin_lock_init(&cxt->pstore.buf_lock); |
324 | if (!cxt->pstore.buf) { | 394 | if (!cxt->pstore.buf) { |
@@ -341,9 +411,8 @@ static int __init ramoops_probe(struct platform_device *pdev) | |||
341 | record_size = pdata->record_size; | 411 | record_size = pdata->record_size; |
342 | dump_oops = pdata->dump_oops; | 412 | dump_oops = pdata->dump_oops; |
343 | 413 | ||
344 | pr_info("attached 0x%lx@0x%llx (%ux0x%zx), ecc: %s\n", | 414 | pr_info("attached 0x%lx@0x%llx, ecc: %s\n", |
345 | cxt->size, (unsigned long long)cxt->phys_addr, | 415 | cxt->size, (unsigned long long)cxt->phys_addr, |
346 | cxt->max_dump_cnt, cxt->record_size, | ||
347 | ramoops_ecc ? "on" : "off"); | 416 | ramoops_ecc ? "on" : "off"); |
348 | 417 | ||
349 | return 0; | 418 | return 0; |
@@ -353,7 +422,9 @@ fail_buf: | |||
353 | fail_clear: | 422 | fail_clear: |
354 | cxt->pstore.bufsize = 0; | 423 | cxt->pstore.bufsize = 0; |
355 | cxt->max_dump_cnt = 0; | 424 | cxt->max_dump_cnt = 0; |
356 | fail_count: | 425 | fail_cnt: |
426 | kfree(cxt->cprz); | ||
427 | fail_init_cprz: | ||
357 | ramoops_free_przs(cxt); | 428 | ramoops_free_przs(cxt); |
358 | fail_out: | 429 | fail_out: |
359 | return err; | 430 | return err; |
@@ -405,6 +476,7 @@ static int __init ramoops_init(void) | |||
405 | dummy_data->mem_size = mem_size; | 476 | dummy_data->mem_size = mem_size; |
406 | dummy_data->mem_address = mem_address; | 477 | dummy_data->mem_address = mem_address; |
407 | dummy_data->record_size = record_size; | 478 | dummy_data->record_size = record_size; |
479 | dummy_data->console_size = ramoops_console_size; | ||
408 | dummy_data->dump_oops = dump_oops; | 480 | dummy_data->dump_oops = dump_oops; |
409 | dummy_data->ecc = ramoops_ecc; | 481 | dummy_data->ecc = ramoops_ecc; |
410 | dummy = platform_create_bundle(&ramoops_driver, ramoops_probe, | 482 | dummy = platform_create_bundle(&ramoops_driver, ramoops_probe, |