linux/drivers/mtd/mtdpstore.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3#define dev_fmt(fmt) "mtdoops-pstore: " fmt
   4
   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 write
  21         * As there are no block_isbad for panic case, we should keep this
  22         * 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        else
 197                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 file
 205 *
 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() when
 208 * 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 zone
 232 * is writable. Otherwise, panic write will fail.
 233 * If zone is used, write operation will return -ENOMSG, which means that
 234 * pstore/blk will try one by one until gets an empty zone. So, it is not
 235 * 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 do
 308 * 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 can
 335                 * still read it and try to understand. So mtdpstore just hands
 336                 * over what it gets and user can judge whether the data is
 337                 * 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        else
 350                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 by
 403         * psblk. The default value of kmsg_size is 64KB. If kmsg_size
 404         * is larger than erasesize, some errors will occur since mtdpsotre
 405         * 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 do
 493 * 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