Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2006-2008 Nokia Corporation
0004  *
0005  * Test random reads, writes and erases on MTD device.
0006  *
0007  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
0008  */
0009 
0010 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0011 
0012 #include <linux/init.h>
0013 #include <linux/module.h>
0014 #include <linux/moduleparam.h>
0015 #include <linux/err.h>
0016 #include <linux/mtd/mtd.h>
0017 #include <linux/slab.h>
0018 #include <linux/sched.h>
0019 #include <linux/vmalloc.h>
0020 #include <linux/random.h>
0021 
0022 #include "mtd_test.h"
0023 
0024 static int dev = -EINVAL;
0025 module_param(dev, int, S_IRUGO);
0026 MODULE_PARM_DESC(dev, "MTD device number to use");
0027 
0028 static int count = 10000;
0029 module_param(count, int, S_IRUGO);
0030 MODULE_PARM_DESC(count, "Number of operations to do (default is 10000)");
0031 
0032 static struct mtd_info *mtd;
0033 static unsigned char *writebuf;
0034 static unsigned char *readbuf;
0035 static unsigned char *bbt;
0036 static int *offsets;
0037 
0038 static int pgsize;
0039 static int bufsize;
0040 static int ebcnt;
0041 static int pgcnt;
0042 
0043 static int rand_eb(void)
0044 {
0045     unsigned int eb;
0046 
0047 again:
0048     eb = prandom_u32();
0049     /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */
0050     eb %= (ebcnt - 1);
0051     if (bbt[eb])
0052         goto again;
0053     return eb;
0054 }
0055 
0056 static int rand_offs(void)
0057 {
0058     unsigned int offs;
0059 
0060     offs = prandom_u32();
0061     offs %= bufsize;
0062     return offs;
0063 }
0064 
0065 static int rand_len(int offs)
0066 {
0067     unsigned int len;
0068 
0069     len = prandom_u32();
0070     len %= (bufsize - offs);
0071     return len;
0072 }
0073 
0074 static int do_read(void)
0075 {
0076     int eb = rand_eb();
0077     int offs = rand_offs();
0078     int len = rand_len(offs);
0079     loff_t addr;
0080 
0081     if (bbt[eb + 1]) {
0082         if (offs >= mtd->erasesize)
0083             offs -= mtd->erasesize;
0084         if (offs + len > mtd->erasesize)
0085             len = mtd->erasesize - offs;
0086     }
0087     addr = (loff_t)eb * mtd->erasesize + offs;
0088     return mtdtest_read(mtd, addr, len, readbuf);
0089 }
0090 
0091 static int do_write(void)
0092 {
0093     int eb = rand_eb(), offs, err, len;
0094     loff_t addr;
0095 
0096     offs = offsets[eb];
0097     if (offs >= mtd->erasesize) {
0098         err = mtdtest_erase_eraseblock(mtd, eb);
0099         if (err)
0100             return err;
0101         offs = offsets[eb] = 0;
0102     }
0103     len = rand_len(offs);
0104     len = ((len + pgsize - 1) / pgsize) * pgsize;
0105     if (offs + len > mtd->erasesize) {
0106         if (bbt[eb + 1])
0107             len = mtd->erasesize - offs;
0108         else {
0109             err = mtdtest_erase_eraseblock(mtd, eb + 1);
0110             if (err)
0111                 return err;
0112             offsets[eb + 1] = 0;
0113         }
0114     }
0115     addr = (loff_t)eb * mtd->erasesize + offs;
0116     err = mtdtest_write(mtd, addr, len, writebuf);
0117     if (unlikely(err))
0118         return err;
0119     offs += len;
0120     while (offs > mtd->erasesize) {
0121         offsets[eb++] = mtd->erasesize;
0122         offs -= mtd->erasesize;
0123     }
0124     offsets[eb] = offs;
0125     return 0;
0126 }
0127 
0128 static int do_operation(void)
0129 {
0130     if (prandom_u32() & 1)
0131         return do_read();
0132     else
0133         return do_write();
0134 }
0135 
0136 static int __init mtd_stresstest_init(void)
0137 {
0138     int err;
0139     int i, op;
0140     uint64_t tmp;
0141 
0142     printk(KERN_INFO "\n");
0143     printk(KERN_INFO "=================================================\n");
0144 
0145     if (dev < 0) {
0146         pr_info("Please specify a valid mtd-device via module parameter\n");
0147         pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
0148         return -EINVAL;
0149     }
0150 
0151     pr_info("MTD device: %d\n", dev);
0152 
0153     mtd = get_mtd_device(NULL, dev);
0154     if (IS_ERR(mtd)) {
0155         err = PTR_ERR(mtd);
0156         pr_err("error: cannot get MTD device\n");
0157         return err;
0158     }
0159 
0160     if (mtd->writesize == 1) {
0161         pr_info("not NAND flash, assume page size is 512 "
0162                "bytes.\n");
0163         pgsize = 512;
0164     } else
0165         pgsize = mtd->writesize;
0166 
0167     tmp = mtd->size;
0168     do_div(tmp, mtd->erasesize);
0169     ebcnt = tmp;
0170     pgcnt = mtd->erasesize / pgsize;
0171 
0172     pr_info("MTD device size %llu, eraseblock size %u, "
0173            "page size %u, count of eraseblocks %u, pages per "
0174            "eraseblock %u, OOB size %u\n",
0175            (unsigned long long)mtd->size, mtd->erasesize,
0176            pgsize, ebcnt, pgcnt, mtd->oobsize);
0177 
0178     if (ebcnt < 2) {
0179         pr_err("error: need at least 2 eraseblocks\n");
0180         err = -ENOSPC;
0181         goto out_put_mtd;
0182     }
0183 
0184     /* Read or write up 2 eraseblocks at a time */
0185     bufsize = mtd->erasesize * 2;
0186 
0187     err = -ENOMEM;
0188     readbuf = vmalloc(bufsize);
0189     writebuf = vmalloc(bufsize);
0190     offsets = kmalloc_array(ebcnt, sizeof(int), GFP_KERNEL);
0191     if (!readbuf || !writebuf || !offsets)
0192         goto out;
0193     for (i = 0; i < ebcnt; i++)
0194         offsets[i] = mtd->erasesize;
0195     prandom_bytes(writebuf, bufsize);
0196 
0197     bbt = kzalloc(ebcnt, GFP_KERNEL);
0198     if (!bbt)
0199         goto out;
0200     err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
0201     if (err)
0202         goto out;
0203 
0204     /* Do operations */
0205     pr_info("doing operations\n");
0206     for (op = 0; op < count; op++) {
0207         if ((op & 1023) == 0)
0208             pr_info("%d operations done\n", op);
0209         err = do_operation();
0210         if (err)
0211             goto out;
0212 
0213         err = mtdtest_relax();
0214         if (err)
0215             goto out;
0216     }
0217     pr_info("finished, %d operations done\n", op);
0218 
0219 out:
0220     kfree(offsets);
0221     kfree(bbt);
0222     vfree(writebuf);
0223     vfree(readbuf);
0224 out_put_mtd:
0225     put_mtd_device(mtd);
0226     if (err)
0227         pr_info("error %d occurred\n", err);
0228     printk(KERN_INFO "=================================================\n");
0229     return err;
0230 }
0231 module_init(mtd_stresstest_init);
0232 
0233 static void __exit mtd_stresstest_exit(void)
0234 {
0235     return;
0236 }
0237 module_exit(mtd_stresstest_exit);
0238 
0239 MODULE_DESCRIPTION("Stress test module");
0240 MODULE_AUTHOR("Adrian Hunter");
0241 MODULE_LICENSE("GPL");