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 allocate 118 clusters for A.TXT.
14 Step6: Create a new thread and allocate cluster 127 and 128 for A.TXT.
15 Step7: Terminate the new thread to simulate poweroff while writing the fat entry of cluster 127
16 (the fat entry of cluster 128 is flushed first).
17 Step8: Open the media.
18 Step9: Enable fault tolerant feature to revert the FAT chain(revert operation).
19 Step10: Perform media check.
20 */
21 
22 #ifndef FX_STANDALONE_ENABLE
23 #include   "tx_api.h"
24 #else
25 #define    _GNU_SOURCE
26 #define    _DEFAULT_SOURCE
27 #include   <pthread.h>
28 #include   <unistd.h>
29 #endif
30 #include   "fx_api.h"
31 #include   "fx_system.h"
32 #include   "fx_fault_tolerant.h"
33 #include   "fx_utility.h"
34 #include   <stdio.h>
35 #include   "fx_ram_driver_test.h"
36 extern void    test_control_return(UINT status);
37 void    filex_fault_tolerant_file_allocate_fat_crossover_test_application_define(void *first_unused_memory);
38 
39 #ifdef FX_ENABLE_FAULT_TOLERANT
40 
41 #define DEMO_STACK_SIZE         4096
42 #define CACHE_SIZE              2048
43 #define FAULT_TOLERANT_SIZE     FX_FAULT_TOLERANT_MINIMAL_BUFFER_SIZE
44 
45 
46 /* Define the ThreadX and FileX object control blocks...  */
47 
48 #ifndef FX_STANDALONE_ENABLE
49 static TX_THREAD                ftest_0;
50 static TX_THREAD                ftest_1;
51 #else
52 static pthread_t                ptid1;
53 #endif
54 static FX_MEDIA                 ram_disk;
55 static FX_FILE                  my_file;
56 static UCHAR                    *pointer;
57 
58 /* Define the counters used in the test application...  */
59 
60 #ifndef FX_STANDALONE_ENABLE
61 static UCHAR                    *cache_buffer;
62 static UCHAR                    *fault_tolerant_buffer;
63 static UCHAR                    *thread_buffer;
64 #else
65 static UCHAR                    cache_buffer[CACHE_SIZE];
66 static UCHAR                    fault_tolerant_buffer[FAULT_TOLERANT_SIZE];
67 #endif
68 static UINT                     fat_write_interrupt = FX_FALSE;
69 static UCHAR                    scratch_memory[16 * 1024];
70 static UINT                     interrupt_count_down;
71 
72 
73 /* Define thread prototypes.  */
74 
75 static void    ftest_0_entry(ULONG thread_input);
76 #ifndef FX_STANDALONE_ENABLE
77 static void    ftest_1_entry(ULONG thread_input);
78 #else
79 static void   * ftest_1_entry(void * thread_input);
80 #endif
81 
82 extern void  _fx_ram_driver(FX_MEDIA *media_ptr);
83 extern void  test_control_return(UINT status);
84 extern UINT  _filex_fault_tolerant_log_check(FX_MEDIA *media_ptr);
85 extern UINT  (*driver_write_callback)(FX_MEDIA *media_ptr, UINT sector_type, UCHAR *block_ptr, UINT *operation_ptr);
86 static UINT  my_driver_write(FX_MEDIA *media_ptr, UINT sector_type, UCHAR *block_ptr, UINT *operation_ptr);
87 
88 
89 
90 /* Define what the initial system looks like.  */
91 #ifdef CTEST
test_application_define(void * first_unused_memory)92 void test_application_define(void *first_unused_memory)
93 #else
94 void    filex_fault_tolerant_file_allocate_fat_crossover_test_application_define(void *first_unused_memory)
95 #endif
96 {
97 
98 #ifndef FX_STANDALONE_ENABLE
99     /* Setup the working pointer.  */
100     pointer =  (UCHAR *) first_unused_memory;
101 
102     /* Create the main thread.  */
103 
104     tx_thread_create(&ftest_0, "thread 0", ftest_0_entry, 0,
105             pointer, DEMO_STACK_SIZE,
106             4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
107 
108     pointer =  pointer + DEMO_STACK_SIZE;
109 
110     /* Setup memory for the RAM disk and the sector cache.  */
111     cache_buffer =  pointer;
112     pointer += CACHE_SIZE;
113     fault_tolerant_buffer = pointer;
114     pointer += FAULT_TOLERANT_SIZE;
115     thread_buffer = pointer;
116     pointer += DEMO_STACK_SIZE;
117 #endif
118 
119     /* Initialize the FileX system.  */
120     fx_system_initialize();
121 #ifdef FX_STANDALONE_ENABLE
122     ftest_0_entry(0);
123 #endif
124 }
125 
126 
127 
128 /* Define the test threads.  */
129 
ftest_0_entry(ULONG thread_input)130 static void    ftest_0_entry(ULONG thread_input)
131 {
132 
133 UINT        status;
134 ULONG       errors_detected;
135 
136     FX_PARAMETER_NOT_USED(thread_input);
137 
138     /* Print out some test information banners.  */
139     printf("FileX Test:   Fault Tolerant File Allocate Fat Crossover Test........");
140 
141     /* Format the media with FAT32.  This needs to be done before opening it!  */
142     status = fx_media_format(&ram_disk,
143                              _fx_ram_driver,         // Driver entry
144                              ram_disk_memory_large,  // RAM disk memory pointer
145                              cache_buffer,           // Media buffer pointer
146                              CACHE_SIZE,             // Media buffer size
147                              "MY_RAM_DISK",          // Volume Name
148                              1,                      // Number of FATs
149                              32,                     // Directory Entries
150                              0,                      // Hidden sectors
151                              70000,                  // Total sectors
152                              512,                    // Sector size
153                              1,                      // Sectors per cluster
154                              1,                      // Heads
155                              1);                     // Sectors per track
156     status +=  fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory_large, cache_buffer, CACHE_SIZE);
157     status += fx_fault_tolerant_enable(&ram_disk, fault_tolerant_buffer, FAULT_TOLERANT_SIZE);
158     return_if_fail(FX_SUCCESS == status);
159 
160     /* One cluster for A.TXT. */
161     status = fx_file_create(&ram_disk, "A.TXT");
162     status += fx_file_open(&ram_disk, &my_file, "A.TXT", FX_OPEN_FOR_WRITE);
163     status += fx_file_allocate(&my_file, 512 * 118);
164     status += fx_file_close(&my_file);
165     return_if_fail(FX_SUCCESS == status);
166 
167     /* Ensure no lost clusters. */
168     status = fx_media_check(&ram_disk, scratch_memory, sizeof(scratch_memory), FX_LOST_CLUSTER_ERROR, &errors_detected);
169     return_if_fail((status == FX_SUCCESS) && (0 == errors_detected));
170 
171     /* Create the main thread.  */
172 #ifndef FX_STANDALONE_ENABLE
173     tx_thread_create(&ftest_1, "thread 1", ftest_1_entry, 0,
174                     thread_buffer, DEMO_STACK_SIZE,
175                     4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
176 #endif
177 
178     /* directory_write_interrupt */
179     fat_write_interrupt = FX_FALSE;
180 
181     /* Let the other thread run.  */
182 #ifndef FX_STANDALONE_ENABLE
183     tx_thread_relinquish();
184 #else
185     pthread_create(&ptid1, NULL, &ftest_1_entry, NULL);
186     usleep(10);
187     pthread_join(ptid1,NULL);
188 #endif
189 
190     /* After write interrupt, reread the files.  */
191     return_if_fail(FX_TRUE == fat_write_interrupt);
192 
193     status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory_large, cache_buffer, CACHE_SIZE);
194     status += fx_fault_tolerant_enable(&ram_disk, fault_tolerant_buffer, FAULT_TOLERANT_SIZE);
195     return_if_fail(FX_SUCCESS == status);
196 
197     status =  fx_media_check(&ram_disk, scratch_memory, sizeof(scratch_memory), FX_LOST_CLUSTER_ERROR, &errors_detected);
198     return_if_fail(FX_SUCCESS == status);
199     return_if_fail(errors_detected == 0);
200 
201     fx_media_close(&ram_disk);
202 
203     /* Delete the thread.  */
204 #ifndef FX_STANDALONE_ENABLE
205     tx_thread_delete(&ftest_1);
206 #else
207     pthread_cancel(ptid1);
208 #endif
209 
210     /* Output successful.  */
211     printf("SUCCESS!\n");
212     test_control_return(0);
213 }
214 
215 /* Define the test threads.  */
216 
217 #ifndef FX_STANDALONE_ENABLE
ftest_1_entry(ULONG thread_input)218 static void    ftest_1_entry(ULONG thread_input)
219 #else
220  void  *  ftest_1_entry(void * thread_input)
221 #endif
222 {
223 
224 #ifdef FX_STANDALONE_ENABLE
225     UINT oldtype;
226     pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
227     pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
228 #endif
229 
230     UINT        status;
231 
232     FX_PARAMETER_NOT_USED(thread_input);
233 
234     /* Set the callback function to simulate poweoff operation when write FAT entry.  */
235     driver_write_callback = my_driver_write;
236 
237     /* Open the test file.  */
238     status = fx_file_open(&ram_disk, &my_file, "A.TXT", FX_OPEN_FOR_WRITE);
239     return_if_fail(FX_SUCCESS == status);
240 
241     interrupt_count_down = 2;
242 
243     /*  The FAT sector of the fat entries of cluster 127 is not the FAT sector for cluster 128.
244         Since the record of cluster 128 is located at fat_cache[0], the fat sector of 128 will be flushed first.
245         Terminate the new thread to simulate poweroff while writing the fat entry of cluster 127.
246     */
247     fx_file_allocate(&my_file, 512 * 2);
248 }
249 
my_driver_write(FX_MEDIA * media_ptr,UINT sector_type,UCHAR * block_ptr,UINT * operation_ptr)250 static UINT my_driver_write(FX_MEDIA *media_ptr, UINT sector_type, UCHAR *block_ptr, UINT *operation_ptr)
251 {
252 
253     FX_PARAMETER_NOT_USED(block_ptr);
254 
255     /* Interrupt the FAT write operation after record the undo log.  */
256     if (sector_type == FX_FAT_SECTOR)
257     {
258 
259         interrupt_count_down--;
260         if (interrupt_count_down == 0)
261         {
262 
263             /* Set the write interrupt operation.  */
264             *operation_ptr = FX_OP_WRITE_INTERRUPT;
265 
266             /* Update the flag.  */
267             fat_write_interrupt = FX_TRUE;
268 
269             /* Clean the callback function.  */
270             driver_write_callback = FX_NULL;
271 
272             /* Delete the media protection structure if FX_SINGLE_THREAD is not
273             defined.  */
274 #ifndef FX_SINGLE_THREAD
275 #ifndef FX_DONT_CREATE_MUTEX
276 
277             /* Note that the protection is never released. The mutex delete
278             service will handle all threads waiting access to this media
279             control block.  */
280             tx_mutex_delete(&(media_ptr -> fx_media_protect));
281 #endif
282 #endif
283 
284             /* Clean the media data.  */
285             _fx_system_media_opened_ptr = FX_NULL;
286             _fx_system_media_opened_count = 0;
287 
288             /* Clean the media.  */
289             memset(media_ptr, 0, sizeof(FX_MEDIA));
290 
291             /* Simulate poweroff.  */
292             /* First terminate the thread to ensure it is ready for deletion.  */
293 #ifndef FX_STANDALONE_ENABLE
294         tx_thread_terminate(&ftest_1);
295 #else
296         pthread_cancel(ptid1);
297 #endif
298         }
299     }
300 
301     /* Return.  */
302     return FX_SUCCESS;
303 }
304 #else
305 
306 #ifdef CTEST
test_application_define(void * first_unused_memory)307 void test_application_define(void *first_unused_memory)
308 #else
309 void    filex_fault_tolerant_file_allocate_fat_crossover_test_application_define(void *first_unused_memory)
310 #endif
311 {
312 
313     FX_PARAMETER_NOT_USED(first_unused_memory);
314 
315     /* Print out some test information banners.  */
316     printf("FileX Test:   Fault Tolerant File Allocate Fat Crossover Test........N/A\n");
317 
318     test_control_return(255);
319 }
320 #endif
321 
322