stresstest.c 4.9 KB

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