1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * MTD Oops/Panic logger 4 * 5 * Copyright © 2007 Nokia Corporation. All rights reserved. 6 * 7 * Author: Richard Purdie <rpurdie@openedhand.com> 8 */ 9 10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/console.h> 15 #include <linux/vmalloc.h> 16 #include <linux/workqueue.h> 17 #include <linux/sched.h> 18 #include <linux/wait.h> 19 #include <linux/delay.h> 20 #include <linux/interrupt.h> 21 #include <linux/timekeeping.h> 22 #include <linux/mtd/mtd.h> 23 #include <linux/kmsg_dump.h> 24 25 /* Maximum MTD partition size */ 26 #define MTDOOPS_MAX_MTD_SIZE (8 * 1024 * 1024) 27 28 static unsigned long record_size = 4096; 29 module_param(record_size, ulong, 0400); 30 MODULE_PARM_DESC(record_size, 31 "record size for MTD OOPS pages in bytes (default 4096)"); 32 33 static char mtddev[80]; 34 module_param_string(mtddev, mtddev, 80, 0400); 35 MODULE_PARM_DESC(mtddev, 36 "name or index number of the MTD device to use"); 37 38 static int dump_oops = 1; 39 module_param(dump_oops, int, 0600); 40 MODULE_PARM_DESC(dump_oops, 41 "set to 1 to dump oopses, 0 to only dump panics (default 1)"); 42 43 #define MTDOOPS_KERNMSG_MAGIC_v1 0x5d005d00 /* Original */ 44 #define MTDOOPS_KERNMSG_MAGIC_v2 0x5d005e00 /* Adds the timestamp */ 45 46 struct mtdoops_hdr { 47 u32 seq; 48 u32 magic; 49 ktime_t timestamp; 50 } __packed; 51 52 static struct mtdoops_context { 53 struct kmsg_dumper dump; 54 55 int mtd_index; 56 struct work_struct work_erase; 57 struct work_struct work_write; 58 struct mtd_info *mtd; 59 int oops_pages; 60 int nextpage; 61 int nextcount; 62 unsigned long *oops_page_used; 63 64 unsigned long oops_buf_busy; 65 void *oops_buf; 66 } oops_cxt; 67 68 static void mark_page_used(struct mtdoops_context *cxt, int page) 69 { 70 set_bit(page, cxt->oops_page_used); 71 } 72 73 static void mark_page_unused(struct mtdoops_context *cxt, int page) 74 { 75 clear_bit(page, cxt->oops_page_used); 76 } 77 78 static int page_is_used(struct mtdoops_context *cxt, int page) 79 { 80 return test_bit(page, cxt->oops_page_used); 81 } 82 83 static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset) 84 { 85 struct mtd_info *mtd = cxt->mtd; 86 u32 start_page_offset = mtd_div_by_eb(offset, mtd) * mtd->erasesize; 87 u32 start_page = start_page_offset / record_size; 88 u32 erase_pages = mtd->erasesize / record_size; 89 struct erase_info erase; 90 int ret; 91 int page; 92 93 erase.addr = offset; 94 erase.len = mtd->erasesize; 95 96 ret = mtd_erase(mtd, &erase); 97 if (ret) { 98 pr_warn("erase of region [0x%llx, 0x%llx] on \"%s\" failed\n", 99 (unsigned long long)erase.addr, 100 (unsigned long long)erase.len, mtddev); 101 return ret; 102 } 103 104 /* Mark pages as unused */ 105 for (page = start_page; page < start_page + erase_pages; page++) 106 mark_page_unused(cxt, page); 107 108 return 0; 109 } 110 111 static void mtdoops_erase(struct mtdoops_context *cxt) 112 { 113 struct mtd_info *mtd = cxt->mtd; 114 int i = 0, j, ret, mod; 115 116 /* We were unregistered */ 117 if (!mtd) 118 return; 119 120 mod = (cxt->nextpage * record_size) % mtd->erasesize; 121 if (mod != 0) { 122 cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / record_size); 123 if (cxt->nextpage >= cxt->oops_pages) 124 cxt->nextpage = 0; 125 } 126 127 while ((ret = mtd_block_isbad(mtd, cxt->nextpage * record_size)) > 0) { 128 badblock: 129 pr_warn("bad block at %08lx\n", 130 cxt->nextpage * record_size); 131 i++; 132 cxt->nextpage = cxt->nextpage + (mtd->erasesize / record_size); 133 if (cxt->nextpage >= cxt->oops_pages) 134 cxt->nextpage = 0; 135 if (i == cxt->oops_pages / (mtd->erasesize / record_size)) { 136 pr_err("all blocks bad!\n"); 137 return; 138 } 139 } 140 141 if (ret < 0) { 142 pr_err("mtd_block_isbad failed, aborting\n"); 143 return; 144 } 145 146 for (j = 0, ret = -1; (j < 3) && (ret < 0); j++) 147 ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size); 148 149 if (ret >= 0) { 150 pr_debug("ready %d, %d\n", 151 cxt->nextpage, cxt->nextcount); 152 return; 153 } 154 155 if (ret == -EIO) { 156 ret = mtd_block_markbad(mtd, cxt->nextpage * record_size); 157 if (ret < 0 && ret != -EOPNOTSUPP) { 158 pr_err("block_markbad failed, aborting\n"); 159 return; 160 } 161 } 162 goto badblock; 163 } 164 165 /* Scheduled work - when we can't proceed without erasing a block */ 166 static void mtdoops_workfunc_erase(struct work_struct *work) 167 { 168 struct mtdoops_context *cxt = 169 container_of(work, struct mtdoops_context, work_erase); 170 mtdoops_erase(cxt); 171 } 172 173 static void mtdoops_inc_counter(struct mtdoops_context *cxt, int panic) 174 { 175 cxt->nextpage++; 176 if (cxt->nextpage >= cxt->oops_pages) 177 cxt->nextpage = 0; 178 cxt->nextcount++; 179 if (cxt->nextcount == 0xffffffff) 180 cxt->nextcount = 0; 181 182 if (page_is_used(cxt, cxt->nextpage)) { 183 pr_debug("not ready %d, %d (erase %s)\n", 184 cxt->nextpage, cxt->nextcount, 185 panic ? "immediately" : "scheduled"); 186 if (panic) { 187 /* In case of panic, erase immediately */ 188 mtdoops_erase(cxt); 189 } else { 190 /* Otherwise, schedule work to erase it "nicely" */ 191 schedule_work(&cxt->work_erase); 192 } 193 } else { 194 pr_debug("ready %d, %d (no erase)\n", 195 cxt->nextpage, cxt->nextcount); 196 } 197 } 198 199 static void mtdoops_write(struct mtdoops_context *cxt, int panic) 200 { 201 struct mtd_info *mtd = cxt->mtd; 202 size_t retlen; 203 struct mtdoops_hdr *hdr; 204 int ret; 205 206 if (test_and_set_bit(0, &cxt->oops_buf_busy)) 207 return; 208 209 /* Add mtdoops header to the buffer */ 210 hdr = (struct mtdoops_hdr *)cxt->oops_buf; 211 hdr->seq = cxt->nextcount; 212 hdr->magic = MTDOOPS_KERNMSG_MAGIC_v2; 213 hdr->timestamp = ktime_get_real(); 214 215 if (panic) { 216 ret = mtd_panic_write(mtd, cxt->nextpage * record_size, 217 record_size, &retlen, cxt->oops_buf); 218 if (ret == -EOPNOTSUPP) { 219 pr_err("Cannot write from panic without panic_write\n"); 220 goto out; 221 } 222 } else 223 ret = mtd_write(mtd, cxt->nextpage * record_size, 224 record_size, &retlen, cxt->oops_buf); 225 226 if (retlen != record_size || ret < 0) 227 pr_err("write failure at %ld (%td of %ld written), error %d\n", 228 cxt->nextpage * record_size, retlen, record_size, ret); 229 mark_page_used(cxt, cxt->nextpage); 230 memset(cxt->oops_buf, 0xff, record_size); 231 232 mtdoops_inc_counter(cxt, panic); 233 out: 234 clear_bit(0, &cxt->oops_buf_busy); 235 } 236 237 static void mtdoops_workfunc_write(struct work_struct *work) 238 { 239 struct mtdoops_context *cxt = 240 container_of(work, struct mtdoops_context, work_write); 241 242 mtdoops_write(cxt, 0); 243 } 244 245 static void find_next_position(struct mtdoops_context *cxt) 246 { 247 struct mtd_info *mtd = cxt->mtd; 248 struct mtdoops_hdr hdr; 249 int ret, page, maxpos = 0; 250 u32 maxcount = 0xffffffff; 251 size_t retlen; 252 253 for (page = 0; page < cxt->oops_pages; page++) { 254 if (mtd_block_isbad(mtd, page * record_size)) 255 continue; 256 /* Assume the page is used */ 257 mark_page_used(cxt, page); 258 ret = mtd_read(mtd, page * record_size, sizeof(hdr), 259 &retlen, (u_char *)&hdr); 260 if (retlen != sizeof(hdr) || 261 (ret < 0 && !mtd_is_bitflip(ret))) { 262 pr_err("read failure at %ld (%zu of %zu read), err %d\n", 263 page * record_size, retlen, sizeof(hdr), ret); 264 continue; 265 } 266 267 if (hdr.seq == 0xffffffff && hdr.magic == 0xffffffff) 268 mark_page_unused(cxt, page); 269 if (hdr.seq == 0xffffffff || 270 (hdr.magic != MTDOOPS_KERNMSG_MAGIC_v1 && 271 hdr.magic != MTDOOPS_KERNMSG_MAGIC_v2)) 272 continue; 273 if (maxcount == 0xffffffff) { 274 maxcount = hdr.seq; 275 maxpos = page; 276 } else if (hdr.seq < 0x40000000 && maxcount > 0xc0000000) { 277 maxcount = hdr.seq; 278 maxpos = page; 279 } else if (hdr.seq > maxcount && hdr.seq < 0xc0000000) { 280 maxcount = hdr.seq; 281 maxpos = page; 282 } else if (hdr.seq > maxcount && hdr.seq > 0xc0000000 283 && maxcount > 0x80000000) { 284 maxcount = hdr.seq; 285 maxpos = page; 286 } 287 } 288 if (maxcount == 0xffffffff) { 289 cxt->nextpage = cxt->oops_pages - 1; 290 cxt->nextcount = 0; 291 } 292 else { 293 cxt->nextpage = maxpos; 294 cxt->nextcount = maxcount; 295 } 296 297 mtdoops_inc_counter(cxt, 0); 298 } 299 300 static void mtdoops_do_dump(struct kmsg_dumper *dumper, 301 enum kmsg_dump_reason reason) 302 { 303 struct mtdoops_context *cxt = container_of(dumper, 304 struct mtdoops_context, dump); 305 struct kmsg_dump_iter iter; 306 307 /* Only dump oopses if dump_oops is set */ 308 if (reason == KMSG_DUMP_OOPS && !dump_oops) 309 return; 310 311 kmsg_dump_rewind(&iter); 312 313 if (test_and_set_bit(0, &cxt->oops_buf_busy)) 314 return; 315 kmsg_dump_get_buffer(&iter, true, 316 cxt->oops_buf + sizeof(struct mtdoops_hdr), 317 record_size - sizeof(struct mtdoops_hdr), NULL); 318 clear_bit(0, &cxt->oops_buf_busy); 319 320 if (reason != KMSG_DUMP_OOPS) { 321 /* Panics must be written immediately */ 322 mtdoops_write(cxt, 1); 323 } else { 324 /* For other cases, schedule work to write it "nicely" */ 325 schedule_work(&cxt->work_write); 326 } 327 } 328 329 static void mtdoops_notify_add(struct mtd_info *mtd) 330 { 331 struct mtdoops_context *cxt = &oops_cxt; 332 u64 mtdoops_pages = div_u64(mtd->size, record_size); 333 int err; 334 335 if (!strcmp(mtd->name, mtddev)) 336 cxt->mtd_index = mtd->index; 337 338 if (mtd->index != cxt->mtd_index || cxt->mtd_index < 0) 339 return; 340 341 if (mtd->size < mtd->erasesize * 2) { 342 pr_err("MTD partition %d not big enough for mtdoops\n", 343 mtd->index); 344 return; 345 } 346 if (mtd->erasesize < record_size) { 347 pr_err("eraseblock size of MTD partition %d too small\n", 348 mtd->index); 349 return; 350 } 351 if (mtd->size > MTDOOPS_MAX_MTD_SIZE) { 352 pr_err("mtd%d is too large (limit is %d MiB)\n", 353 mtd->index, MTDOOPS_MAX_MTD_SIZE / 1024 / 1024); 354 return; 355 } 356 357 /* oops_page_used is a bit field */ 358 cxt->oops_page_used = 359 vmalloc(array_size(sizeof(unsigned long), 360 DIV_ROUND_UP(mtdoops_pages, 361 BITS_PER_LONG))); 362 if (!cxt->oops_page_used) { 363 pr_err("could not allocate page array\n"); 364 return; 365 } 366 367 cxt->dump.max_reason = KMSG_DUMP_OOPS; 368 cxt->dump.dump = mtdoops_do_dump; 369 err = kmsg_dump_register(&cxt->dump); 370 if (err) { 371 pr_err("registering kmsg dumper failed, error %d\n", err); 372 vfree(cxt->oops_page_used); 373 cxt->oops_page_used = NULL; 374 return; 375 } 376 377 cxt->mtd = mtd; 378 cxt->oops_pages = (int)mtd->size / record_size; 379 find_next_position(cxt); 380 pr_info("Attached to MTD device %d\n", mtd->index); 381 } 382 383 static void mtdoops_notify_remove(struct mtd_info *mtd) 384 { 385 struct mtdoops_context *cxt = &oops_cxt; 386 387 if (mtd->index != cxt->mtd_index || cxt->mtd_index < 0) 388 return; 389 390 if (kmsg_dump_unregister(&cxt->dump) < 0) 391 pr_warn("could not unregister kmsg_dumper\n"); 392 393 cxt->mtd = NULL; 394 flush_work(&cxt->work_erase); 395 flush_work(&cxt->work_write); 396 } 397 398 399 static struct mtd_notifier mtdoops_notifier = { 400 .add = mtdoops_notify_add, 401 .remove = mtdoops_notify_remove, 402 }; 403 404 static int __init mtdoops_init(void) 405 { 406 struct mtdoops_context *cxt = &oops_cxt; 407 int mtd_index; 408 char *endp; 409 410 if (strlen(mtddev) == 0) { 411 pr_err("mtd device (mtddev=name/number) must be supplied\n"); 412 return -EINVAL; 413 } 414 if ((record_size & 4095) != 0) { 415 pr_err("record_size must be a multiple of 4096\n"); 416 return -EINVAL; 417 } 418 if (record_size < 4096) { 419 pr_err("record_size must be over 4096 bytes\n"); 420 return -EINVAL; 421 } 422 423 /* Setup the MTD device to use */ 424 cxt->mtd_index = -1; 425 mtd_index = simple_strtoul(mtddev, &endp, 0); 426 if (*endp == '\0') 427 cxt->mtd_index = mtd_index; 428 429 cxt->oops_buf = vmalloc(record_size); 430 if (!cxt->oops_buf) 431 return -ENOMEM; 432 memset(cxt->oops_buf, 0xff, record_size); 433 cxt->oops_buf_busy = 0; 434 435 INIT_WORK(&cxt->work_erase, mtdoops_workfunc_erase); 436 INIT_WORK(&cxt->work_write, mtdoops_workfunc_write); 437 438 register_mtd_user(&mtdoops_notifier); 439 return 0; 440 } 441 442 static void __exit mtdoops_exit(void) 443 { 444 struct mtdoops_context *cxt = &oops_cxt; 445 446 unregister_mtd_user(&mtdoops_notifier); 447 vfree(cxt->oops_buf); 448 vfree(cxt->oops_page_used); 449 } 450 451 452 module_init(mtdoops_init); 453 module_exit(mtdoops_exit); 454 455 MODULE_LICENSE("GPL"); 456 MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); 457 MODULE_DESCRIPTION("MTD Oops/Panic console logger/driver"); 458