cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

oobtest.c (17402B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2006-2008 Nokia Corporation
      4 *
      5 * Test OOB read and write on MTD device.
      6 *
      7 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
      8 */
      9
     10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     11
     12#include <asm/div64.h>
     13#include <linux/init.h>
     14#include <linux/module.h>
     15#include <linux/moduleparam.h>
     16#include <linux/err.h>
     17#include <linux/mtd/mtd.h>
     18#include <linux/slab.h>
     19#include <linux/sched.h>
     20#include <linux/random.h>
     21
     22#include "mtd_test.h"
     23
     24static int dev = -EINVAL;
     25static int bitflip_limit;
     26module_param(dev, int, S_IRUGO);
     27MODULE_PARM_DESC(dev, "MTD device number to use");
     28module_param(bitflip_limit, int, S_IRUGO);
     29MODULE_PARM_DESC(bitflip_limit, "Max. allowed bitflips per page");
     30
     31static struct mtd_info *mtd;
     32static unsigned char *readbuf;
     33static unsigned char *writebuf;
     34static unsigned char *bbt;
     35
     36static int ebcnt;
     37static int pgcnt;
     38static int errcnt;
     39static int use_offset;
     40static int use_len;
     41static int use_len_max;
     42static int vary_offset;
     43static struct rnd_state rnd_state;
     44
     45static void do_vary_offset(void)
     46{
     47	use_len -= 1;
     48	if (use_len < 1) {
     49		use_offset += 1;
     50		if (use_offset >= use_len_max)
     51			use_offset = 0;
     52		use_len = use_len_max - use_offset;
     53	}
     54}
     55
     56static int write_eraseblock(int ebnum)
     57{
     58	int i;
     59	struct mtd_oob_ops ops;
     60	int err = 0;
     61	loff_t addr = (loff_t)ebnum * mtd->erasesize;
     62
     63	prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
     64	for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
     65		ops.mode      = MTD_OPS_AUTO_OOB;
     66		ops.len       = 0;
     67		ops.retlen    = 0;
     68		ops.ooblen    = use_len;
     69		ops.oobretlen = 0;
     70		ops.ooboffs   = use_offset;
     71		ops.datbuf    = NULL;
     72		ops.oobbuf    = writebuf + (use_len_max * i) + use_offset;
     73		err = mtd_write_oob(mtd, addr, &ops);
     74		if (err || ops.oobretlen != use_len) {
     75			pr_err("error: writeoob failed at %#llx\n",
     76			       (long long)addr);
     77			pr_err("error: use_len %d, use_offset %d\n",
     78			       use_len, use_offset);
     79			errcnt += 1;
     80			return err ? err : -1;
     81		}
     82		if (vary_offset)
     83			do_vary_offset();
     84	}
     85
     86	return err;
     87}
     88
     89static int write_whole_device(void)
     90{
     91	int err;
     92	unsigned int i;
     93
     94	pr_info("writing OOBs of whole device\n");
     95	for (i = 0; i < ebcnt; ++i) {
     96		if (bbt[i])
     97			continue;
     98		err = write_eraseblock(i);
     99		if (err)
    100			return err;
    101		if (i % 256 == 0)
    102			pr_info("written up to eraseblock %u\n", i);
    103
    104		err = mtdtest_relax();
    105		if (err)
    106			return err;
    107	}
    108	pr_info("written %u eraseblocks\n", i);
    109	return 0;
    110}
    111
    112/*
    113 * Display the address, offset and data bytes at comparison failure.
    114 * Return number of bitflips encountered.
    115 */
    116static size_t memcmpshowoffset(loff_t addr, loff_t offset, const void *cs,
    117			       const void *ct, size_t count)
    118{
    119	const unsigned char *su1, *su2;
    120	int res;
    121	size_t i = 0;
    122	size_t bitflips = 0;
    123
    124	for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) {
    125		res = *su1 ^ *su2;
    126		if (res) {
    127			pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0x%x diff 0x%x\n",
    128				(unsigned long)addr, (unsigned long)offset + i,
    129				*su1, *su2, res);
    130			bitflips += hweight8(res);
    131		}
    132	}
    133
    134	return bitflips;
    135}
    136
    137#define memcmpshow(addr, cs, ct, count) memcmpshowoffset((addr), 0, (cs), (ct),\
    138							 (count))
    139
    140/*
    141 * Compare with 0xff and show the address, offset and data bytes at
    142 * comparison failure. Return number of bitflips encountered.
    143 */
    144static size_t memffshow(loff_t addr, loff_t offset, const void *cs,
    145			size_t count)
    146{
    147	const unsigned char *su1;
    148	int res;
    149	size_t i = 0;
    150	size_t bitflips = 0;
    151
    152	for (su1 = cs; 0 < count; ++su1, count--, i++) {
    153		res = *su1 ^ 0xff;
    154		if (res) {
    155			pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0xff diff 0x%x\n",
    156				(unsigned long)addr, (unsigned long)offset + i,
    157				*su1, res);
    158			bitflips += hweight8(res);
    159		}
    160	}
    161
    162	return bitflips;
    163}
    164
    165static int verify_eraseblock(int ebnum)
    166{
    167	int i;
    168	struct mtd_oob_ops ops;
    169	int err = 0;
    170	loff_t addr = (loff_t)ebnum * mtd->erasesize;
    171	size_t bitflips;
    172
    173	prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
    174	for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
    175		ops.mode      = MTD_OPS_AUTO_OOB;
    176		ops.len       = 0;
    177		ops.retlen    = 0;
    178		ops.ooblen    = use_len;
    179		ops.oobretlen = 0;
    180		ops.ooboffs   = use_offset;
    181		ops.datbuf    = NULL;
    182		ops.oobbuf    = readbuf;
    183		err = mtd_read_oob(mtd, addr, &ops);
    184		if (mtd_is_bitflip(err))
    185			err = 0;
    186
    187		if (err || ops.oobretlen != use_len) {
    188			pr_err("error: readoob failed at %#llx\n",
    189			       (long long)addr);
    190			errcnt += 1;
    191			return err ? err : -1;
    192		}
    193
    194		bitflips = memcmpshow(addr, readbuf,
    195				      writebuf + (use_len_max * i) + use_offset,
    196				      use_len);
    197		if (bitflips > bitflip_limit) {
    198			pr_err("error: verify failed at %#llx\n",
    199			       (long long)addr);
    200			errcnt += 1;
    201			if (errcnt > 1000) {
    202				pr_err("error: too many errors\n");
    203				return -1;
    204			}
    205		} else if (bitflips) {
    206			pr_info("ignoring error as within bitflip_limit\n");
    207		}
    208
    209		if (use_offset != 0 || use_len < mtd->oobavail) {
    210			int k;
    211
    212			ops.mode      = MTD_OPS_AUTO_OOB;
    213			ops.len       = 0;
    214			ops.retlen    = 0;
    215			ops.ooblen    = mtd->oobavail;
    216			ops.oobretlen = 0;
    217			ops.ooboffs   = 0;
    218			ops.datbuf    = NULL;
    219			ops.oobbuf    = readbuf;
    220			err = mtd_read_oob(mtd, addr, &ops);
    221			if (mtd_is_bitflip(err))
    222				err = 0;
    223
    224			if (err || ops.oobretlen != mtd->oobavail) {
    225				pr_err("error: readoob failed at %#llx\n",
    226						(long long)addr);
    227				errcnt += 1;
    228				return err ? err : -1;
    229			}
    230			bitflips = memcmpshowoffset(addr, use_offset,
    231						    readbuf + use_offset,
    232						    writebuf + (use_len_max * i) + use_offset,
    233						    use_len);
    234
    235			/* verify pre-offset area for 0xff */
    236			bitflips += memffshow(addr, 0, readbuf, use_offset);
    237
    238			/* verify post-(use_offset + use_len) area for 0xff */
    239			k = use_offset + use_len;
    240			bitflips += memffshow(addr, k, readbuf + k,
    241					      mtd->oobavail - k);
    242
    243			if (bitflips > bitflip_limit) {
    244				pr_err("error: verify failed at %#llx\n",
    245						(long long)addr);
    246				errcnt += 1;
    247				if (errcnt > 1000) {
    248					pr_err("error: too many errors\n");
    249					return -1;
    250				}
    251			} else if (bitflips) {
    252				pr_info("ignoring errors as within bitflip limit\n");
    253			}
    254		}
    255		if (vary_offset)
    256			do_vary_offset();
    257	}
    258	return err;
    259}
    260
    261static int verify_eraseblock_in_one_go(int ebnum)
    262{
    263	struct mtd_oob_ops ops;
    264	int err = 0;
    265	loff_t addr = (loff_t)ebnum * mtd->erasesize;
    266	size_t len = mtd->oobavail * pgcnt;
    267	size_t oobavail = mtd->oobavail;
    268	size_t bitflips;
    269	int i;
    270
    271	prandom_bytes_state(&rnd_state, writebuf, len);
    272	ops.mode      = MTD_OPS_AUTO_OOB;
    273	ops.len       = 0;
    274	ops.retlen    = 0;
    275	ops.ooblen    = len;
    276	ops.oobretlen = 0;
    277	ops.ooboffs   = 0;
    278	ops.datbuf    = NULL;
    279	ops.oobbuf    = readbuf;
    280
    281	/* read entire block's OOB at one go */
    282	err = mtd_read_oob(mtd, addr, &ops);
    283	if (mtd_is_bitflip(err))
    284		err = 0;
    285
    286	if (err || ops.oobretlen != len) {
    287		pr_err("error: readoob failed at %#llx\n",
    288		       (long long)addr);
    289		errcnt += 1;
    290		return err ? err : -1;
    291	}
    292
    293	/* verify one page OOB at a time for bitflip per page limit check */
    294	for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
    295		bitflips = memcmpshow(addr, readbuf + (i * oobavail),
    296				      writebuf + (i * oobavail), oobavail);
    297		if (bitflips > bitflip_limit) {
    298			pr_err("error: verify failed at %#llx\n",
    299			       (long long)addr);
    300			errcnt += 1;
    301			if (errcnt > 1000) {
    302				pr_err("error: too many errors\n");
    303				return -1;
    304			}
    305		} else if (bitflips) {
    306			pr_info("ignoring error as within bitflip_limit\n");
    307		}
    308	}
    309
    310	return err;
    311}
    312
    313static int verify_all_eraseblocks(void)
    314{
    315	int err;
    316	unsigned int i;
    317
    318	pr_info("verifying all eraseblocks\n");
    319	for (i = 0; i < ebcnt; ++i) {
    320		if (bbt[i])
    321			continue;
    322		err = verify_eraseblock(i);
    323		if (err)
    324			return err;
    325		if (i % 256 == 0)
    326			pr_info("verified up to eraseblock %u\n", i);
    327
    328		err = mtdtest_relax();
    329		if (err)
    330			return err;
    331	}
    332	pr_info("verified %u eraseblocks\n", i);
    333	return 0;
    334}
    335
    336static int __init mtd_oobtest_init(void)
    337{
    338	int err = 0;
    339	unsigned int i;
    340	uint64_t tmp;
    341	struct mtd_oob_ops ops;
    342	loff_t addr = 0, addr0;
    343
    344	printk(KERN_INFO "\n");
    345	printk(KERN_INFO "=================================================\n");
    346
    347	if (dev < 0) {
    348		pr_info("Please specify a valid mtd-device via module parameter\n");
    349		pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
    350		return -EINVAL;
    351	}
    352
    353	pr_info("MTD device: %d\n", dev);
    354
    355	mtd = get_mtd_device(NULL, dev);
    356	if (IS_ERR(mtd)) {
    357		err = PTR_ERR(mtd);
    358		pr_err("error: cannot get MTD device\n");
    359		return err;
    360	}
    361
    362	if (!mtd_type_is_nand(mtd)) {
    363		pr_info("this test requires NAND flash\n");
    364		goto out;
    365	}
    366
    367	tmp = mtd->size;
    368	do_div(tmp, mtd->erasesize);
    369	ebcnt = tmp;
    370	pgcnt = mtd->erasesize / mtd->writesize;
    371
    372	pr_info("MTD device size %llu, eraseblock size %u, "
    373	       "page size %u, count of eraseblocks %u, pages per "
    374	       "eraseblock %u, OOB size %u\n",
    375	       (unsigned long long)mtd->size, mtd->erasesize,
    376	       mtd->writesize, ebcnt, pgcnt, mtd->oobsize);
    377
    378	err = -ENOMEM;
    379	readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
    380	if (!readbuf)
    381		goto out;
    382	writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
    383	if (!writebuf)
    384		goto out;
    385	bbt = kzalloc(ebcnt, GFP_KERNEL);
    386	if (!bbt)
    387		goto out;
    388
    389	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
    390	if (err)
    391		goto out;
    392
    393	use_offset = 0;
    394	use_len = mtd->oobavail;
    395	use_len_max = mtd->oobavail;
    396	vary_offset = 0;
    397
    398	/* First test: write all OOB, read it back and verify */
    399	pr_info("test 1 of 5\n");
    400
    401	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
    402	if (err)
    403		goto out;
    404
    405	prandom_seed_state(&rnd_state, 1);
    406	err = write_whole_device();
    407	if (err)
    408		goto out;
    409
    410	prandom_seed_state(&rnd_state, 1);
    411	err = verify_all_eraseblocks();
    412	if (err)
    413		goto out;
    414
    415	/*
    416	 * Second test: write all OOB, a block at a time, read it back and
    417	 * verify.
    418	 */
    419	pr_info("test 2 of 5\n");
    420
    421	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
    422	if (err)
    423		goto out;
    424
    425	prandom_seed_state(&rnd_state, 3);
    426	err = write_whole_device();
    427	if (err)
    428		goto out;
    429
    430	/* Check all eraseblocks */
    431	prandom_seed_state(&rnd_state, 3);
    432	pr_info("verifying all eraseblocks\n");
    433	for (i = 0; i < ebcnt; ++i) {
    434		if (bbt[i])
    435			continue;
    436		err = verify_eraseblock_in_one_go(i);
    437		if (err)
    438			goto out;
    439		if (i % 256 == 0)
    440			pr_info("verified up to eraseblock %u\n", i);
    441
    442		err = mtdtest_relax();
    443		if (err)
    444			goto out;
    445	}
    446	pr_info("verified %u eraseblocks\n", i);
    447
    448	/*
    449	 * Third test: write OOB at varying offsets and lengths, read it back
    450	 * and verify.
    451	 */
    452	pr_info("test 3 of 5\n");
    453
    454	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
    455	if (err)
    456		goto out;
    457
    458	/* Write all eraseblocks */
    459	use_offset = 0;
    460	use_len = mtd->oobavail;
    461	use_len_max = mtd->oobavail;
    462	vary_offset = 1;
    463	prandom_seed_state(&rnd_state, 5);
    464
    465	err = write_whole_device();
    466	if (err)
    467		goto out;
    468
    469	/* Check all eraseblocks */
    470	use_offset = 0;
    471	use_len = mtd->oobavail;
    472	use_len_max = mtd->oobavail;
    473	vary_offset = 1;
    474	prandom_seed_state(&rnd_state, 5);
    475	err = verify_all_eraseblocks();
    476	if (err)
    477		goto out;
    478
    479	use_offset = 0;
    480	use_len = mtd->oobavail;
    481	use_len_max = mtd->oobavail;
    482	vary_offset = 0;
    483
    484	/* Fourth test: try to write off end of device */
    485	pr_info("test 4 of 5\n");
    486
    487	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
    488	if (err)
    489		goto out;
    490
    491	addr0 = 0;
    492	for (i = 0; i < ebcnt && bbt[i]; ++i)
    493		addr0 += mtd->erasesize;
    494
    495	/* Attempt to write off end of OOB */
    496	ops.mode      = MTD_OPS_AUTO_OOB;
    497	ops.len       = 0;
    498	ops.retlen    = 0;
    499	ops.ooblen    = 1;
    500	ops.oobretlen = 0;
    501	ops.ooboffs   = mtd->oobavail;
    502	ops.datbuf    = NULL;
    503	ops.oobbuf    = writebuf;
    504	pr_info("attempting to start write past end of OOB\n");
    505	pr_info("an error is expected...\n");
    506	err = mtd_write_oob(mtd, addr0, &ops);
    507	if (err) {
    508		pr_info("error occurred as expected\n");
    509	} else {
    510		pr_err("error: can write past end of OOB\n");
    511		errcnt += 1;
    512	}
    513
    514	/* Attempt to read off end of OOB */
    515	ops.mode      = MTD_OPS_AUTO_OOB;
    516	ops.len       = 0;
    517	ops.retlen    = 0;
    518	ops.ooblen    = 1;
    519	ops.oobretlen = 0;
    520	ops.ooboffs   = mtd->oobavail;
    521	ops.datbuf    = NULL;
    522	ops.oobbuf    = readbuf;
    523	pr_info("attempting to start read past end of OOB\n");
    524	pr_info("an error is expected...\n");
    525	err = mtd_read_oob(mtd, addr0, &ops);
    526	if (mtd_is_bitflip(err))
    527		err = 0;
    528
    529	if (err) {
    530		pr_info("error occurred as expected\n");
    531	} else {
    532		pr_err("error: can read past end of OOB\n");
    533		errcnt += 1;
    534	}
    535
    536	if (bbt[ebcnt - 1])
    537		pr_info("skipping end of device tests because last "
    538		       "block is bad\n");
    539	else {
    540		/* Attempt to write off end of device */
    541		ops.mode      = MTD_OPS_AUTO_OOB;
    542		ops.len       = 0;
    543		ops.retlen    = 0;
    544		ops.ooblen    = mtd->oobavail + 1;
    545		ops.oobretlen = 0;
    546		ops.ooboffs   = 0;
    547		ops.datbuf    = NULL;
    548		ops.oobbuf    = writebuf;
    549		pr_info("attempting to write past end of device\n");
    550		pr_info("an error is expected...\n");
    551		err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
    552		if (err) {
    553			pr_info("error occurred as expected\n");
    554		} else {
    555			pr_err("error: wrote past end of device\n");
    556			errcnt += 1;
    557		}
    558
    559		/* Attempt to read off end of device */
    560		ops.mode      = MTD_OPS_AUTO_OOB;
    561		ops.len       = 0;
    562		ops.retlen    = 0;
    563		ops.ooblen    = mtd->oobavail + 1;
    564		ops.oobretlen = 0;
    565		ops.ooboffs   = 0;
    566		ops.datbuf    = NULL;
    567		ops.oobbuf    = readbuf;
    568		pr_info("attempting to read past end of device\n");
    569		pr_info("an error is expected...\n");
    570		err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
    571		if (mtd_is_bitflip(err))
    572			err = 0;
    573
    574		if (err) {
    575			pr_info("error occurred as expected\n");
    576		} else {
    577			pr_err("error: read past end of device\n");
    578			errcnt += 1;
    579		}
    580
    581		err = mtdtest_erase_eraseblock(mtd, ebcnt - 1);
    582		if (err)
    583			goto out;
    584
    585		/* Attempt to write off end of device */
    586		ops.mode      = MTD_OPS_AUTO_OOB;
    587		ops.len       = 0;
    588		ops.retlen    = 0;
    589		ops.ooblen    = mtd->oobavail;
    590		ops.oobretlen = 0;
    591		ops.ooboffs   = 1;
    592		ops.datbuf    = NULL;
    593		ops.oobbuf    = writebuf;
    594		pr_info("attempting to write past end of device\n");
    595		pr_info("an error is expected...\n");
    596		err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
    597		if (err) {
    598			pr_info("error occurred as expected\n");
    599		} else {
    600			pr_err("error: wrote past end of device\n");
    601			errcnt += 1;
    602		}
    603
    604		/* Attempt to read off end of device */
    605		ops.mode      = MTD_OPS_AUTO_OOB;
    606		ops.len       = 0;
    607		ops.retlen    = 0;
    608		ops.ooblen    = mtd->oobavail;
    609		ops.oobretlen = 0;
    610		ops.ooboffs   = 1;
    611		ops.datbuf    = NULL;
    612		ops.oobbuf    = readbuf;
    613		pr_info("attempting to read past end of device\n");
    614		pr_info("an error is expected...\n");
    615		err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
    616		if (mtd_is_bitflip(err))
    617			err = 0;
    618
    619		if (err) {
    620			pr_info("error occurred as expected\n");
    621		} else {
    622			pr_err("error: read past end of device\n");
    623			errcnt += 1;
    624		}
    625	}
    626
    627	/* Fifth test: write / read across block boundaries */
    628	pr_info("test 5 of 5\n");
    629
    630	/* Erase all eraseblocks */
    631	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
    632	if (err)
    633		goto out;
    634
    635	/* Write all eraseblocks */
    636	prandom_seed_state(&rnd_state, 11);
    637	pr_info("writing OOBs of whole device\n");
    638	for (i = 0; i < ebcnt - 1; ++i) {
    639		int cnt = 2;
    640		int pg;
    641		size_t sz = mtd->oobavail;
    642		if (bbt[i] || bbt[i + 1])
    643			continue;
    644		addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
    645		prandom_bytes_state(&rnd_state, writebuf, sz * cnt);
    646		for (pg = 0; pg < cnt; ++pg) {
    647			ops.mode      = MTD_OPS_AUTO_OOB;
    648			ops.len       = 0;
    649			ops.retlen    = 0;
    650			ops.ooblen    = sz;
    651			ops.oobretlen = 0;
    652			ops.ooboffs   = 0;
    653			ops.datbuf    = NULL;
    654			ops.oobbuf    = writebuf + pg * sz;
    655			err = mtd_write_oob(mtd, addr, &ops);
    656			if (err)
    657				goto out;
    658			if (i % 256 == 0)
    659				pr_info("written up to eraseblock %u\n", i);
    660
    661			err = mtdtest_relax();
    662			if (err)
    663				goto out;
    664
    665			addr += mtd->writesize;
    666		}
    667	}
    668	pr_info("written %u eraseblocks\n", i);
    669
    670	/* Check all eraseblocks */
    671	prandom_seed_state(&rnd_state, 11);
    672	pr_info("verifying all eraseblocks\n");
    673	for (i = 0; i < ebcnt - 1; ++i) {
    674		if (bbt[i] || bbt[i + 1])
    675			continue;
    676		prandom_bytes_state(&rnd_state, writebuf, mtd->oobavail * 2);
    677		addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
    678		ops.mode      = MTD_OPS_AUTO_OOB;
    679		ops.len       = 0;
    680		ops.retlen    = 0;
    681		ops.ooblen    = mtd->oobavail * 2;
    682		ops.oobretlen = 0;
    683		ops.ooboffs   = 0;
    684		ops.datbuf    = NULL;
    685		ops.oobbuf    = readbuf;
    686		err = mtd_read_oob(mtd, addr, &ops);
    687		if (mtd_is_bitflip(err))
    688			err = 0;
    689
    690		if (err)
    691			goto out;
    692		if (memcmpshow(addr, readbuf, writebuf,
    693			       mtd->oobavail * 2)) {
    694			pr_err("error: verify failed at %#llx\n",
    695			       (long long)addr);
    696			errcnt += 1;
    697			if (errcnt > 1000) {
    698				err = -EINVAL;
    699				pr_err("error: too many errors\n");
    700				goto out;
    701			}
    702		}
    703		if (i % 256 == 0)
    704			pr_info("verified up to eraseblock %u\n", i);
    705
    706		err = mtdtest_relax();
    707		if (err)
    708			goto out;
    709	}
    710	pr_info("verified %u eraseblocks\n", i);
    711
    712	pr_info("finished with %d errors\n", errcnt);
    713out:
    714	kfree(bbt);
    715	kfree(writebuf);
    716	kfree(readbuf);
    717	put_mtd_device(mtd);
    718	if (err)
    719		pr_info("error %d occurred\n", err);
    720	printk(KERN_INFO "=================================================\n");
    721	return err;
    722}
    723module_init(mtd_oobtest_init);
    724
    725static void __exit mtd_oobtest_exit(void)
    726{
    727	return;
    728}
    729module_exit(mtd_oobtest_exit);
    730
    731MODULE_DESCRIPTION("Out-of-band test module");
    732MODULE_AUTHOR("Adrian Hunter");
    733MODULE_LICENSE("GPL");