brintos

brintos / linux-shallow public Read only

0
0
Text · 4.9 KiB · 8062098 Raw
233 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2006-2008 Nokia Corporation4 *5 * Test random reads, writes and erases on MTD device.6 *7 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>8 */9 10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt11 12#include <linux/init.h>13#include <linux/module.h>14#include <linux/moduleparam.h>15#include <linux/err.h>16#include <linux/mtd/mtd.h>17#include <linux/slab.h>18#include <linux/sched.h>19#include <linux/vmalloc.h>20#include <linux/random.h>21 22#include "mtd_test.h"23 24static int dev = -EINVAL;25module_param(dev, int, S_IRUGO);26MODULE_PARM_DESC(dev, "MTD device number to use");27 28static int count = 10000;29module_param(count, int, S_IRUGO);30MODULE_PARM_DESC(count, "Number of operations to do (default is 10000)");31 32static struct mtd_info *mtd;33static unsigned char *writebuf;34static unsigned char *readbuf;35static unsigned char *bbt;36static int *offsets;37 38static int pgsize;39static int bufsize;40static int ebcnt;41static int pgcnt;42 43static int rand_eb(void)44{45	unsigned int eb;46 47again:48	/* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */49	eb = get_random_u32_below(ebcnt - 1);50	if (bbt[eb])51		goto again;52	return eb;53}54 55static int rand_offs(void)56{57	return get_random_u32_below(bufsize);58}59 60static int rand_len(int offs)61{62	return get_random_u32_below(bufsize - offs);63}64 65static int do_read(void)66{67	int eb = rand_eb();68	int offs = rand_offs();69	int len = rand_len(offs);70	loff_t addr;71 72	if (bbt[eb + 1]) {73		if (offs >= mtd->erasesize)74			offs -= mtd->erasesize;75		if (offs + len > mtd->erasesize)76			len = mtd->erasesize - offs;77	}78	addr = (loff_t)eb * mtd->erasesize + offs;79	return mtdtest_read(mtd, addr, len, readbuf);80}81 82static int do_write(void)83{84	int eb = rand_eb(), offs, err, len;85	loff_t addr;86 87	offs = offsets[eb];88	if (offs >= mtd->erasesize) {89		err = mtdtest_erase_eraseblock(mtd, eb);90		if (err)91			return err;92		offs = offsets[eb] = 0;93	}94	len = rand_len(offs);95	len = ((len + pgsize - 1) / pgsize) * pgsize;96	if (offs + len > mtd->erasesize) {97		if (bbt[eb + 1])98			len = mtd->erasesize - offs;99		else {100			err = mtdtest_erase_eraseblock(mtd, eb + 1);101			if (err)102				return err;103			offsets[eb + 1] = 0;104		}105	}106	addr = (loff_t)eb * mtd->erasesize + offs;107	err = mtdtest_write(mtd, addr, len, writebuf);108	if (unlikely(err))109		return err;110	offs += len;111	while (offs > mtd->erasesize) {112		offsets[eb++] = mtd->erasesize;113		offs -= mtd->erasesize;114	}115	offsets[eb] = offs;116	return 0;117}118 119static int do_operation(void)120{121	if (get_random_u32_below(2))122		return do_read();123	else124		return do_write();125}126 127static int __init mtd_stresstest_init(void)128{129	int err;130	int i, op;131	uint64_t tmp;132 133	printk(KERN_INFO "\n");134	printk(KERN_INFO "=================================================\n");135 136	if (dev < 0) {137		pr_info("Please specify a valid mtd-device via module parameter\n");138		pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");139		return -EINVAL;140	}141 142	pr_info("MTD device: %d\n", dev);143 144	mtd = get_mtd_device(NULL, dev);145	if (IS_ERR(mtd)) {146		err = PTR_ERR(mtd);147		pr_err("error: cannot get MTD device\n");148		return err;149	}150 151	if (mtd->writesize == 1) {152		pr_info("not NAND flash, assume page size is 512 "153		       "bytes.\n");154		pgsize = 512;155	} else156		pgsize = mtd->writesize;157 158	tmp = mtd->size;159	do_div(tmp, mtd->erasesize);160	ebcnt = tmp;161	pgcnt = mtd->erasesize / pgsize;162 163	pr_info("MTD device size %llu, eraseblock size %u, "164	       "page size %u, count of eraseblocks %u, pages per "165	       "eraseblock %u, OOB size %u\n",166	       (unsigned long long)mtd->size, mtd->erasesize,167	       pgsize, ebcnt, pgcnt, mtd->oobsize);168 169	if (ebcnt < 2) {170		pr_err("error: need at least 2 eraseblocks\n");171		err = -ENOSPC;172		goto out_put_mtd;173	}174 175	/* Read or write up 2 eraseblocks at a time */176	bufsize = mtd->erasesize * 2;177 178	err = -ENOMEM;179	readbuf = vmalloc(bufsize);180	writebuf = vmalloc(bufsize);181	offsets = kmalloc_array(ebcnt, sizeof(int), GFP_KERNEL);182	if (!readbuf || !writebuf || !offsets)183		goto out;184	for (i = 0; i < ebcnt; i++)185		offsets[i] = mtd->erasesize;186	get_random_bytes(writebuf, bufsize);187 188	bbt = kzalloc(ebcnt, GFP_KERNEL);189	if (!bbt)190		goto out;191	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);192	if (err)193		goto out;194 195	/* Do operations */196	pr_info("doing operations\n");197	for (op = 0; op < count; op++) {198		if ((op & 1023) == 0)199			pr_info("%d operations done\n", op);200		err = do_operation();201		if (err)202			goto out;203 204		err = mtdtest_relax();205		if (err)206			goto out;207	}208	pr_info("finished, %d operations done\n", op);209 210out:211	kfree(offsets);212	kfree(bbt);213	vfree(writebuf);214	vfree(readbuf);215out_put_mtd:216	put_mtd_device(mtd);217	if (err)218		pr_info("error %d occurred\n", err);219	printk(KERN_INFO "=================================================\n");220	return err;221}222module_init(mtd_stresstest_init);223 224static void __exit mtd_stresstest_exit(void)225{226	return;227}228module_exit(mtd_stresstest_exit);229 230MODULE_DESCRIPTION("Stress test module");231MODULE_AUTHOR("Adrian Hunter");232MODULE_LICENSE("GPL");233