1 /* This FileX test concentrates on the bug as per
2  * JIRA: https://expresslogic.atlassian.net/browse/FIL-4.
3  * In fx_fault_tolerant_cleanup_FAT_chain.c, a group of the FAT entries are updated in the cache
4  * before it is flushed into media system. The design requires the FAT entries updated in reverse
5  * order in FAT chain. Due to the FAT cache, the FAT entries may be updated in any order.
6  * That will break the fault tolerant design. The expected issue is, the FAT chain could
7  * not be released completely.*/
8 /*
9 For FAT 32 one cluster size is 512 bytes and one sector per cluster;
10 
11 Step1: Format and open the media;
12 Step2: Enable fault tolerant feature;
13 Step3: Create and write 1M bytes into TEST.TXT;
14 Step4: Create a new thread and seek to beginning of file and overwrite 64K bytes into TEST.TXT;
15 Step5: Terminate the new thread to simulate poweroff when write the fat after redo log generated, during FAT chain cleanup.
16 Step8: Open the media;
17 Step9: Enable fault tolerant feature to recover the data(undo operation);
18 Step10: Perform media check.
19 */
20 
21 #ifndef FX_STANDALONE_ENABLE
22 #include   "tx_api.h"
23 #else
24 #define    _GNU_SOURCE
25 #define    _DEFAULT_SOURCE
26 #include   <pthread.h>
27 #include   <unistd.h>
28 #endif
29 #include   "fx_api.h"
30 #include   "fx_system.h"
31 #include   "fx_fault_tolerant.h"
32 #include   "fx_utility.h"
33 #include   <stdio.h>
34 #include   "fx_ram_driver_test.h"
35 extern void    test_control_return(UINT status);
36 void    filex_fault_tolerant_file_write_fat_crossover_test_application_define(void *first_unused_memory);
37 
38 #ifdef FX_ENABLE_FAULT_TOLERANT
39 
40 #define DEMO_STACK_SIZE         4096
41 #define CACHE_SIZE              2048
42 #define FAULT_TOLERANT_SIZE     FX_FAULT_TOLERANT_MINIMAL_BUFFER_SIZE
43 
44 
45 /* Define the ThreadX and FileX object control blocks...  */
46 
47 #ifndef FX_STANDALONE_ENABLE
48 static TX_THREAD                ftest_0;
49 static TX_THREAD                ftest_1;
50 #else
51 static pthread_t                ptid1;
52 #endif
53 static FX_MEDIA                 ram_disk;
54 static FX_FILE                  my_file;
55 static UCHAR                    *pointer;
56 
57 /* Define the counters used in the test application...  */
58 
59 #ifndef FX_STANDALONE_ENABLE
60 static UCHAR                    *cache_buffer;
61 static UCHAR                    *fault_tolerant_buffer;
62 static UCHAR                    *thread_buffer;
63 #else
64 static UCHAR                    cache_buffer[CACHE_SIZE];
65 static UCHAR                    fault_tolerant_buffer[FAULT_TOLERANT_SIZE];
66 #endif
67 static UINT                     error_couter = 0;
68 static UINT                     fat_write_interrupt = FX_FALSE;
69 static UCHAR                    data_buffer[64 * 1024];
70 static UCHAR                    scratch_memory[16 * 1024];
71 static UINT                     interrupt_count_down;
72 
73 
74 /* Define thread prototypes.  */
75 
76 static void    ftest_0_entry(ULONG thread_input);
77 #ifndef FX_STANDALONE_ENABLE
78 static void    ftest_1_entry(ULONG thread_input);
79 #else
80 static void   * ftest_1_entry(void * thread_input);
81 #endif
82 
83 extern void  _fx_ram_driver(FX_MEDIA *media_ptr);
84 extern void  test_control_return(UINT status);
85 extern UINT  _filex_fault_tolerant_log_check(FX_MEDIA *media_ptr);
86 extern UINT  (*driver_write_callback)(FX_MEDIA *media_ptr, UINT sector_type, UCHAR *block_ptr, UINT *operation_ptr);
87 static UINT  my_driver_write(FX_MEDIA *media_ptr, UINT sector_type, UCHAR *block_ptr, UINT *operation_ptr);
88 
89 
90 
91 /* Define what the initial system looks like.  */
92 
93 #ifdef CTEST
test_application_define(void * first_unused_memory)94 void test_application_define(void *first_unused_memory)
95 #else
96 void    filex_fault_tolerant_file_write_fat_crossover_test_application_define(void *first_unused_memory)
97 #endif
98 {
99 
100 
101 #ifndef FX_STANDALONE_ENABLE
102     /* Setup the working pointer.  */
103     pointer =  (UCHAR *) first_unused_memory;
104 
105     /* Create the main thread.  */
106 
107     tx_thread_create(&ftest_0, "thread 0", ftest_0_entry, 0,
108             pointer, DEMO_STACK_SIZE,
109             4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
110 
111     pointer =  pointer + DEMO_STACK_SIZE;
112 
113     /* Setup memory for the RAM disk and the sector cache.  */
114     cache_buffer =  pointer;
115     pointer += CACHE_SIZE;
116     fault_tolerant_buffer = pointer;
117     pointer += FAULT_TOLERANT_SIZE;
118     thread_buffer = pointer;
119     pointer += DEMO_STACK_SIZE;
120 #endif
121 
122     /* Initialize the FileX system.  */
123     fx_system_initialize();
124 #ifdef FX_STANDALONE_ENABLE
125     ftest_0_entry(0);
126 #endif
127 }
128 
129 
130 
131 /* Define the test threads.  */
132 
ftest_0_entry(ULONG thread_input)133 static void    ftest_0_entry(ULONG thread_input)
134 {
135 
136 UINT        status;
137 ULONG       errors_detected;
138 
139     FX_PARAMETER_NOT_USED(thread_input);
140 
141     /* Print out some test information banners.  */
142     printf("FileX Test:   Fault Tolerant File Write FAT Crossover Test...........");
143 
144     /* Format the media with FAT32.  This needs to be done before opening it!  */
145     status =  fx_media_format(&ram_disk,
146                              _fx_ram_driver,         // Driver entry
147                              ram_disk_memory_large,  // RAM disk memory pointer
148                              cache_buffer,           // Media buffer pointer
149                              CACHE_SIZE,             // Media buffer size
150                              "MY_RAM_DISK",          // Volume Name
151                              1,                      // Number of FATs
152                              32,                     // Directory Entries
153                              0,                      // Hidden sectors
154                              70000,                  // Total sectors
155                              512,                    // Sector size
156                              1,                      // Sectors per cluster
157                              1,                      // Heads
158                              1);                     // Sectors per track
159 
160     /* Determine if the format had an error.  */
161     if (status)
162     {
163 
164         printf("ERROR!\n");
165         test_control_return(1);
166     }
167 
168     /* Open the ram_disk.  */
169     status =  fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory_large, cache_buffer, CACHE_SIZE);
170 
171     /* Check the status.  */
172     if (status != FX_SUCCESS)
173     {
174 
175         /* Error, return error code.  */
176         printf("ERROR!\n");
177         test_control_return(2);
178     }
179 
180     /* Enable the Fault-tolerant feature.  */
181     status = fx_fault_tolerant_enable(&ram_disk, fault_tolerant_buffer, FAULT_TOLERANT_SIZE);
182 
183     /* Check status.   */
184     if (status)
185     {
186 
187         printf("ERROR!\n");
188         test_control_return(3);
189     }
190 
191     /* Create a file called TEST.TXT in the root directory.  */
192     status =  fx_file_create(&ram_disk, "TEST.TXT");
193 
194     /* Check the create status.  */
195     if (status != FX_SUCCESS)
196     {
197 
198         printf("ERROR!\n");
199         test_control_return(4);
200     }
201 
202     /* Open the test file.  */
203     status =  fx_file_open(&ram_disk, &my_file, "TEST.TXT", FX_OPEN_FOR_WRITE);
204 
205     /* Check the file open status.  */
206     if (status != FX_SUCCESS)
207     {
208 
209         printf("ERROR!\n");
210         test_control_return(5);
211     }
212 
213     /* Write a string to the test file.  */
214     status =  fx_file_write(&my_file, data_buffer, sizeof(data_buffer));
215 
216     /* Check the file write status.  */
217     if (status != FX_SUCCESS)
218     {
219 
220         printf("ERROR!\n");
221         test_control_return(6);
222     }
223 
224     /* Close the test file.  */
225     status =  fx_file_close(&my_file);
226 
227     /* Alter the FAT chain of file. Swap FAT 112 and 136. */
228     _fx_utility_FAT_entry_write(&ram_disk, 111, 136);
229     _fx_utility_FAT_entry_write(&ram_disk, 112, ram_disk.fx_media_fat_last);
230     _fx_utility_FAT_entry_write(&ram_disk, 136, 113);
231     _fx_utility_FAT_entry_write(&ram_disk, 135, 112);
232     fx_media_flush(&ram_disk);
233 
234     status =  fx_media_check(&ram_disk, scratch_memory, sizeof(scratch_memory), FX_LOST_CLUSTER_ERROR, &errors_detected);
235 
236     /* Determine if any were found - should not have found any errors at this point.  */
237     if ((status != FX_SUCCESS) || (errors_detected))
238     {
239 
240         printf("ERROR!\n");
241         test_control_return(7);
242     }
243 
244     /* Create the main thread.  */
245 #ifndef FX_STANDALONE_ENABLE
246     tx_thread_create(&ftest_1, "thread 1", ftest_1_entry, 0,
247                     thread_buffer, DEMO_STACK_SIZE,
248                     4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
249 #endif
250 
251     /* directory_write_interrupt */
252     fat_write_interrupt = FX_FALSE;
253 
254     /* Let the other thread run.  */
255 #ifndef FX_STANDALONE_ENABLE
256     tx_thread_relinquish();
257 #else
258     pthread_create(&ptid1, NULL, &ftest_1_entry, NULL);
259     usleep(10);
260     pthread_join(ptid1,NULL);
261 #endif
262     /* After write interrupt, reread the files.  */
263 
264     /* Open the ram_disk.  */
265     status =  fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory_large, cache_buffer, CACHE_SIZE);
266 
267     /* Check the status.  */
268     if (status != FX_SUCCESS)
269     {
270 
271         /* Error, return error code.  */
272         printf("ERROR!\n");
273         test_control_return(22);
274     }
275 
276     /* Enable the Fault-tolerant feature to recover the media.  */
277     status = fx_fault_tolerant_enable(&ram_disk, fault_tolerant_buffer, FAULT_TOLERANT_SIZE);
278 
279     /* Check status.   */
280     if (status)
281     {
282 
283         printf("ERROR!\n");
284         test_control_return(23);
285     }
286 
287     status =  fx_media_check(&ram_disk, scratch_memory, sizeof(scratch_memory), FX_LOST_CLUSTER_ERROR, &errors_detected);
288 
289     /* Determine if any were found - should not have found any errors at this point.  */
290     if ((status != FX_SUCCESS) || (errors_detected))
291     {
292 
293         printf("ERROR!\n");
294         test_control_return(35);
295     }
296 
297     /* Close the media.  */
298     status =  fx_media_close(&ram_disk);
299 
300     /* Determine if the test was successful.  */
301     if ((status != FX_SUCCESS) || (fat_write_interrupt != FX_TRUE) || (error_couter))
302     {
303 
304         printf("ERROR!\n");
305         test_control_return(36);
306     }
307 
308     /* Delete the thread.  */
309 #ifndef FX_STANDALONE_ENABLE
310     tx_thread_delete(&ftest_1);
311 #else
312     pthread_cancel(ptid1);
313 #endif
314 
315     /* Output successful.  */
316     printf("SUCCESS!\n");
317     test_control_return(0);
318 }
319 
320 /* Define the test threads.  */
321 
322 #ifndef FX_STANDALONE_ENABLE
ftest_1_entry(ULONG thread_input)323 static void    ftest_1_entry(ULONG thread_input)
324 #else
325  void  *  ftest_1_entry(void * thread_input)
326 #endif
327 {
328 
329 #ifdef FX_STANDALONE_ENABLE
330     UINT oldtype;
331     pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
332     pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
333 #endif
334     UINT        status;
335 
336     FX_PARAMETER_NOT_USED(thread_input);
337 
338     /* Set the callback function to simulate poweoff operation when write FAT entry.  */
339     driver_write_callback = my_driver_write;
340 
341     /* Open the test file.  */
342     status =  fx_file_open(&ram_disk, &my_file, "TEST.TXT", FX_OPEN_FOR_WRITE);
343 
344     /* Check the file open status.  */
345     if (status != FX_SUCCESS)
346     {
347         error_couter ++;
348 #ifndef FX_STANDALONE_ENABLE
349         return;
350 #else
351         return NULL;
352 #endif
353     }
354 
355     status = fx_file_seek(&my_file, 0);
356 
357     /* Check the file seek status.  */
358     if (status != FX_SUCCESS)
359     {
360         error_couter ++;
361 #ifndef FX_STANDALONE_ENABLE
362         return;
363 #else
364         return NULL;
365 #endif
366     }
367 
368     interrupt_count_down = 2;
369 
370     /* Write 64K bytes to the file.  */
371     fx_file_write(&my_file, data_buffer, sizeof(data_buffer));
372 }
373 
my_driver_write(FX_MEDIA * media_ptr,UINT sector_type,UCHAR * block_ptr,UINT * operation_ptr)374 static UINT my_driver_write(FX_MEDIA *media_ptr, UINT sector_type, UCHAR *block_ptr, UINT *operation_ptr)
375 {
376 
377     FX_PARAMETER_NOT_USED(block_ptr);
378 
379     /* Interrupt the FAT write operation after record the undo log.  */
380     if ((sector_type == FX_FAT_SECTOR) && (_filex_fault_tolerant_log_check(media_ptr) & FX_FAULT_TOLERANT_LOG_REDO_DONE))
381     {
382 
383         interrupt_count_down--;
384         if (interrupt_count_down == 0)
385         {
386 
387             /* Set the write interrupt operation.  */
388             *operation_ptr = FX_OP_WRITE_INTERRUPT;
389 
390             /* Update the flag.  */
391             fat_write_interrupt = FX_TRUE;
392 
393             /* Clean the callback function.  */
394             driver_write_callback = FX_NULL;
395 
396             /* Delete the media protection structure if FX_SINGLE_THREAD is not
397             defined.  */
398 #ifndef FX_SINGLE_THREAD
399 #ifndef FX_DONT_CREATE_MUTEX
400 
401             /* Note that the protection is never released. The mutex delete
402             service will handle all threads waiting access to this media
403             control block.  */
404             tx_mutex_delete(&(media_ptr -> fx_media_protect));
405 #endif
406 #endif
407 
408             /* Clean the media data.  */
409             _fx_system_media_opened_ptr = FX_NULL;
410             _fx_system_media_opened_count = 0;
411 
412             /* Clean the media.  */
413             memset(media_ptr, 0, sizeof(FX_MEDIA));
414 
415             /* Simulate poweroff.  */
416             /* First terminate the thread to ensure it is ready for deletion.  */
417 #ifndef FX_STANDALONE_ENABLE
418         tx_thread_terminate(&ftest_1);
419 #else
420         pthread_cancel(ptid1);
421 #endif
422         }
423     }
424 
425     /* Return.  */
426     return FX_SUCCESS;
427 }
428 #else
429 
430 #ifdef CTEST
test_application_define(void * first_unused_memory)431 void test_application_define(void *first_unused_memory)
432 #else
433 void    filex_fault_tolerant_file_write_fat_crossover_test_application_define(void *first_unused_memory)
434 #endif
435 {
436 
437     FX_PARAMETER_NOT_USED(first_unused_memory);
438 
439     /* Print out some test information banners.  */
440     printf("FileX Test:   Fault Tolerant File Write FAT Crossover Test...........N/A\n");
441 
442     test_control_return(255);
443 }
444 #endif
445 
446