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