io_paral.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. * Copyright (c) International Business Machines Corp., 2006
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  12. * the GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. *
  18. * Author: Artem B. Bityutskiy
  19. *
  20. * This test does a lot of I/O to volumes in parallel.
  21. */
  22. #include <stdio.h>
  23. #include <errno.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <stdint.h>
  27. #include <unistd.h>
  28. #include <pthread.h>
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31. #include <fcntl.h>
  32. #include "libubi.h"
  33. #define PROGRAM_NAME "io_paral"
  34. #include "common.h"
  35. #include "helpers.h"
  36. #define THREADS_NUM 4
  37. #define ITERATIONS (1024 * 1)
  38. #define VOL_LEBS 10
  39. static libubi_t libubi;
  40. static struct ubi_dev_info dev_info;
  41. static const char *node;
  42. static int vol_size;
  43. static struct ubi_mkvol_request reqests[THREADS_NUM + 1];
  44. static char vol_name[THREADS_NUM + 1][100];
  45. static char vol_nodes[THREADS_NUM + 1][sizeof(UBI_VOLUME_PATTERN) + 99];
  46. static unsigned char *wbufs[THREADS_NUM + 1];
  47. static unsigned char *rbufs[THREADS_NUM + 1];
  48. static int update_volume(int vol_id, int bytes)
  49. {
  50. int i, fd, ret, written = 0, rd = 0;
  51. char *vol_node = vol_nodes[vol_id];
  52. unsigned char *wbuf = wbufs[vol_id];
  53. unsigned char *rbuf = rbufs[vol_id];
  54. unsigned int seed = seed_random_generator();
  55. fd = open(vol_node, O_RDWR);
  56. if (fd == -1) {
  57. failed("open");
  58. errorm("cannot open \"%s\"\n", vol_node);
  59. return -1;
  60. }
  61. for (i = 0; i < bytes; i++)
  62. wbuf[i] = rand_r(&seed) % 255;
  63. memset(rbuf, '\0', bytes);
  64. ret = ubi_update_start(libubi, fd, bytes);
  65. if (ret) {
  66. failed("ubi_update_start");
  67. errorm("volume id is %d", vol_id);
  68. goto err_close;
  69. }
  70. while (written < bytes) {
  71. int to_write = rand_r(&seed) % (bytes - written);
  72. if (to_write == 0)
  73. to_write = 1;
  74. ret = write(fd, wbuf + written, to_write);
  75. if (ret != to_write) {
  76. failed("write");
  77. errorm("failed to write %d bytes at offset %d "
  78. "of volume %d", to_write, written,
  79. vol_id);
  80. errorm("update: %d bytes", bytes);
  81. goto err_close;
  82. }
  83. written += to_write;
  84. }
  85. close(fd);
  86. fd = open(vol_node, O_RDONLY);
  87. if (fd == -1) {
  88. failed("open");
  89. errorm("cannot open \"%s\"\n", node);
  90. return -1;
  91. }
  92. /* read data back and check */
  93. while (rd < bytes) {
  94. int to_read = rand_r(&seed) % (bytes - rd);
  95. if (to_read == 0)
  96. to_read = 1;
  97. ret = read(fd, rbuf + rd, to_read);
  98. if (ret != to_read) {
  99. failed("read");
  100. errorm("failed to read %d bytes at offset %d "
  101. "of volume %d", to_read, rd, vol_id);
  102. goto err_close;
  103. }
  104. rd += to_read;
  105. }
  106. if (memcmp(wbuf, rbuf, bytes)) {
  107. errorm("written and read data are different");
  108. goto err_close;
  109. }
  110. close(fd);
  111. return 0;
  112. err_close:
  113. close(fd);
  114. return -1;
  115. }
  116. static void *update_thread(void *ptr)
  117. {
  118. int vol_id = (long)ptr, i;
  119. unsigned int seed = seed_random_generator();
  120. for (i = 0; i < ITERATIONS; i++) {
  121. int ret, bytes = (rand_r(&seed) % (vol_size - 1)) + 1;
  122. int remove = !(rand_r(&seed) % 16);
  123. /* From time to time remove the volume */
  124. if (remove) {
  125. ret = ubi_rmvol(libubi, node, vol_id);
  126. if (ret) {
  127. failed("ubi_rmvol");
  128. errorm("cannot remove volume %d", vol_id);
  129. return (void *) -1;
  130. }
  131. ret = ubi_mkvol(libubi, node, &reqests[vol_id]);
  132. if (ret) {
  133. failed("ubi_mkvol");
  134. errorm("cannot create volume %d", vol_id);
  135. return (void *) -1;
  136. }
  137. }
  138. ret = update_volume(vol_id, bytes);
  139. if (ret != 0)
  140. return (void *) -1;
  141. }
  142. return (void *) 0;
  143. }
  144. static void *write_thread(void *ptr)
  145. {
  146. int ret, fd, vol_id = (long)ptr, i;
  147. char *vol_node = vol_nodes[vol_id];
  148. unsigned char *wbuf = wbufs[vol_id];
  149. unsigned char *rbuf = rbufs[vol_id];
  150. unsigned int seed = seed_random_generator();
  151. fd = open(vol_node, O_RDWR);
  152. if (fd == -1) {
  153. failed("open");
  154. errorm("cannot open \"%s\"\n", vol_node);
  155. return (void *) -1;
  156. }
  157. ret = ubi_set_property(fd, UBI_VOL_PROP_DIRECT_WRITE, 1);
  158. if (ret) {
  159. failed("ubi_set_property");
  160. errorm("cannot set property for \"%s\"\n", vol_node);
  161. }
  162. for (i = 0; i < ITERATIONS * VOL_LEBS; i++) {
  163. int j, leb = rand_r(&seed) % VOL_LEBS;
  164. off_t offs = dev_info.leb_size * leb;
  165. ret = ubi_leb_unmap(fd, leb);
  166. if (ret) {
  167. failed("ubi_leb_unmap");
  168. errorm("cannot unmap LEB %d", leb);
  169. break;
  170. }
  171. for (j = 0; j < dev_info.leb_size; j++)
  172. wbuf[j] = rand_r(&seed) % 255;
  173. memset(rbuf, '\0', dev_info.leb_size);
  174. ret = pwrite(fd, wbuf, dev_info.leb_size, offs);
  175. if (ret != dev_info.leb_size) {
  176. failed("pwrite");
  177. errorm("cannot write %d bytes to offs %ld, wrote %d",
  178. dev_info.leb_size, offs, ret);
  179. break;
  180. }
  181. /* read data back and check */
  182. ret = pread(fd, rbuf, dev_info.leb_size, offs);
  183. if (ret != dev_info.leb_size) {
  184. failed("read");
  185. errorm("failed to read %d bytes at offset %ld "
  186. "of volume %d", dev_info.leb_size, offs,
  187. vol_id);
  188. break;
  189. }
  190. if (memcmp(wbuf, rbuf, dev_info.leb_size)) {
  191. errorm("written and read data are different");
  192. break;
  193. }
  194. }
  195. close(fd);
  196. return (void *) 0;
  197. }
  198. int main(int argc, char * const argv[])
  199. {
  200. int i, ret, error=false;
  201. intptr_t thread_ret;
  202. pthread_t threads[THREADS_NUM];
  203. if (initial_check(argc, argv))
  204. return 1;
  205. node = argv[1];
  206. libubi = libubi_open();
  207. if (libubi == NULL) {
  208. failed("libubi_open");
  209. return 1;
  210. }
  211. if (ubi_get_dev_info(libubi, node, &dev_info)) {
  212. failed("ubi_get_dev_info");
  213. goto close;
  214. }
  215. /*
  216. * Create 1 volume more than threads count. The last volume
  217. * will not change to let WL move more stuff.
  218. */
  219. vol_size = dev_info.leb_size * VOL_LEBS;
  220. for (i = 0; i <= THREADS_NUM; i++) {
  221. reqests[i].alignment = 1;
  222. reqests[i].bytes = vol_size;
  223. reqests[i].vol_id = i;
  224. sprintf(vol_name[i], PROGRAM_NAME":%d", i);
  225. reqests[i].name = vol_name[i];
  226. reqests[i].vol_type = UBI_DYNAMIC_VOLUME;
  227. reqests[i].flags = 0;
  228. if (i == THREADS_NUM)
  229. reqests[i].vol_type = UBI_STATIC_VOLUME;
  230. sprintf(vol_nodes[i], UBI_VOLUME_PATTERN, dev_info.dev_num, i);
  231. if (ubi_mkvol(libubi, node, &reqests[i])) {
  232. failed("ubi_mkvol");
  233. goto remove;
  234. }
  235. wbufs[i] = malloc(vol_size);
  236. rbufs[i] = malloc(vol_size);
  237. if (!wbufs[i] || !rbufs[i]) {
  238. failed("malloc");
  239. goto remove;
  240. }
  241. ret = update_volume(i, vol_size);
  242. if (ret)
  243. goto remove;
  244. }
  245. for (i = 0; i < THREADS_NUM / 2; i++) {
  246. ret = pthread_create(&threads[i], NULL, &write_thread, (void *)(long)i);
  247. if (ret) {
  248. failed("pthread_create");
  249. goto remove;
  250. }
  251. }
  252. for (i = THREADS_NUM / 2; i < THREADS_NUM; i++) {
  253. ret = pthread_create(&threads[i], NULL, &update_thread, (void *)(long)i);
  254. if (ret) {
  255. failed("pthread_create");
  256. goto remove;
  257. }
  258. }
  259. for (i = 0; i < THREADS_NUM; i++) {
  260. pthread_join(threads[i], (void **) &thread_ret);
  261. if (thread_ret != 0)
  262. error = true;
  263. }
  264. if (error)
  265. goto remove;
  266. for (i = 0; i <= THREADS_NUM; i++) {
  267. if (ubi_rmvol(libubi, node, i)) {
  268. failed("ubi_rmvol");
  269. goto remove;
  270. }
  271. if (wbufs[i])
  272. free(wbufs[i]);
  273. if (rbufs[i])
  274. free(rbufs[i]);
  275. wbufs[i] = NULL;
  276. rbufs[i] = NULL;
  277. }
  278. libubi_close(libubi);
  279. return 0;
  280. remove:
  281. for (i = 0; i <= THREADS_NUM; i++) {
  282. ubi_rmvol(libubi, node, i);
  283. if (wbufs[i])
  284. free(wbufs[i]);
  285. if (rbufs[i])
  286. free(rbufs[i]);
  287. wbufs[i] = NULL;
  288. rbufs[i] = NULL;
  289. }
  290. close:
  291. libubi_close(libubi);
  292. return 1;
  293. }