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