93a9a8e33bfe5ef98850c2cc9cd6af683202db7f
[yaffs2.git] / direct / test-framework / tests / nor_stress.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2011 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  *
13  */
14
15 #include "nor_stress.h"
16
17
18 #include "yaffsfs.h"
19 #include "yaffs_fsx.h"
20
21 #include <stdio.h>
22 #include <unistd.h>
23
24
25 extern int fuzz_test;
26
27 #if 1
28 #define FSX_INIT(mount_pt) do{ if(interleave_fsx) yaffs_fsx_init(mount_pt); } while(0)
29 #define FSX_COMPLETE() do { if(interleave_fsx) yaffs_fsx_complete(); } while (0)
30
31 #define FSX() \
32 do { \
33   if((myrand() & 0x1) == 0){\
34      if(interleave_fsx) \
35         yaffs_fsx_do_op(); \
36   } \
37 } while(0)
38
39 #else
40 #define FSX_INIT(mount_point) do { } while(0)
41 #define FSX_COMPLETE() do { } while(0)
42 #define FSX() do { } while(0)
43 #endif
44
45
46 void (*ext_fatal)(void) = NULL;
47
48 static unsigned powerUps;
49 static unsigned cycleStarts;
50 static unsigned cycleEnds;
51
52 static int interleave_fsx;
53
54 static int no_verification;
55
56 char fullPathName[100];
57 char fullPowerUpName[100];
58 char fullStartName[100];
59 char fullEndName[100];
60 char fullMainName[100];
61 char fullTempMainName[100];
62 char fullTempCounterName[100];
63
64
65 extern int random_seed;
66
67 int myrand(void) {
68   random_seed = random_seed * 1103515245 + 12345;
69   return((unsigned)(random_seed/65536) % 32768);
70 }
71
72 void MakeName(char *fullName,const char *prefix, const char *name)
73 {
74   strcpy(fullName,prefix);
75   strcat(fullName,"/");
76   strcat(fullName,name);
77 }
78
79
80 void MakeFullNames(const char *prefix)
81 {
82   MakeName(fullPathName,prefix,"");
83   MakeName(fullPowerUpName,prefix,"powerUps");
84   MakeName(fullStartName,prefix,"starts");
85   MakeName(fullEndName,prefix,"ends");
86   MakeName(fullMainName,prefix,"main");
87   MakeName(fullTempCounterName,prefix,"tmp-counter");
88   MakeName(fullTempMainName,prefix,"tmp-main");
89 }
90
91 static void FatalError(int line_no)
92 {
93   printf("Integrity error %d\n",line_no);
94
95   if(fuzz_test)
96         return;
97
98   if(ext_fatal)
99         ext_fatal();
100
101   while(1){
102    sleep(1);
103   }
104 }
105 void print_stat(const char *str, struct yaffs_stat *st)
106 {
107         printf("%s inode %d\n",str,st->st_ino);
108 }
109
110 static void UpdateCounter(const char *name, unsigned *val,  int initialise)
111 {
112   int inh=-1;
113   int outh=-1;
114   unsigned x[2];
115   int nread = 0;
116   int nwritten = 0;
117
118   x[0] = x[1] = 0;
119
120   if(initialise){
121     x[0] = 0;
122     x[1] = 1;
123   } else {
124     inh = yaffs_open(name,O_RDONLY, S_IREAD | S_IWRITE);
125     if(inh >= 0){
126       nread = yaffs_read(inh,x,sizeof(x));
127       yaffs_close(inh);
128     }
129
130     if(!no_verification &&
131       (nread != sizeof(x) ||
132        x[0] + 1 != x[1])){
133       printf("Error reading counter %s handle %d, x[0] %u x[1] %u last error %d\n",
134               name, inh, x[0], x[1],yaffsfs_GetLastError());
135       FatalError(__LINE__);
136
137     }
138     x[0]++;
139     x[1]++;
140   }
141
142   FSX();
143   outh = yaffs_open(fullTempCounterName, O_RDWR | O_TRUNC | O_CREAT, S_IREAD | S_IWRITE);
144
145   if(outh >= 0){
146    struct yaffs_stat tmpstat, oldstat, tmpfstat;
147    FSX();
148     yaffs_fstat(outh,&tmpfstat);
149     printf("\n\n\n*** Writing file %s inode %d\n",fullTempCounterName,tmpfstat.st_ino);
150     nwritten = yaffs_write(outh,x,sizeof(x));
151     FSX();
152     yaffs_close(outh);
153     FSX();
154
155     printf("About to rename %s to %s\n",fullTempCounterName,name);
156     yaffs_stat(fullTempCounterName,&tmpstat);
157     yaffs_stat(name,&oldstat);
158     print_stat("old stat",&oldstat);
159     print_stat("new stat",&tmpstat);
160     print_stat("new fstat",&tmpfstat);
161     yaffs_rename(fullTempCounterName,name);
162     FSX();
163   }
164
165   if(nwritten != sizeof(x)){
166       printf("Error writing counter %s handle %d, x[0] %u x[1] %u\n",
167               name, inh, x[0], x[1]);
168       FatalError(__LINE__);
169   }
170
171   *val = x[0];
172
173   printf("##\n"
174          "## Set counter %s to %u\n"
175          "##\n", name,x[0]);
176 }
177
178
179 static void dump_directory_tree_worker(const char *dname,int recursive)
180 {
181         yaffs_DIR *d;
182         struct yaffs_dirent *de;
183         struct yaffs_stat s;
184         char str[1000];
185         int error_line = 0;
186         int nentries;
187
188         d = yaffs_opendir(dname);
189
190         if(!d)
191         {
192                 printf("opendir failed\n");
193         }
194         else
195         {
196                 nentries = 0;
197                 while((de = yaffs_readdir(d)) != NULL)
198                 {
199                         strcpy(str,dname);
200                         strcat(str,"/");
201                         strcat(str,de->d_name);
202                         nentries++;
203
204                         yaffs_lstat(str,&s);
205
206                         printf("%s inode %ld %d obj %x length %d mode %X ",str, de->d_ino, s.st_ino,de->d_dont_use,(int)s.st_size,s.st_mode);\
207                         if(de->d_ino != s.st_ino){
208                                 printf(" \n\n!!!! HEY inode mismatch\n\n");
209                                 error_line = __LINE__;
210                         }
211
212                         switch(s.st_mode & S_IFMT)
213                         {
214                                 case S_IFREG: printf("data file"); break;
215                                 case S_IFDIR: printf("directory"); break;
216                                 case S_IFLNK: printf("symlink -->");
217                                                           if(yaffs_readlink(str,str,100) < 0)
218                                                                 printf("no alias");
219                                                           else
220                                                                 printf("\"%s\"",str);
221                                                           break;
222                                 default: printf("unknown"); break;
223                         }
224
225                         printf("\n");
226
227                         if((s.st_mode & S_IFMT) == S_IFDIR && recursive)
228                                 dump_directory_tree_worker(str,1);
229
230                         if(s.st_ino > 10000)
231                                 error_line = __LINE__;
232
233                 }
234
235                 if(strstr(dname,"lost+found") && nentries >0){
236                         printf("\n\n!!! HEY lost+found not empty, had %d entries\n\n\n",nentries);
237                         error_line = __LINE__;
238                 }
239
240                 if(error_line && !no_verification)
241                         FatalError(error_line);
242
243                 yaffs_closedir(d);
244         }
245
246 }
247
248 static void dump_directory_tree(const char *dname)
249 {
250         dump_directory_tree_worker(dname,1);
251         printf("\n");
252         printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname));
253 }
254
255
256
257
258 #define XX_SIZE 500
259
260 static unsigned xx[XX_SIZE];
261
262 static int y_wr_file(const char *fname, unsigned sz32)
263 {
264         int h;
265         int r;
266         int i;
267         struct yaffs_stat st;
268         unsigned checksum = 0;
269
270
271         FSX();
272         h = yaffs_open(fname,O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
273         yaffs_fstat(h,&st);
274         printf("\n\n\n**** Open writing file %s inode %d\n",fname, st.st_ino);
275
276         FSX();
277
278         if(h < 0){
279                 printf("could not open file %s\n",fname);
280                 return h;
281         }
282
283         xx[0] = sz32;
284         checksum ^= xx[0];
285
286         if((r = yaffs_write(h,xx,sizeof(unsigned))) != sizeof(unsigned)){
287                 goto WRITE_ERROR;
288         }
289         FSX();
290         while(sz32> 0){
291                 for(i = 0; i < XX_SIZE; i++){
292                   xx[i] = sz32 + i;
293                   checksum ^= xx[i];
294                 }
295
296                 FSX();
297                 if((r = yaffs_write(h,xx,sizeof(xx))) != sizeof(xx)){
298                         goto WRITE_ERROR;
299                 }
300                 sz32--;
301         }
302
303         xx[0] = checksum;
304         FSX();
305         if((r = yaffs_write(h,xx,sizeof(unsigned))) != sizeof(unsigned)){
306                 goto WRITE_ERROR;
307         }
308
309         FSX();
310         yaffs_close(h);
311         printf("File closed\n");
312         return 0;
313
314 WRITE_ERROR:
315         printf("ywrite error at position %d\n",(int)yaffs_lseek(h,0,SEEK_END));
316         yaffs_close(h);
317         return -1;
318
319 }
320
321 static int y_verify_file(const char *fName)
322 {
323         unsigned checksum = 0;
324         unsigned totalSize;
325         unsigned sz32;
326         unsigned recordedSize = 0;
327         int r;
328         int h;
329         int i;
330         int retval = 0;
331
332         if(no_verification)
333                 return 0;
334
335         printf("Verifying file %s\n",fName);
336
337         h = yaffs_open(fName, O_RDONLY,S_IREAD | S_IWRITE);
338
339         if(h < 0){
340                 printf("could not open file %s\n",fName);
341                 return -1;
342         }
343
344         totalSize = yaffs_lseek(h,0,SEEK_END);
345         yaffs_lseek(h,0,SEEK_SET);
346
347         r = yaffs_read(h,&sz32,sizeof(sz32));
348
349         if(r != sizeof(sz32)){
350                 printf("reading size failed ... returned %d\n",r);
351                 yaffs_close(h);
352                 return -1;
353         }
354
355         recordedSize = sz32 * sizeof(xx) + 8;
356
357         printf("verify %s: file size is %d, recorded size is %d\n", fName, totalSize, recordedSize);
358         if(totalSize != recordedSize){
359                 printf("!!!!!!!!!!!!!!!!!!!!!!!!file size is wrong, should be %d, is %d\n", recordedSize,totalSize);
360                 yaffs_close(h);
361                 return -1;
362         }
363
364         checksum ^= sz32;
365
366
367         while(sz32 > 0){
368                 r = yaffs_read(h,xx,sizeof(xx));
369                 if(r != sizeof(xx)){
370                         printf("!!!!!!!!!!!!!!!!!!!!!!!!!!reading data failed ... returned %d\n",r);
371                         yaffs_close(h);
372                         return -1;
373                 }
374                 for(i = 0; i < XX_SIZE; i++)
375                   checksum ^= xx[i];
376                 sz32--;
377         }
378         r = yaffs_read(h,xx,sizeof(xx[0]));
379         if(r != sizeof(xx[0])){
380                 printf("!!!!!!!!!!!!!!!!!!!!!!!!!!reading data failed ... returned %d\n",r);
381                 yaffs_close(h);
382                 return -1;
383         }
384
385         checksum ^= xx[0];
386
387         if(checksum != 0){
388                 printf("!!!!!!!!!!!!!!!!!!!!! checksum failed\n");
389                 retval = -1;
390         } else
391                 printf("verified ok\n");
392         yaffs_close(h);
393
394         return retval;
395 }
396
397
398 static void DoUpdateMainFile(void)
399 {
400         int result;
401         int sz32;
402         sz32 = (myrand() % 1000)   + 20;
403
404         result = y_wr_file(fullTempMainName,sz32);
405         FSX();
406         if(!no_verification && result)
407             FatalError(__LINE__);
408         printf("Rename file %s to %s\n",fullTempMainName,fullMainName);
409         yaffs_rename(fullTempMainName,fullMainName);
410         FSX();
411 }
412
413 static void DoVerifyMainFile(void)
414 {
415         int result;
416         if(no_verification)
417                 return;
418         result = y_verify_file(fullMainName);
419         if(result)
420             FatalError(__LINE__);
421
422 }
423
424
425 void NorStressTestInitialise(const char *prefix)
426 {
427   MakeFullNames(prefix);
428
429   UpdateCounter(fullPowerUpName,&powerUps,1);
430   UpdateCounter(fullStartName,&cycleStarts,1);
431   UpdateCounter(fullEndName,&cycleEnds,1);
432   UpdateCounter(fullPowerUpName,&powerUps,1);
433   DoUpdateMainFile();
434   DoVerifyMainFile();
435 }
436
437
438 void NorStressTestRun(const char *prefix, int n_cycles, int do_fsx, int skip_verification)
439 {
440
441   interleave_fsx = do_fsx;
442   no_verification = skip_verification;
443
444   MakeFullNames(prefix);
445   dump_directory_tree(fullPathName);
446   FSX_INIT(prefix);
447
448   dump_directory_tree(fullPathName);
449
450   UpdateCounter(fullPowerUpName,&powerUps,0);
451   dump_directory_tree(fullPathName);
452
453   while(n_cycles < 0 || n_cycles > 0){
454     if(n_cycles > 0)
455       n_cycles--;
456     UpdateCounter(fullStartName, &cycleStarts,0);
457     dump_directory_tree(fullPathName);
458     DoVerifyMainFile();
459     DoUpdateMainFile();
460     dump_directory_tree(fullPathName);
461
462     UpdateCounter(fullEndName,&cycleEnds,0);
463     dump_directory_tree(fullPathName);
464   }
465   FSX_COMPLETE();
466 }