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