yaffs_fsx.c 22 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  1. /*
  2. * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
  3. *
  4. * @APPLE_LICENSE_HEADER_START@
  5. *
  6. * The contents of this file constitute Original Code as defined in and
  7. * are subject to the Apple Public Source License Version 1.2 (the
  8. * "License"). You may not use this file except in compliance with the
  9. * License. Please obtain a copy of the License at
  10. * http://www.apple.com/publicsource and read it before using this file.
  11. *
  12. * This Original Code and all software distributed under the License are
  13. * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14. * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15. * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
  17. * License for the specific language governing rights and limitations
  18. * under the License.
  19. *
  20. * @APPLE_LICENSE_HEADER_END@
  21. *
  22. * WARNING--WARNING--WARNING
  23. * This is not the original fsx.c. It has been modified to run with
  24. * yaffs direct. Seek out the original fsx.c if you want to do anything
  25. * else.
  26. *
  27. *
  28. *
  29. * File: fsx.c
  30. * Author: Avadis Tevanian, Jr.
  31. *
  32. * File system exerciser.
  33. *
  34. * Rewrite and enhancements 1998-2001 Conrad Minshall -- conrad@mac.com
  35. *
  36. * Various features from Joe Sokol, Pat Dirks, and Clark Warner.
  37. *
  38. * Small changes to work under Linux -- davej@suse.de
  39. *
  40. * Sundry porting patches from Guy Harris 12/2001
  41. *
  42. * Checks for mmap last-page zero fill.
  43. *
  44. * Modified heavily by Charles Manning to exercise via the
  45. * yaffs direct interface.
  46. *
  47. */
  48. #include <sys/types.h>
  49. #include <sys/stat.h>
  50. #ifdef _UWIN
  51. # include <sys/param.h>
  52. # include <limits.h>
  53. # include <time.h>
  54. # include <strings.h>
  55. #endif
  56. #include <fcntl.h>
  57. #include <sys/mman.h>
  58. #ifndef MAP_FILE
  59. # define MAP_FILE 0
  60. #endif
  61. #include <limits.h>
  62. #include <signal.h>
  63. #include <stdio.h>
  64. #include <stdlib.h>
  65. #include <string.h>
  66. #include <unistd.h>
  67. #include <stdarg.h>
  68. #include <errno.h>
  69. #include "yaffsfs.h"
  70. #define NUMPRINTCOLUMNS 32 /* # columns of data to print on each line */
  71. /*
  72. * A log entry is an operation and a bunch of arguments.
  73. */
  74. struct log_entry {
  75. int operation;
  76. int args[3];
  77. };
  78. #define LOGSIZE 1000
  79. struct log_entry oplog[LOGSIZE]; /* the log */
  80. int logptr = 0; /* current position in log */
  81. int logcount = 0; /* total ops */
  82. /*
  83. * Define operations
  84. */
  85. #define OP_READ 1
  86. #define OP_WRITE 2
  87. #define OP_TRUNCATE 3
  88. #define OP_CLOSEOPEN 4
  89. #define OP_MAPREAD 5
  90. #define OP_MAPWRITE 6
  91. #define OP_SKIPPED 7
  92. int page_size;
  93. int page_mask;
  94. char *original_buf; /* a pointer to the original data */
  95. char *good_buf; /* a pointer to the correct data */
  96. char *temp_buf; /* a pointer to the current data */
  97. char *fname; /* name of our test file */
  98. int fd; /* fd for our test file */
  99. off_t file_size = 0;
  100. off_t biggest = 0;
  101. char state[256];
  102. unsigned long testcalls = 0; /* calls to function "test" */
  103. unsigned long simulatedopcount = 0; /* -b flag */
  104. int closeprob = 0; /* -c flag */
  105. int debug = 0; /* -d flag */
  106. unsigned long debugstart = 0; /* -D flag */
  107. unsigned long maxfilelen = 256 * 1024; /* -l flag */
  108. int sizechecks = 1; /* -n flag disables them */
  109. int maxoplen = 64 * 1024; /* -o flag */
  110. int quiet = 0; /* -q flag */
  111. unsigned long progressinterval = 0; /* -p flag */
  112. int readbdy = 1; /* -r flag */
  113. int style = 0; /* -s flag */
  114. int truncbdy = 1; /* -t flag */
  115. int writebdy = 1; /* -w flag */
  116. long monitorstart = -1; /* -m flag */
  117. long monitorend = -1; /* -m flag */
  118. int lite = 0; /* -L flag */
  119. long numops = -1; /* -N flag */
  120. int randomoplen = 1; /* -O flag disables it */
  121. int seed = 1; /* -S flag */
  122. int mapped_writes = 0; /* yaffs direct does not support mmapped files */
  123. int mapped_reads = 0;
  124. int fsxgoodfd = 0;
  125. FILE * fsxlogf = NULL;
  126. int badoff = -1;
  127. int closeopen = 0;
  128. void
  129. vwarnc(code, fmt, ap)
  130. int code;
  131. const char *fmt;
  132. va_list ap;
  133. {
  134. fprintf(stderr, "fsx: ");
  135. if (fmt != NULL) {
  136. vfprintf(stderr, fmt, ap);
  137. fprintf(stderr, ": ");
  138. }
  139. fprintf(stderr, "%s\n", strerror(code));
  140. }
  141. void
  142. warn(const char * fmt, ...)
  143. {
  144. va_list ap;
  145. va_start(ap, fmt);
  146. vwarnc(errno, fmt, ap);
  147. va_end(ap);
  148. }
  149. void
  150. prt(char *fmt, ...)
  151. {
  152. va_list args;
  153. va_start(args, fmt);
  154. vfprintf(stdout, fmt, args);
  155. if (fsxlogf)
  156. vfprintf(fsxlogf, fmt, args);
  157. va_end(args);
  158. }
  159. void
  160. prterr(char *prefix)
  161. {
  162. prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno));
  163. }
  164. void
  165. log4(int operation, int arg0, int arg1, int arg2)
  166. {
  167. struct log_entry *le;
  168. le = &oplog[logptr];
  169. le->operation = operation;
  170. if (closeopen)
  171. le->operation = ~ le->operation;
  172. le->args[0] = arg0;
  173. le->args[1] = arg1;
  174. le->args[2] = arg2;
  175. logptr++;
  176. logcount++;
  177. if (logptr >= LOGSIZE)
  178. logptr = 0;
  179. }
  180. void
  181. logdump(void)
  182. {
  183. int i, count, down;
  184. struct log_entry *lp;
  185. prt("LOG DUMP (%d total operations):\n", logcount);
  186. if (logcount < LOGSIZE) {
  187. i = 0;
  188. count = logcount;
  189. } else {
  190. i = logptr;
  191. count = LOGSIZE;
  192. }
  193. for ( ; count > 0; count--) {
  194. int opnum;
  195. opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
  196. prt("%d(%d mod 256): ", opnum, opnum%256);
  197. lp = &oplog[i];
  198. if ((closeopen = lp->operation < 0))
  199. lp->operation = ~ lp->operation;
  200. switch (lp->operation) {
  201. case OP_MAPREAD:
  202. prt("MAPREAD\t0x%x thru 0x%x\t(0x%x bytes)",
  203. lp->args[0], lp->args[0] + lp->args[1] - 1,
  204. lp->args[1]);
  205. if (badoff >= lp->args[0] && badoff <
  206. lp->args[0] + lp->args[1])
  207. prt("\t***RRRR***");
  208. break;
  209. case OP_MAPWRITE:
  210. prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)",
  211. lp->args[0], lp->args[0] + lp->args[1] - 1,
  212. lp->args[1]);
  213. if (badoff >= lp->args[0] && badoff <
  214. lp->args[0] + lp->args[1])
  215. prt("\t******WWWW");
  216. break;
  217. case OP_READ:
  218. prt("READ\t0x%x thru 0x%x\t(0x%x bytes)",
  219. lp->args[0], lp->args[0] + lp->args[1] - 1,
  220. lp->args[1]);
  221. if (badoff >= lp->args[0] &&
  222. badoff < lp->args[0] + lp->args[1])
  223. prt("\t***RRRR***");
  224. break;
  225. case OP_WRITE:
  226. prt("WRITE\t0x%x thru 0x%x\t(0x%x bytes)",
  227. lp->args[0], lp->args[0] + lp->args[1] - 1,
  228. lp->args[1]);
  229. if (lp->args[0] > lp->args[2])
  230. prt(" HOLE");
  231. else if (lp->args[0] + lp->args[1] > lp->args[2])
  232. prt(" EXTEND");
  233. if ((badoff >= lp->args[0] || badoff >=lp->args[2]) &&
  234. badoff < lp->args[0] + lp->args[1])
  235. prt("\t***WWWW");
  236. break;
  237. case OP_TRUNCATE:
  238. down = lp->args[0] < lp->args[1];
  239. prt("TRUNCATE %s\tfrom 0x%x to 0x%x",
  240. down ? "DOWN" : "UP", lp->args[1], lp->args[0]);
  241. if (badoff >= lp->args[!down] &&
  242. badoff < lp->args[!!down])
  243. prt("\t******WWWW");
  244. break;
  245. case OP_SKIPPED:
  246. prt("SKIPPED (no operation)");
  247. break;
  248. default:
  249. prt("BOGUS LOG ENTRY (operation code = %d)!",
  250. lp->operation);
  251. }
  252. if (closeopen)
  253. prt("\n\t\tCLOSE/OPEN");
  254. prt("\n");
  255. i++;
  256. if (i == LOGSIZE)
  257. i = 0;
  258. }
  259. }
  260. void
  261. save_buffer(char *buffer, off_t bufferlength, int fd)
  262. {
  263. off_t ret;
  264. ssize_t byteswritten;
  265. if (fd <= 0 || bufferlength == 0)
  266. return;
  267. if (bufferlength > SSIZE_MAX) {
  268. prt("fsx flaw: overflow in save_buffer\n");
  269. exit(67);
  270. }
  271. if (lite) {
  272. off_t size_by_seek = yaffs_lseek(fd, (off_t)0, SEEK_END);
  273. if (size_by_seek == (off_t)-1)
  274. prterr("save_buffer: lseek eof");
  275. else if (bufferlength > size_by_seek) {
  276. warn("save_buffer: .fsxgood file too short... will save 0x%llx bytes instead of 0x%llx\n", (unsigned long long)size_by_seek,
  277. (unsigned long long)bufferlength);
  278. bufferlength = size_by_seek;
  279. }
  280. }
  281. ret = yaffs_lseek(fd, (off_t)0, SEEK_SET);
  282. if (ret == (off_t)-1)
  283. prterr("save_buffer: lseek 0");
  284. byteswritten = yaffs_write(fd, buffer, (size_t)bufferlength);
  285. if (byteswritten != bufferlength) {
  286. if (byteswritten == -1)
  287. prterr("save_buffer write");
  288. else
  289. warn("save_buffer: short write, 0x%x bytes instead of 0x%llx\n",
  290. (unsigned)byteswritten,
  291. (unsigned long long)bufferlength);
  292. }
  293. }
  294. void
  295. report_failure(int status)
  296. {
  297. logdump();
  298. if (fsxgoodfd) {
  299. if (good_buf) {
  300. save_buffer(good_buf, file_size, fsxgoodfd);
  301. prt("Correct content saved for comparison\n");
  302. prt("(maybe hexdump \"%s\" vs \"%s.fsxgood\")\n",
  303. fname, fname);
  304. }
  305. close(fsxgoodfd);
  306. }
  307. prt("Exiting with %d\n",status);
  308. exit(status);
  309. }
  310. #define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \
  311. *(((unsigned char *)(cp)) + 1)))
  312. void
  313. check_buffers(unsigned offset, unsigned size)
  314. {
  315. unsigned char c, t;
  316. unsigned i = 0;
  317. unsigned n = 0;
  318. unsigned op = 0;
  319. unsigned bad = 0;
  320. if (memcmp(good_buf + offset, temp_buf, size) != 0) {
  321. prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n",
  322. offset, size);
  323. prt("OFFSET\tGOOD\tBAD\tRANGE\n");
  324. while (size > 0) {
  325. c = good_buf[offset];
  326. t = temp_buf[i];
  327. if (c != t) {
  328. if (n == 0) {
  329. bad = short_at(&temp_buf[i]);
  330. prt("0x%5x\t0x%04x\t0x%04x", offset,
  331. short_at(&good_buf[offset]), bad);
  332. op = temp_buf[offset & 1 ? i+1 : i];
  333. }
  334. n++;
  335. badoff = offset;
  336. }
  337. offset++;
  338. i++;
  339. size--;
  340. }
  341. if (n) {
  342. prt("\t0x%5x\n", n);
  343. if (bad)
  344. prt("operation# (mod 256) for the bad data may be %u\n", ((unsigned)op & 0xff));
  345. else
  346. prt("operation# (mod 256) for the bad data unknown, check HOLE and EXTEND ops\n");
  347. } else
  348. prt("????????????????\n");
  349. report_failure(110);
  350. }
  351. }
  352. void
  353. check_size(void)
  354. {
  355. struct yaffs_stat statbuf;
  356. off_t size_by_seek;
  357. if (yaffs_fstat(fd, &statbuf)) {
  358. prterr("check_size: fstat");
  359. statbuf.st_size = -1;
  360. }
  361. size_by_seek = yaffs_lseek(fd, (off_t)0, SEEK_END);
  362. if (file_size != statbuf.st_size || file_size != size_by_seek) {
  363. prt("Size error: expected 0x%llx stat 0x%llx seek 0x%llx\n",
  364. (unsigned long long)file_size,
  365. (unsigned long long)statbuf.st_size,
  366. (unsigned long long)size_by_seek);
  367. report_failure(120);
  368. }
  369. }
  370. void
  371. check_trunc_hack(void)
  372. {
  373. struct yaffs_stat statbuf;
  374. yaffs_truncate(fd, (off_t)0);
  375. yaffs_truncate(fd, (off_t)100000);
  376. yaffs_fstat(fd, &statbuf);
  377. if (statbuf.st_size != (off_t)100000) {
  378. prt("no extend on truncate! not posix!\n");
  379. exit(130);
  380. }
  381. yaffs_truncate(fd, (off_t)0);
  382. }
  383. void
  384. doread(unsigned offset, unsigned size)
  385. {
  386. off_t ret;
  387. unsigned iret;
  388. offset -= offset % readbdy;
  389. if (size == 0) {
  390. if (!quiet && testcalls > simulatedopcount)
  391. prt("skipping zero size read\n");
  392. log4(OP_SKIPPED, OP_READ, offset, size);
  393. return;
  394. }
  395. if (size + offset > file_size) {
  396. if (!quiet && testcalls > simulatedopcount)
  397. prt("skipping seek/read past end of file\n");
  398. log4(OP_SKIPPED, OP_READ, offset, size);
  399. return;
  400. }
  401. log4(OP_READ, offset, size, 0);
  402. if (testcalls <= simulatedopcount)
  403. return;
  404. if (!quiet && ((progressinterval &&
  405. testcalls % progressinterval == 0) ||
  406. (debug &&
  407. (monitorstart == -1 ||
  408. (offset + size > monitorstart &&
  409. (monitorend == -1 || offset <= monitorend))))))
  410. prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
  411. offset, offset + size - 1, size);
  412. ret = yaffs_lseek(fd, (off_t)offset, SEEK_SET);
  413. if (ret == (off_t)-1) {
  414. prterr("doread: lseek");
  415. report_failure(140);
  416. }
  417. iret = yaffs_read(fd, temp_buf, size);
  418. if (iret != size) {
  419. if (iret == -1)
  420. prterr("doread: read");
  421. else
  422. prt("short read: 0x%x bytes instead of 0x%x\n",
  423. iret, size);
  424. report_failure(141);
  425. }
  426. check_buffers(offset, size);
  427. }
  428. void
  429. gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size)
  430. {
  431. while (size--) {
  432. good_buf[offset] = testcalls % 256;
  433. if (offset % 2)
  434. good_buf[offset] += original_buf[offset];
  435. offset++;
  436. }
  437. }
  438. void
  439. dowrite(unsigned offset, unsigned size)
  440. {
  441. off_t ret;
  442. unsigned iret;
  443. offset -= offset % writebdy;
  444. if (size == 0) {
  445. if (!quiet && testcalls > simulatedopcount)
  446. prt("skipping zero size write\n");
  447. log4(OP_SKIPPED, OP_WRITE, offset, size);
  448. return;
  449. }
  450. log4(OP_WRITE, offset, size, file_size);
  451. gendata(original_buf, good_buf, offset, size);
  452. if (file_size < offset + size) {
  453. if (file_size < offset)
  454. memset(good_buf + file_size, '\0', offset - file_size);
  455. file_size = offset + size;
  456. if (lite) {
  457. warn("Lite file size bug in fsx!");
  458. report_failure(149);
  459. }
  460. }
  461. if (testcalls <= simulatedopcount)
  462. return;
  463. if (!quiet && ((progressinterval &&
  464. testcalls % progressinterval == 0) ||
  465. (debug &&
  466. (monitorstart == -1 ||
  467. (offset + size > monitorstart &&
  468. (monitorend == -1 || offset <= monitorend))))))
  469. prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
  470. offset, offset + size - 1, size);
  471. ret = yaffs_lseek(fd, (off_t)offset, SEEK_SET);
  472. if (ret == (off_t)-1) {
  473. prterr("dowrite: lseek");
  474. report_failure(150);
  475. }
  476. iret = yaffs_write(fd, good_buf + offset, size);
  477. if (iret != size) {
  478. if (iret == -1)
  479. prterr("dowrite: write");
  480. else
  481. prt("short write: 0x%x bytes instead of 0x%x\n",
  482. iret, size);
  483. report_failure(151);
  484. }
  485. }
  486. void
  487. dotruncate(unsigned size)
  488. {
  489. int oldsize = file_size;
  490. size -= size % truncbdy;
  491. if (size > biggest) {
  492. biggest = size;
  493. if (!quiet && testcalls > simulatedopcount)
  494. prt("truncating to largest ever: 0x%x\n", size);
  495. }
  496. log4(OP_TRUNCATE, size, (unsigned)file_size, 0);
  497. if (size > file_size)
  498. memset(good_buf + file_size, '\0', size - file_size);
  499. file_size = size;
  500. if (testcalls <= simulatedopcount)
  501. return;
  502. if ((progressinterval && testcalls % progressinterval == 0) ||
  503. (debug && (monitorstart == -1 || monitorend == -1 ||
  504. size <= monitorend)))
  505. prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size);
  506. if (yaffs_truncate(fd, (off_t)size) == -1) {
  507. prt("ftruncate1: %x\n", size);
  508. prterr("dotruncate: ftruncate");
  509. report_failure(160);
  510. }
  511. }
  512. void
  513. writefileimage()
  514. {
  515. ssize_t iret;
  516. if (yaffs_lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
  517. prterr("writefileimage: lseek");
  518. report_failure(171);
  519. }
  520. iret = yaffs_write(fd, good_buf, file_size);
  521. if ((off_t)iret != file_size) {
  522. if (iret == -1)
  523. prterr("writefileimage: write");
  524. else
  525. prt("short write: 0x%x bytes instead of 0x%llx\n",
  526. iret, (unsigned long long)file_size);
  527. report_failure(172);
  528. }
  529. if (lite ? 0 : yaffs_truncate(fd, file_size) == -1) {
  530. prt("ftruncate2: %llx\n", (unsigned long long)file_size);
  531. prterr("writefileimage: ftruncate");
  532. report_failure(173);
  533. }
  534. }
  535. void
  536. docloseopen(void)
  537. {
  538. if (testcalls <= simulatedopcount)
  539. return;
  540. if (debug)
  541. prt("%lu close/open\n", testcalls);
  542. if (yaffs_close(fd)) {
  543. prterr("docloseopen: close");
  544. report_failure(180);
  545. }
  546. fd = yaffs_open(fname, O_RDWR, 0);
  547. if (fd < 0) {
  548. prterr("docloseopen: open");
  549. report_failure(181);
  550. }
  551. }
  552. void
  553. test(void)
  554. {
  555. unsigned long offset;
  556. unsigned long size = maxoplen;
  557. unsigned long rv = random();
  558. unsigned long op = rv % (3 + !lite + mapped_writes);
  559. /* turn off the map read if necessary */
  560. if (op == 2 && !mapped_reads)
  561. op = 0;
  562. if (simulatedopcount > 0 && testcalls == simulatedopcount)
  563. writefileimage();
  564. testcalls++;
  565. if (closeprob)
  566. closeopen = (rv >> 3) < (1 << 28) / closeprob;
  567. if (debugstart > 0 && testcalls >= debugstart)
  568. debug = 1;
  569. if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0)
  570. prt("%lu...\n", testcalls);
  571. /*
  572. * READ: op = 0
  573. * WRITE: op = 1
  574. * MAPREAD: op = 2
  575. * TRUNCATE: op = 3
  576. * MAPWRITE: op = 3 or 4
  577. */
  578. if (lite ? 0 : op == 3 && (style & 1) == 0) /* vanilla truncate? */
  579. dotruncate(random() % maxfilelen);
  580. else {
  581. if (randomoplen)
  582. size = random() % (maxoplen+1);
  583. if (lite ? 0 : op == 3)
  584. dotruncate(size);
  585. else {
  586. offset = random();
  587. if (op == 1 || op == (lite ? 3 : 4)) {
  588. offset %= maxfilelen;
  589. if (offset + size > maxfilelen)
  590. size = maxfilelen - offset;
  591. dowrite(offset, size);
  592. } else {
  593. if (file_size)
  594. offset %= file_size;
  595. else
  596. offset = 0;
  597. if (offset + size > file_size)
  598. size = file_size - offset;
  599. doread(offset, size);
  600. }
  601. }
  602. }
  603. if (sizechecks && testcalls > simulatedopcount)
  604. check_size();
  605. if (closeopen)
  606. docloseopen();
  607. }
  608. void
  609. cleanup(sig)
  610. int sig;
  611. {
  612. if (sig)
  613. prt("signal %d\n", sig);
  614. prt("testcalls = %lu\n", testcalls);
  615. exit(sig);
  616. }
  617. void
  618. usage(void)
  619. {
  620. fprintf(stdout, "usage: %s",
  621. "fsx [-dnqLOW] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] fname\n\
  622. -b opnum: beginning operation number (default 1)\n\
  623. -c P: 1 in P chance of file close+open at each op (default infinity)\n\
  624. -d: debug output for all operations\n\
  625. -l flen: the upper bound on file size (default 262144)\n\
  626. -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\
  627. -n: no verifications of file size\n\
  628. -o oplen: the upper bound on operation size (default 65536)\n\
  629. -p progressinterval: debug output at specified operation interval\n\
  630. -q: quieter operation\n\
  631. -r readbdy: 4096 would make reads page aligned (default 1)\n\
  632. -s style: 1 gives smaller truncates (default 0)\n\
  633. -t truncbdy: 4096 would make truncates page aligned (default 1)\n\
  634. -w writebdy: 4096 would make writes page aligned (default 1)\n\
  635. -D startingop: debug output starting at specified operation\n\
  636. -L: fsxLite - no file creations & no file size changes\n\
  637. -N numops: total # operations to do (default infinity)\n\
  638. -O: use oplen (see -o flag) for every op (default random)\n\
  639. -P dirpath: save .fsxlog and .fsxgood files in dirpath (default ./)\n\
  640. -S seed: for random # generator (default 1) 0 gets timestamp\n\
  641. fname: this filename is REQUIRED (no default)\n");
  642. exit(90);
  643. }
  644. int
  645. getnum(char *s, char **e)
  646. {
  647. int ret = -1;
  648. *e = (char *) 0;
  649. ret = strtol(s, e, 0);
  650. if (*e)
  651. switch (**e) {
  652. case 'b':
  653. case 'B':
  654. ret *= 512;
  655. *e = *e + 1;
  656. break;
  657. case 'k':
  658. case 'K':
  659. ret *= 1024;
  660. *e = *e + 1;
  661. break;
  662. case 'm':
  663. case 'M':
  664. ret *= 1024*1024;
  665. *e = *e + 1;
  666. break;
  667. case 'w':
  668. case 'W':
  669. ret *= 4;
  670. *e = *e + 1;
  671. break;
  672. }
  673. return (ret);
  674. }
  675. int
  676. main(int argc, char **argv)
  677. {
  678. int i, style, ch;
  679. char *endp;
  680. char goodfile[1024];
  681. char logfile[1024];
  682. goodfile[0] = 0;
  683. logfile[0] = 0;
  684. page_size = getpagesize();
  685. page_mask = page_size - 1;
  686. setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
  687. while ((ch = getopt(argc, argv, "b:c:dl:m:no:p:qr:s:t:w:D:LN:OP:RS:W"))
  688. != EOF)
  689. switch (ch) {
  690. case 'b':
  691. simulatedopcount = getnum(optarg, &endp);
  692. if (!quiet)
  693. fprintf(stdout, "Will begin at operation %ld\n",
  694. simulatedopcount);
  695. if (simulatedopcount == 0)
  696. usage();
  697. simulatedopcount -= 1;
  698. break;
  699. case 'c':
  700. closeprob = getnum(optarg, &endp);
  701. if (!quiet)
  702. fprintf(stdout,
  703. "Chance of close/open is 1 in %d\n",
  704. closeprob);
  705. if (closeprob <= 0)
  706. usage();
  707. break;
  708. case 'd':
  709. debug = 1;
  710. break;
  711. case 'l':
  712. maxfilelen = getnum(optarg, &endp);
  713. if (maxfilelen <= 0)
  714. usage();
  715. break;
  716. case 'm':
  717. monitorstart = getnum(optarg, &endp);
  718. if (monitorstart < 0)
  719. usage();
  720. if (!endp || *endp++ != ':')
  721. usage();
  722. monitorend = getnum(endp, &endp);
  723. if (monitorend < 0)
  724. usage();
  725. if (monitorend == 0)
  726. monitorend = -1; /* aka infinity */
  727. debug = 1;
  728. case 'n':
  729. sizechecks = 0;
  730. break;
  731. case 'o':
  732. maxoplen = getnum(optarg, &endp);
  733. if (maxoplen <= 0)
  734. usage();
  735. break;
  736. case 'p':
  737. progressinterval = getnum(optarg, &endp);
  738. if (progressinterval < 0)
  739. usage();
  740. break;
  741. case 'q':
  742. quiet = 1;
  743. break;
  744. case 'r':
  745. readbdy = getnum(optarg, &endp);
  746. if (readbdy <= 0)
  747. usage();
  748. break;
  749. case 's':
  750. style = getnum(optarg, &endp);
  751. if (style < 0 || style > 1)
  752. usage();
  753. break;
  754. case 't':
  755. truncbdy = getnum(optarg, &endp);
  756. if (truncbdy <= 0)
  757. usage();
  758. break;
  759. case 'w':
  760. writebdy = getnum(optarg, &endp);
  761. if (writebdy <= 0)
  762. usage();
  763. break;
  764. case 'D':
  765. debugstart = getnum(optarg, &endp);
  766. if (debugstart < 1)
  767. usage();
  768. break;
  769. case 'L':
  770. lite = 1;
  771. break;
  772. case 'N':
  773. numops = getnum(optarg, &endp);
  774. if (numops < 0)
  775. usage();
  776. break;
  777. case 'O':
  778. randomoplen = 0;
  779. break;
  780. case 'P':
  781. strncpy(goodfile, optarg, sizeof(goodfile));
  782. strcat(goodfile, "/");
  783. strncpy(logfile, optarg, sizeof(logfile));
  784. strcat(logfile, "/");
  785. break;
  786. case 'R':
  787. mapped_reads = 0;
  788. break;
  789. case 'S':
  790. seed = getnum(optarg, &endp);
  791. if (seed == 0)
  792. seed = time(0) % 10000;
  793. if (!quiet)
  794. fprintf(stdout, "Seed set to %d\n", seed);
  795. if (seed < 0)
  796. usage();
  797. break;
  798. case 'W':
  799. mapped_writes = 0;
  800. if (!quiet)
  801. fprintf(stdout, "mapped writes DISABLED\n");
  802. break;
  803. default:
  804. usage();
  805. /* NOTREACHED */
  806. }
  807. argc -= optind;
  808. argv += optind;
  809. yaffs_StartUp();
  810. yaffs_mount("/flash/flash");
  811. fname = "/flash/flash/fsxdata";
  812. signal(SIGHUP, cleanup);
  813. signal(SIGINT, cleanup);
  814. signal(SIGPIPE, cleanup);
  815. signal(SIGALRM, cleanup);
  816. signal(SIGTERM, cleanup);
  817. signal(SIGXCPU, cleanup);
  818. signal(SIGXFSZ, cleanup);
  819. signal(SIGVTALRM, cleanup);
  820. signal(SIGUSR1, cleanup);
  821. signal(SIGUSR2, cleanup);
  822. initstate(seed, state, 256);
  823. setstate(state);
  824. fd = yaffs_open(fname, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC), 0666);
  825. if (fd < 0) {
  826. prterr(fname);
  827. exit(91);
  828. }
  829. strncat(goodfile, fname, 256);
  830. strcat (goodfile, ".fsxgood");
  831. fsxgoodfd = yaffs_open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666);
  832. if (fsxgoodfd < 0) {
  833. prterr(goodfile);
  834. exit(92);
  835. }
  836. strncat(logfile, "fsx", 256);
  837. strcat (logfile, ".fsxlog");
  838. fsxlogf = fopen(logfile, "w");
  839. if (fsxlogf == NULL) {
  840. prterr(logfile);
  841. exit(93);
  842. }
  843. if (lite) {
  844. off_t ret;
  845. file_size = maxfilelen = yaffs_lseek(fd, (off_t)0, SEEK_END);
  846. if (file_size == (off_t)-1) {
  847. prterr(fname);
  848. warn("main: lseek eof");
  849. exit(94);
  850. }
  851. ret = yaffs_lseek(fd, (off_t)0, SEEK_SET);
  852. if (ret == (off_t)-1) {
  853. prterr(fname);
  854. warn("main: lseek 0");
  855. exit(95);
  856. }
  857. }
  858. original_buf = (char *) malloc(maxfilelen);
  859. for (i = 0; i < maxfilelen; i++)
  860. original_buf[i] = random() % 256;
  861. good_buf = (char *) malloc(maxfilelen);
  862. memset(good_buf, '\0', maxfilelen);
  863. temp_buf = (char *) malloc(maxoplen);
  864. memset(temp_buf, '\0', maxoplen);
  865. if (lite) { /* zero entire existing file */
  866. ssize_t written;
  867. written = yaffs_write(fd, good_buf, (size_t)maxfilelen);
  868. if (written != maxfilelen) {
  869. if (written == -1) {
  870. prterr(fname);
  871. warn("main: error on write");
  872. } else
  873. warn("main: short write, 0x%x bytes instead of 0x%x\n",
  874. (unsigned)written, maxfilelen);
  875. exit(98);
  876. }
  877. } else
  878. check_trunc_hack();
  879. while (numops == -1 || numops--)
  880. test();
  881. if (yaffs_close(fd)) {
  882. prterr("close");
  883. report_failure(99);
  884. }
  885. yaffs_close(fsxgoodfd);
  886. yaffs_unmount("flash/flash");
  887. prt("All operations completed A-OK!\n");
  888. exit(0);
  889. return 0;
  890. }