580 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#define dev_fmt(fmt) "mtdoops-pstore: " fmt4 5#include <linux/kernel.h>6#include <linux/module.h>7#include <linux/pstore_blk.h>8#include <linux/mtd/mtd.h>9#include <linux/bitops.h>10#include <linux/slab.h>11 12static struct mtdpstore_context {13 int index;14 struct pstore_blk_config info;15 struct pstore_device_info dev;16 struct mtd_info *mtd;17 unsigned long *rmmap; /* removed bit map */18 unsigned long *usedmap; /* used bit map */19 /*20 * used for panic write21 * As there are no block_isbad for panic case, we should keep this22 * status before panic to ensure panic_write not failed.23 */24 unsigned long *badmap; /* bad block bit map */25} oops_cxt;26 27static int mtdpstore_block_isbad(struct mtdpstore_context *cxt, loff_t off)28{29 int ret;30 struct mtd_info *mtd = cxt->mtd;31 u64 blknum;32 33 off = ALIGN_DOWN(off, mtd->erasesize);34 blknum = div_u64(off, mtd->erasesize);35 36 if (test_bit(blknum, cxt->badmap))37 return true;38 ret = mtd_block_isbad(mtd, off);39 if (ret < 0) {40 dev_err(&mtd->dev, "mtd_block_isbad failed, aborting\n");41 return ret;42 } else if (ret > 0) {43 set_bit(blknum, cxt->badmap);44 return true;45 }46 return false;47}48 49static inline int mtdpstore_panic_block_isbad(struct mtdpstore_context *cxt,50 loff_t off)51{52 struct mtd_info *mtd = cxt->mtd;53 u64 blknum;54 55 off = ALIGN_DOWN(off, mtd->erasesize);56 blknum = div_u64(off, mtd->erasesize);57 return test_bit(blknum, cxt->badmap);58}59 60static inline void mtdpstore_mark_used(struct mtdpstore_context *cxt,61 loff_t off)62{63 struct mtd_info *mtd = cxt->mtd;64 u64 zonenum = div_u64(off, cxt->info.kmsg_size);65 66 dev_dbg(&mtd->dev, "mark zone %llu used\n", zonenum);67 set_bit(zonenum, cxt->usedmap);68}69 70static inline void mtdpstore_mark_unused(struct mtdpstore_context *cxt,71 loff_t off)72{73 struct mtd_info *mtd = cxt->mtd;74 u64 zonenum = div_u64(off, cxt->info.kmsg_size);75 76 dev_dbg(&mtd->dev, "mark zone %llu unused\n", zonenum);77 clear_bit(zonenum, cxt->usedmap);78}79 80static inline void mtdpstore_block_mark_unused(struct mtdpstore_context *cxt,81 loff_t off)82{83 struct mtd_info *mtd = cxt->mtd;84 u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size;85 u64 zonenum;86 87 off = ALIGN_DOWN(off, mtd->erasesize);88 zonenum = div_u64(off, cxt->info.kmsg_size);89 while (zonecnt > 0) {90 dev_dbg(&mtd->dev, "mark zone %llu unused\n", zonenum);91 clear_bit(zonenum, cxt->usedmap);92 zonenum++;93 zonecnt--;94 }95}96 97static inline int mtdpstore_is_used(struct mtdpstore_context *cxt, loff_t off)98{99 u64 zonenum = div_u64(off, cxt->info.kmsg_size);100 u64 blknum = div_u64(off, cxt->mtd->erasesize);101 102 if (test_bit(blknum, cxt->badmap))103 return true;104 return test_bit(zonenum, cxt->usedmap);105}106 107static int mtdpstore_block_is_used(struct mtdpstore_context *cxt,108 loff_t off)109{110 struct mtd_info *mtd = cxt->mtd;111 u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size;112 u64 zonenum;113 114 off = ALIGN_DOWN(off, mtd->erasesize);115 zonenum = div_u64(off, cxt->info.kmsg_size);116 while (zonecnt > 0) {117 if (test_bit(zonenum, cxt->usedmap))118 return true;119 zonenum++;120 zonecnt--;121 }122 return false;123}124 125static int mtdpstore_is_empty(struct mtdpstore_context *cxt, char *buf,126 size_t size)127{128 struct mtd_info *mtd = cxt->mtd;129 size_t sz;130 int i;131 132 sz = min_t(uint32_t, size, mtd->writesize / 4);133 for (i = 0; i < sz; i++) {134 if (buf[i] != (char)0xFF)135 return false;136 }137 return true;138}139 140static void mtdpstore_mark_removed(struct mtdpstore_context *cxt, loff_t off)141{142 struct mtd_info *mtd = cxt->mtd;143 u64 zonenum = div_u64(off, cxt->info.kmsg_size);144 145 dev_dbg(&mtd->dev, "mark zone %llu removed\n", zonenum);146 set_bit(zonenum, cxt->rmmap);147}148 149static void mtdpstore_block_clear_removed(struct mtdpstore_context *cxt,150 loff_t off)151{152 struct mtd_info *mtd = cxt->mtd;153 u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size;154 u64 zonenum;155 156 off = ALIGN_DOWN(off, mtd->erasesize);157 zonenum = div_u64(off, cxt->info.kmsg_size);158 while (zonecnt > 0) {159 clear_bit(zonenum, cxt->rmmap);160 zonenum++;161 zonecnt--;162 }163}164 165static int mtdpstore_block_is_removed(struct mtdpstore_context *cxt,166 loff_t off)167{168 struct mtd_info *mtd = cxt->mtd;169 u32 zonecnt = mtd->erasesize / cxt->info.kmsg_size;170 u64 zonenum;171 172 off = ALIGN_DOWN(off, mtd->erasesize);173 zonenum = div_u64(off, cxt->info.kmsg_size);174 while (zonecnt > 0) {175 if (test_bit(zonenum, cxt->rmmap))176 return true;177 zonenum++;178 zonecnt--;179 }180 return false;181}182 183static int mtdpstore_erase_do(struct mtdpstore_context *cxt, loff_t off)184{185 struct mtd_info *mtd = cxt->mtd;186 struct erase_info erase;187 int ret;188 189 off = ALIGN_DOWN(off, cxt->mtd->erasesize);190 dev_dbg(&mtd->dev, "try to erase off 0x%llx\n", off);191 erase.len = cxt->mtd->erasesize;192 erase.addr = off;193 ret = mtd_erase(cxt->mtd, &erase);194 if (!ret)195 mtdpstore_block_clear_removed(cxt, off);196 else197 dev_err(&mtd->dev, "erase of region [0x%llx, 0x%llx] on \"%s\" failed\n",198 (unsigned long long)erase.addr,199 (unsigned long long)erase.len, cxt->info.device);200 return ret;201}202 203/*204 * called while removing file205 *206 * Avoiding over erasing, do erase block only when the whole block is unused.207 * If the block contains valid log, do erase lazily on flush_removed() when208 * unregister.209 */210static ssize_t mtdpstore_erase(size_t size, loff_t off)211{212 struct mtdpstore_context *cxt = &oops_cxt;213 214 if (mtdpstore_block_isbad(cxt, off))215 return -EIO;216 217 mtdpstore_mark_unused(cxt, off);218 219 /* If the block still has valid data, mtdpstore do erase lazily */220 if (likely(mtdpstore_block_is_used(cxt, off))) {221 mtdpstore_mark_removed(cxt, off);222 return 0;223 }224 225 /* all zones are unused, erase it */226 return mtdpstore_erase_do(cxt, off);227}228 229/*230 * What is security for mtdpstore?231 * As there is no erase for panic case, we should ensure at least one zone232 * is writable. Otherwise, panic write will fail.233 * If zone is used, write operation will return -ENOMSG, which means that234 * pstore/blk will try one by one until gets an empty zone. So, it is not235 * needed to ensure the next zone is empty, but at least one.236 */237static int mtdpstore_security(struct mtdpstore_context *cxt, loff_t off)238{239 int ret = 0, i;240 struct mtd_info *mtd = cxt->mtd;241 u32 zonenum = (u32)div_u64(off, cxt->info.kmsg_size);242 u32 zonecnt = (u32)div_u64(cxt->mtd->size, cxt->info.kmsg_size);243 u32 blkcnt = (u32)div_u64(cxt->mtd->size, cxt->mtd->erasesize);244 u32 erasesize = cxt->mtd->erasesize;245 246 for (i = 0; i < zonecnt; i++) {247 u32 num = (zonenum + i) % zonecnt;248 249 /* found empty zone */250 if (!test_bit(num, cxt->usedmap))251 return 0;252 }253 254 /* If there is no any empty zone, we have no way but to do erase */255 while (blkcnt--) {256 div64_u64_rem(off + erasesize, cxt->mtd->size, (u64 *)&off);257 258 if (mtdpstore_block_isbad(cxt, off))259 continue;260 261 ret = mtdpstore_erase_do(cxt, off);262 if (!ret) {263 mtdpstore_block_mark_unused(cxt, off);264 break;265 }266 }267 268 if (ret)269 dev_err(&mtd->dev, "all blocks bad!\n");270 dev_dbg(&mtd->dev, "end security\n");271 return ret;272}273 274static ssize_t mtdpstore_write(const char *buf, size_t size, loff_t off)275{276 struct mtdpstore_context *cxt = &oops_cxt;277 struct mtd_info *mtd = cxt->mtd;278 size_t retlen;279 int ret;280 281 if (mtdpstore_block_isbad(cxt, off))282 return -ENOMSG;283 284 /* zone is used, please try next one */285 if (mtdpstore_is_used(cxt, off))286 return -ENOMSG;287 288 dev_dbg(&mtd->dev, "try to write off 0x%llx size %zu\n", off, size);289 ret = mtd_write(cxt->mtd, off, size, &retlen, (u_char *)buf);290 if (ret < 0 || retlen != size) {291 dev_err(&mtd->dev, "write failure at %lld (%zu of %zu written), err %d\n",292 off, retlen, size, ret);293 return -EIO;294 }295 mtdpstore_mark_used(cxt, off);296 297 mtdpstore_security(cxt, off);298 return retlen;299}300 301static inline bool mtdpstore_is_io_error(int ret)302{303 return ret < 0 && !mtd_is_bitflip(ret) && !mtd_is_eccerr(ret);304}305 306/*307 * All zones will be read as pstore/blk will read zone one by one when do308 * recover.309 */310static ssize_t mtdpstore_read(char *buf, size_t size, loff_t off)311{312 struct mtdpstore_context *cxt = &oops_cxt;313 struct mtd_info *mtd = cxt->mtd;314 size_t retlen, done;315 int ret;316 317 if (mtdpstore_block_isbad(cxt, off))318 return -ENOMSG;319 320 dev_dbg(&mtd->dev, "try to read off 0x%llx size %zu\n", off, size);321 for (done = 0, retlen = 0; done < size; done += retlen) {322 retlen = 0;323 324 ret = mtd_read(cxt->mtd, off + done, size - done, &retlen,325 (u_char *)buf + done);326 if (mtdpstore_is_io_error(ret)) {327 dev_err(&mtd->dev, "read failure at %lld (%zu of %zu read), err %d\n",328 off + done, retlen, size - done, ret);329 /* the zone may be broken, try next one */330 return -ENOMSG;331 }332 333 /*334 * ECC error. The impact on log data is so small. Maybe we can335 * still read it and try to understand. So mtdpstore just hands336 * over what it gets and user can judge whether the data is337 * valid or not.338 */339 if (mtd_is_eccerr(ret)) {340 dev_err(&mtd->dev, "ecc error at %lld (%zu of %zu read), err %d\n",341 off + done, retlen, size - done, ret);342 /* driver may not set retlen when ecc error */343 retlen = retlen == 0 ? size - done : retlen;344 }345 }346 347 if (mtdpstore_is_empty(cxt, buf, size))348 mtdpstore_mark_unused(cxt, off);349 else350 mtdpstore_mark_used(cxt, off);351 352 mtdpstore_security(cxt, off);353 return retlen;354}355 356static ssize_t mtdpstore_panic_write(const char *buf, size_t size, loff_t off)357{358 struct mtdpstore_context *cxt = &oops_cxt;359 struct mtd_info *mtd = cxt->mtd;360 size_t retlen;361 int ret;362 363 if (mtdpstore_panic_block_isbad(cxt, off))364 return -ENOMSG;365 366 /* zone is used, please try next one */367 if (mtdpstore_is_used(cxt, off))368 return -ENOMSG;369 370 ret = mtd_panic_write(cxt->mtd, off, size, &retlen, (u_char *)buf);371 if (ret < 0 || size != retlen) {372 dev_err(&mtd->dev, "panic write failure at %lld (%zu of %zu read), err %d\n",373 off, retlen, size, ret);374 return -EIO;375 }376 mtdpstore_mark_used(cxt, off);377 378 return retlen;379}380 381static void mtdpstore_notify_add(struct mtd_info *mtd)382{383 int ret;384 struct mtdpstore_context *cxt = &oops_cxt;385 struct pstore_blk_config *info = &cxt->info;386 unsigned long longcnt;387 388 if (!strcmp(mtd->name, info->device))389 cxt->index = mtd->index;390 391 if (mtd->index != cxt->index || cxt->index < 0)392 return;393 394 dev_dbg(&mtd->dev, "found matching MTD device %s\n", mtd->name);395 396 if (mtd->size < info->kmsg_size * 2) {397 dev_err(&mtd->dev, "MTD partition %d not big enough\n",398 mtd->index);399 return;400 }401 /*402 * kmsg_size must be aligned to 4096 Bytes, which is limited by403 * psblk. The default value of kmsg_size is 64KB. If kmsg_size404 * is larger than erasesize, some errors will occur since mtdpstore405 * is designed on it.406 */407 if (mtd->erasesize < info->kmsg_size) {408 dev_err(&mtd->dev, "eraseblock size of MTD partition %d too small\n",409 mtd->index);410 return;411 }412 if (unlikely(info->kmsg_size % mtd->writesize)) {413 dev_err(&mtd->dev, "record size %lu KB must align to write size %d KB\n",414 info->kmsg_size / 1024,415 mtd->writesize / 1024);416 return;417 }418 419 longcnt = BITS_TO_LONGS(div_u64(mtd->size, info->kmsg_size));420 cxt->rmmap = kcalloc(longcnt, sizeof(long), GFP_KERNEL);421 cxt->usedmap = kcalloc(longcnt, sizeof(long), GFP_KERNEL);422 423 longcnt = BITS_TO_LONGS(div_u64(mtd->size, mtd->erasesize));424 cxt->badmap = kcalloc(longcnt, sizeof(long), GFP_KERNEL);425 426 /* just support dmesg right now */427 cxt->dev.flags = PSTORE_FLAGS_DMESG;428 cxt->dev.zone.read = mtdpstore_read;429 cxt->dev.zone.write = mtdpstore_write;430 cxt->dev.zone.erase = mtdpstore_erase;431 cxt->dev.zone.panic_write = mtdpstore_panic_write;432 cxt->dev.zone.total_size = mtd->size;433 434 ret = register_pstore_device(&cxt->dev);435 if (ret) {436 dev_err(&mtd->dev, "mtd%d register to psblk failed\n",437 mtd->index);438 return;439 }440 cxt->mtd = mtd;441 dev_info(&mtd->dev, "Attached to MTD device %d\n", mtd->index);442}443 444static int mtdpstore_flush_removed_do(struct mtdpstore_context *cxt,445 loff_t off, size_t size)446{447 struct mtd_info *mtd = cxt->mtd;448 u_char *buf;449 int ret;450 size_t retlen;451 struct erase_info erase;452 453 buf = kmalloc(mtd->erasesize, GFP_KERNEL);454 if (!buf)455 return -ENOMEM;456 457 /* 1st. read to cache */458 ret = mtd_read(mtd, off, mtd->erasesize, &retlen, buf);459 if (mtdpstore_is_io_error(ret))460 goto free;461 462 /* 2nd. erase block */463 erase.len = mtd->erasesize;464 erase.addr = off;465 ret = mtd_erase(mtd, &erase);466 if (ret)467 goto free;468 469 /* 3rd. write back */470 while (size) {471 unsigned int zonesize = cxt->info.kmsg_size;472 473 /* there is valid data on block, write back */474 if (mtdpstore_is_used(cxt, off)) {475 ret = mtd_write(mtd, off, zonesize, &retlen, buf);476 if (ret)477 dev_err(&mtd->dev, "write failure at %lld (%zu of %u written), err %d\n",478 off, retlen, zonesize, ret);479 }480 481 off += zonesize;482 size -= min_t(unsigned int, zonesize, size);483 }484 485free:486 kfree(buf);487 return ret;488}489 490/*491 * What does mtdpstore_flush_removed() do?492 * When user remove any log file on pstore filesystem, mtdpstore should do493 * something to ensure log file removed. If the whole block is no longer used,494 * it's nice to erase the block. However if the block still contains valid log,495 * what mtdpstore can do is to erase and write the valid log back.496 */497static int mtdpstore_flush_removed(struct mtdpstore_context *cxt)498{499 struct mtd_info *mtd = cxt->mtd;500 int ret;501 loff_t off;502 u32 blkcnt = (u32)div_u64(mtd->size, mtd->erasesize);503 504 for (off = 0; blkcnt > 0; blkcnt--, off += mtd->erasesize) {505 ret = mtdpstore_block_isbad(cxt, off);506 if (ret)507 continue;508 509 ret = mtdpstore_block_is_removed(cxt, off);510 if (!ret)511 continue;512 513 ret = mtdpstore_flush_removed_do(cxt, off, mtd->erasesize);514 if (ret)515 return ret;516 }517 return 0;518}519 520static void mtdpstore_notify_remove(struct mtd_info *mtd)521{522 struct mtdpstore_context *cxt = &oops_cxt;523 524 if (mtd->index != cxt->index || cxt->index < 0)525 return;526 527 mtdpstore_flush_removed(cxt);528 529 unregister_pstore_device(&cxt->dev);530 kfree(cxt->badmap);531 kfree(cxt->usedmap);532 kfree(cxt->rmmap);533 cxt->mtd = NULL;534 cxt->index = -1;535}536 537static struct mtd_notifier mtdpstore_notifier = {538 .add = mtdpstore_notify_add,539 .remove = mtdpstore_notify_remove,540};541 542static int __init mtdpstore_init(void)543{544 int ret;545 struct mtdpstore_context *cxt = &oops_cxt;546 struct pstore_blk_config *info = &cxt->info;547 548 ret = pstore_blk_get_config(info);549 if (unlikely(ret))550 return ret;551 552 if (strlen(info->device) == 0) {553 pr_err("mtd device must be supplied (device name is empty)\n");554 return -EINVAL;555 }556 if (!info->kmsg_size) {557 pr_err("no backend enabled (kmsg_size is 0)\n");558 return -EINVAL;559 }560 561 /* Setup the MTD device to use */562 ret = kstrtoint((char *)info->device, 0, &cxt->index);563 if (ret)564 cxt->index = -1;565 566 register_mtd_user(&mtdpstore_notifier);567 return 0;568}569module_init(mtdpstore_init);570 571static void __exit mtdpstore_exit(void)572{573 unregister_mtd_user(&mtdpstore_notifier);574}575module_exit(mtdpstore_exit);576 577MODULE_LICENSE("GPL");578MODULE_AUTHOR("WeiXiong Liao <liaoweixiong@allwinnertech.com>");579MODULE_DESCRIPTION("MTD backend for pstore/blk");580