aboutsummaryrefslogtreecommitdiffstats
path: root/fs/pstore/ram.c
diff options
context:
space:
mode:
authorAnton Vorontsov <anton.vorontsov@linaro.org>2012-05-26 09:20:23 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-13 19:59:28 -0400
commitb5d38e9bf1b0c4db19e336b59b38dfb5d28bf1bf (patch)
tree4265e0a8df54cb1ffa196c1f98d9f789165e7970 /fs/pstore/ram.c
parent755d66b48fe5a1f2a07802fcc8704e8b9e775e7d (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.c100
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);
41MODULE_PARM_DESC(record_size, 41MODULE_PARM_DESC(record_size,
42 "size of each dump done on oops/panic"); 42 "size of each dump done on oops/panic");
43 43
44static ulong ramoops_console_size = MIN_MEM_SIZE;
45module_param_named(console_size, ramoops_console_size, ulong, 0400);
46MODULE_PARM_DESC(console_size, "size of kernel console log");
47
44static ulong mem_address; 48static ulong mem_address;
45module_param(mem_address, ulong, 0400); 49module_param(mem_address, ulong, 0400);
46MODULE_PARM_DESC(mem_address, 50MODULE_PARM_DESC(mem_address,
@@ -63,14 +67,17 @@ MODULE_PARM_DESC(ramoops_ecc,
63 67
64struct ramoops_context { 68struct 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
307static 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
279static int __init ramoops_probe(struct platform_device *pdev) 333static 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:
353fail_clear: 422fail_clear:
354 cxt->pstore.bufsize = 0; 423 cxt->pstore.bufsize = 0;
355 cxt->max_dump_cnt = 0; 424 cxt->max_dump_cnt = 0;
356fail_count: 425fail_cnt:
426 kfree(cxt->cprz);
427fail_init_cprz:
357 ramoops_free_przs(cxt); 428 ramoops_free_przs(cxt);
358fail_out: 429fail_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,