Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.6 347 lines 7.7 kB view raw
1/* 2 * Copyright (C) 2006-2008 Nokia Corporation 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 as published by 6 * the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * this program; see the file COPYING. If not, write to the Free Software 15 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 * 17 * Test random reads, writes and erases on MTD device. 18 * 19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> 20 */ 21 22#include <linux/init.h> 23#include <linux/module.h> 24#include <linux/moduleparam.h> 25#include <linux/err.h> 26#include <linux/mtd/mtd.h> 27#include <linux/slab.h> 28#include <linux/sched.h> 29#include <linux/vmalloc.h> 30 31#define PRINT_PREF KERN_INFO "mtd_stresstest: " 32 33static int dev = -EINVAL; 34module_param(dev, int, S_IRUGO); 35MODULE_PARM_DESC(dev, "MTD device number to use"); 36 37static int count = 10000; 38module_param(count, int, S_IRUGO); 39MODULE_PARM_DESC(count, "Number of operations to do (default is 10000)"); 40 41static struct mtd_info *mtd; 42static unsigned char *writebuf; 43static unsigned char *readbuf; 44static unsigned char *bbt; 45static int *offsets; 46 47static int pgsize; 48static int bufsize; 49static int ebcnt; 50static int pgcnt; 51static unsigned long next = 1; 52 53static inline unsigned int simple_rand(void) 54{ 55 next = next * 1103515245 + 12345; 56 return (unsigned int)((next / 65536) % 32768); 57} 58 59static inline void simple_srand(unsigned long seed) 60{ 61 next = seed; 62} 63 64static int rand_eb(void) 65{ 66 int eb; 67 68again: 69 if (ebcnt < 32768) 70 eb = simple_rand(); 71 else 72 eb = (simple_rand() << 15) | simple_rand(); 73 /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */ 74 eb %= (ebcnt - 1); 75 if (bbt[eb]) 76 goto again; 77 return eb; 78} 79 80static int rand_offs(void) 81{ 82 int offs; 83 84 if (bufsize < 32768) 85 offs = simple_rand(); 86 else 87 offs = (simple_rand() << 15) | simple_rand(); 88 offs %= bufsize; 89 return offs; 90} 91 92static int rand_len(int offs) 93{ 94 int len; 95 96 if (bufsize < 32768) 97 len = simple_rand(); 98 else 99 len = (simple_rand() << 15) | simple_rand(); 100 len %= (bufsize - offs); 101 return len; 102} 103 104static int erase_eraseblock(int ebnum) 105{ 106 int err; 107 struct erase_info ei; 108 loff_t addr = ebnum * mtd->erasesize; 109 110 memset(&ei, 0, sizeof(struct erase_info)); 111 ei.mtd = mtd; 112 ei.addr = addr; 113 ei.len = mtd->erasesize; 114 115 err = mtd_erase(mtd, &ei); 116 if (unlikely(err)) { 117 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); 118 return err; 119 } 120 121 if (unlikely(ei.state == MTD_ERASE_FAILED)) { 122 printk(PRINT_PREF "some erase error occurred at EB %d\n", 123 ebnum); 124 return -EIO; 125 } 126 127 return 0; 128} 129 130static int is_block_bad(int ebnum) 131{ 132 loff_t addr = ebnum * mtd->erasesize; 133 int ret; 134 135 ret = mtd_block_isbad(mtd, addr); 136 if (ret) 137 printk(PRINT_PREF "block %d is bad\n", ebnum); 138 return ret; 139} 140 141static int do_read(void) 142{ 143 size_t read; 144 int eb = rand_eb(); 145 int offs = rand_offs(); 146 int len = rand_len(offs), err; 147 loff_t addr; 148 149 if (bbt[eb + 1]) { 150 if (offs >= mtd->erasesize) 151 offs -= mtd->erasesize; 152 if (offs + len > mtd->erasesize) 153 len = mtd->erasesize - offs; 154 } 155 addr = eb * mtd->erasesize + offs; 156 err = mtd_read(mtd, addr, len, &read, readbuf); 157 if (mtd_is_bitflip(err)) 158 err = 0; 159 if (unlikely(err || read != len)) { 160 printk(PRINT_PREF "error: read failed at 0x%llx\n", 161 (long long)addr); 162 if (!err) 163 err = -EINVAL; 164 return err; 165 } 166 return 0; 167} 168 169static int do_write(void) 170{ 171 int eb = rand_eb(), offs, err, len; 172 size_t written; 173 loff_t addr; 174 175 offs = offsets[eb]; 176 if (offs >= mtd->erasesize) { 177 err = erase_eraseblock(eb); 178 if (err) 179 return err; 180 offs = offsets[eb] = 0; 181 } 182 len = rand_len(offs); 183 len = ((len + pgsize - 1) / pgsize) * pgsize; 184 if (offs + len > mtd->erasesize) { 185 if (bbt[eb + 1]) 186 len = mtd->erasesize - offs; 187 else { 188 err = erase_eraseblock(eb + 1); 189 if (err) 190 return err; 191 offsets[eb + 1] = 0; 192 } 193 } 194 addr = eb * mtd->erasesize + offs; 195 err = mtd_write(mtd, addr, len, &written, writebuf); 196 if (unlikely(err || written != len)) { 197 printk(PRINT_PREF "error: write failed at 0x%llx\n", 198 (long long)addr); 199 if (!err) 200 err = -EINVAL; 201 return err; 202 } 203 offs += len; 204 while (offs > mtd->erasesize) { 205 offsets[eb++] = mtd->erasesize; 206 offs -= mtd->erasesize; 207 } 208 offsets[eb] = offs; 209 return 0; 210} 211 212static int do_operation(void) 213{ 214 if (simple_rand() & 1) 215 return do_read(); 216 else 217 return do_write(); 218} 219 220static int scan_for_bad_eraseblocks(void) 221{ 222 int i, bad = 0; 223 224 bbt = kzalloc(ebcnt, GFP_KERNEL); 225 if (!bbt) { 226 printk(PRINT_PREF "error: cannot allocate memory\n"); 227 return -ENOMEM; 228 } 229 230 if (!mtd_can_have_bb(mtd)) 231 return 0; 232 233 printk(PRINT_PREF "scanning for bad eraseblocks\n"); 234 for (i = 0; i < ebcnt; ++i) { 235 bbt[i] = is_block_bad(i) ? 1 : 0; 236 if (bbt[i]) 237 bad += 1; 238 cond_resched(); 239 } 240 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); 241 return 0; 242} 243 244static int __init mtd_stresstest_init(void) 245{ 246 int err; 247 int i, op; 248 uint64_t tmp; 249 250 printk(KERN_INFO "\n"); 251 printk(KERN_INFO "=================================================\n"); 252 253 if (dev < 0) { 254 printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); 255 printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); 256 return -EINVAL; 257 } 258 259 printk(PRINT_PREF "MTD device: %d\n", dev); 260 261 mtd = get_mtd_device(NULL, dev); 262 if (IS_ERR(mtd)) { 263 err = PTR_ERR(mtd); 264 printk(PRINT_PREF "error: cannot get MTD device\n"); 265 return err; 266 } 267 268 if (mtd->writesize == 1) { 269 printk(PRINT_PREF "not NAND flash, assume page size is 512 " 270 "bytes.\n"); 271 pgsize = 512; 272 } else 273 pgsize = mtd->writesize; 274 275 tmp = mtd->size; 276 do_div(tmp, mtd->erasesize); 277 ebcnt = tmp; 278 pgcnt = mtd->erasesize / pgsize; 279 280 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " 281 "page size %u, count of eraseblocks %u, pages per " 282 "eraseblock %u, OOB size %u\n", 283 (unsigned long long)mtd->size, mtd->erasesize, 284 pgsize, ebcnt, pgcnt, mtd->oobsize); 285 286 if (ebcnt < 2) { 287 printk(PRINT_PREF "error: need at least 2 eraseblocks\n"); 288 err = -ENOSPC; 289 goto out_put_mtd; 290 } 291 292 /* Read or write up 2 eraseblocks at a time */ 293 bufsize = mtd->erasesize * 2; 294 295 err = -ENOMEM; 296 readbuf = vmalloc(bufsize); 297 writebuf = vmalloc(bufsize); 298 offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL); 299 if (!readbuf || !writebuf || !offsets) { 300 printk(PRINT_PREF "error: cannot allocate memory\n"); 301 goto out; 302 } 303 for (i = 0; i < ebcnt; i++) 304 offsets[i] = mtd->erasesize; 305 simple_srand(current->pid); 306 for (i = 0; i < bufsize; i++) 307 writebuf[i] = simple_rand(); 308 309 err = scan_for_bad_eraseblocks(); 310 if (err) 311 goto out; 312 313 /* Do operations */ 314 printk(PRINT_PREF "doing operations\n"); 315 for (op = 0; op < count; op++) { 316 if ((op & 1023) == 0) 317 printk(PRINT_PREF "%d operations done\n", op); 318 err = do_operation(); 319 if (err) 320 goto out; 321 cond_resched(); 322 } 323 printk(PRINT_PREF "finished, %d operations done\n", op); 324 325out: 326 kfree(offsets); 327 kfree(bbt); 328 vfree(writebuf); 329 vfree(readbuf); 330out_put_mtd: 331 put_mtd_device(mtd); 332 if (err) 333 printk(PRINT_PREF "error %d occurred\n", err); 334 printk(KERN_INFO "=================================================\n"); 335 return err; 336} 337module_init(mtd_stresstest_init); 338 339static void __exit mtd_stresstest_exit(void) 340{ 341 return; 342} 343module_exit(mtd_stresstest_exit); 344 345MODULE_DESCRIPTION("Stress test module"); 346MODULE_AUTHOR("Adrian Hunter"); 347MODULE_LICENSE("GPL");