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