GCC Code Coverage Report


Directory: common/src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 71 / 0 / 71
Functions: 100.0% 2 / 0 / 2
Branches: 96.0% 48 / 0 / 50

fx_fault_tolerant_cleanup_FAT_chain.c
Line Branch Exec Source
1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 * Copyright (c) 2026-present Eclipse ThreadX contributors
4 *
5 * This program and the accompanying materials are made available under the
6 * terms of the MIT License which is available at
7 * https://opensource.org/licenses/MIT.
8 *
9 * SPDX-License-Identifier: MIT
10 **************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** FileX Component */
17 /** */
18 /** Fault Tolerant */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define FX_SOURCE_CODE
24
25 #include "fx_api.h"
26 #include "fx_utility.h"
27 #include "fx_fault_tolerant.h"
28
29
30 #ifdef FX_ENABLE_FAULT_TOLERANT
31
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _fx_utility_FAT_entry_multiple_sectors_check PORTABLE C */
38 /* 6.2.0 */
39 /* AUTHOR */
40 /* */
41 /* Tiejun Zhou, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* This function checks whether the FAT entry spans multiple sectors. */
46 /* It is only possible when the file system is FAT12. */
47 /* */
48 /* INPUT */
49 /* */
50 /* media_ptr Media control block pointer */
51 /* cluster Cluster entry number */
52 /* */
53 /* OUTPUT */
54 /* */
55 /* FX_TRUE FAT entry spans two sectors */
56 /* FX_FALSE FAT entry in one sector */
57 /* */
58 /* CALLS */
59 /* */
60 /* None */
61 /* */
62 /* CALLED BY */
63 /* */
64 /* _fx_fault_tolerant_cleanup_FAT_chain */
65 /* */
66 /**************************************************************************/
67 37509451 static UINT _fx_utility_FAT_entry_multiple_sectors_check(FX_MEDIA *media_ptr, ULONG cluster)
68 {
69 ULONG byte_offset;
70 ULONG FAT_sector;
71
72 /* Check FAT format. */
73
2/2
✓ Branch 2 → 3 taken 36870850 times.
✓ Branch 2 → 4 taken 638601 times.
37509451 if (!media_ptr -> fx_media_12_bit_FAT)
74 {
75
76 /* Not FAT12. The FAT entry will be in one sector. */
77 36870850 return(FX_FALSE);
78 }
79
80 /* File system is FAT12. */
81 /* Calculate the byte offset to the cluster entry. */
82 638601 byte_offset = (((ULONG)cluster << 1) + cluster) >> 1;
83
84 /* Calculate the FAT sector the requested FAT entry resides in. */
85 638601 FAT_sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
86 638601 (ULONG)media_ptr -> fx_media_reserved_sectors;
87
88 /* Now calculate the byte offset into this FAT sector. */
89 638601 byte_offset = byte_offset -
90 638601 ((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
91 638601 media_ptr -> fx_media_bytes_per_sector);
92
93 /* Determine if we are now past the end of the FAT buffer in memory. */
94
2/2
✓ Branch 4 → 5 taken 200 times.
✓ Branch 4 → 6 taken 638401 times.
638601 if (byte_offset == (ULONG)(media_ptr -> fx_media_bytes_per_sector - 1))
95 {
96
97 /* Yes, we are past the end of the FAT buffer. */
98 200 return(FX_TRUE);
99 }
100 else
101 {
102
103 /* No, we are not past the end of the FAT buffer. */
104 638401 return(FX_FALSE);
105 }
106 }
107
108 /**************************************************************************/
109 /* */
110 /* FUNCTION RELEASE */
111 /* */
112 /* _fx_fault_tolerant_cleanup_FAT_chain PORTABLE C */
113 /* 6.2.0 */
114 /* AUTHOR */
115 /* */
116 /* William E. Lamie, Microsoft Corporation */
117 /* */
118 /* DESCRIPTION */
119 /* */
120 /* This function cleans up FAT chain. In order to prevent failures */
121 /* during the link-list walk, and to improve efficiency, this function */
122 /* frees the FAT entry chain in sections. For each section, it frees */
123 /* FAT entry from the last entry in the chain and works backwards. */
124 /* Using this method, if the system fails in the middle of the free */
125 /* operation, the head is preserved, and fault tolerant module can */
126 /* "redo" this operation next time it starts up. */
127 /* */
128 /* INPUT */
129 /* */
130 /* media_ptr Media control block pointer */
131 /* operation Recover a failure operation or*/
132 /* cleanup old FAT chain */
133 /* */
134 /* OUTPUT */
135 /* */
136 /* return status */
137 /* */
138 /* CALLS */
139 /* */
140 /* _fx_utility_FAT_entry_read Read a FAT entry */
141 /* _fx_utility_FAT_entry_write Write a FAT entry */
142 /* _fx_utility_16_unsigned_write Write a USHORT from memory */
143 /* _fx_utility_32_unsigned_write Write a ULONG from memory */
144 /* _fx_utility_32_unsigned_read Read a ULONG from memory */
145 /* _fx_utility_FAT_flush Flush written FAT entries */
146 /* _fx_fault_tolerant_calculate_checksum Compute Checksum of data */
147 /* _fx_fault_tolerant_write_log_file Write log file */
148 /* _fx_utility_FAT_entry_multiple_sectors_check */
149 /* Check sectors for FAT entry */
150 /* */
151 /* CALLED BY */
152 /* */
153 /* _fx_fault_tolerant_apply_logs */
154 /* _fx_fault_tolerant_recover */
155 /* */
156 /**************************************************************************/
157 8413787 UINT _fx_fault_tolerant_cleanup_FAT_chain(FX_MEDIA *media_ptr, UINT operation)
158 {
159 UINT status;
160 ULONG current_cluster;
161 8413787 ULONG next_cluster = 0;
162 ULONG head_cluster;
163 ULONG tail_cluster;
164 ULONG cache_count;
165 8413787 ULONG cache_max = FX_FAULT_TOLERANT_CACHE_SIZE >> 2;
166 8413787 ULONG *cache_ptr = media_ptr -> fx_media_fault_tolerant_cache;
167 ULONG next_session;
168 USHORT checksum;
169 ULONG i;
170 FX_FAULT_TOLERANT_FAT_CHAIN *FAT_chain;
171 ULONG FAT_sector;
172 ULONG last_FAT_sector;
173
174 /* Set FAT chain pointer. */
175 8413787 FAT_chain = (FX_FAULT_TOLERANT_FAT_CHAIN *)(media_ptr -> fx_media_fault_tolerant_memory_buffer + FX_FAULT_TOLERANT_FAT_CHAIN_OFFSET);
176
177 /* Get head and tail cluster. */
178
2/2
✓ Branch 2 → 3 taken 508 times.
✓ Branch 2 → 4 taken 8413279 times.
8413787 if (operation == FX_FAULT_TOLERANT_FAT_CHAIN_RECOVER)
179 {
180
181 /* Recover phase. Cleanup (remove) new FAT chain. */
182 508 head_cluster = _fx_utility_32_unsigned_read((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_new);
183 }
184 else
185 {
186
187 /* Cleanup phase. Cleanup (remove) old FAT chain. */
188 8413279 head_cluster = _fx_utility_32_unsigned_read((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_original);
189 }
190
191 /* At this point, the head_cluster points to the cluster chain that is to be removed. */
192
193 /* Tail cluster points to the back of the original FAT chain where the new chain is attached to.
194 The remove process terminates once this cluster is encountered. */
195 8413787 tail_cluster = _fx_utility_32_unsigned_read((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_insertion_back);
196
197 /* Are there any clusters to free? */
198
4/4
✓ Branch 6 → 7 taken 8413771 times.
✓ Branch 6 → 8 taken 16 times.
✓ Branch 7 → 8 taken 3699757 times.
✓ Branch 7 → 9 taken 4714014 times.
8413787 if ((head_cluster < FX_FAT_ENTRY_START) || (head_cluster >= media_ptr -> fx_media_fat_reserved))
199 {
200 3699773 return(FX_SUCCESS);
201 }
202
203 /* To optimize the deletion process of a long FAT chain, the deletion is done in sessions. During one session,
204 a set of FAT entries are removed. If one session is interrupted, after restart the deletion process resumes and
205 picks up from where it left.
206
207 During one deletion session, all FAT entries are between head_cluster(inclusive) and next_session (exclusive).
208 */
209 4714014 next_session = _fx_utility_32_unsigned_read((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_next_deletion);
210
211 /* Loop to cleanup all FAT entries. */
212
4/4
✓ Branch 57 → 58 taken 4735820 times.
✓ Branch 57 → 59 taken 4713888 times.
✓ Branch 58 → 11 taken 4735812 times.
✓ Branch 58 → 59 taken 8 times.
9449708 while ((head_cluster >= FX_FAT_ENTRY_START) && (head_cluster < media_ptr -> fx_media_fat_reserved))
213 {
214
215 /* Initialize. */
216 4735812 current_cluster = head_cluster;
217 4735812 cache_count = 0;
218
219 /* Loop from head cluster to find entries to cleanup and store this information into cache. */
220 do
221 {
222
223 /* Get the next FAT entry. */
224 37509589 status = _fx_utility_FAT_entry_read(media_ptr, current_cluster, &next_cluster);
225
2/2
✓ Branch 13 → 14 taken 8 times.
✓ Branch 13 → 15 taken 37509581 times.
37509589 if (status != FX_SUCCESS)
226 {
227
228 /* Return the error status. */
229 8 return(status);
230 }
231
232 /* Whether or not the cluster is occupied. */
233
2/2
✓ Branch 15 → 16 taken 130 times.
✓ Branch 15 → 17 taken 37509451 times.
37509581 if (next_cluster == FX_FREE_CLUSTER)
234 {
235
236 /* Current cluster has already been released. */
237 130 break;
238 }
239
240 /* Cache the FAT list. */
241 37509451 cache_ptr[cache_count++] = current_cluster;
242
243 /* Check whether FAT entry spans multiple sectors. */
244
2/2
✓ Branch 18 → 19 taken 200 times.
✓ Branch 18 → 24 taken 37509251 times.
37509451 if (_fx_utility_FAT_entry_multiple_sectors_check(media_ptr, current_cluster))
245 {
246
4/4
✓ Branch 19 → 20 taken 20 times.
✓ Branch 19 → 21 taken 180 times.
✓ Branch 20 → 21 taken 16 times.
✓ Branch 20 → 23 taken 4 times.
200 if (head_cluster == next_session || next_session == FX_FREE_CLUSTER)
247 {
248 /* Do not start another session if this is the end of the chain. */
249
1/2
✓ Branch 21 → 22 taken 196 times.
✗ Branch 21 → 23 not taken.
196 if (next_cluster != tail_cluster)
250 {
251 196 next_session = next_cluster;
252 }
253 }
254 200 break;
255 }
256
257 /* Move to next cluster. */
258 37509251 current_cluster = next_cluster;
259 75018498 } while ((next_cluster >= FX_FAT_ENTRY_START) &&
260
2/2
✓ Branch 25 → 26 taken 33553805 times.
✓ Branch 25 → 29 taken 3955442 times.
37509247 (next_cluster < media_ptr -> fx_media_fat_reserved) &&
261
6/6
✓ Branch 24 → 25 taken 37509247 times.
✓ Branch 24 → 29 taken 4 times.
✓ Branch 26 → 27 taken 32795381 times.
✓ Branch 26 → 29 taken 758424 times.
✓ Branch 27 → 28 taken 32773777 times.
✓ Branch 27 → 29 taken 21604 times.
71063056 (next_cluster != tail_cluster) &&
262 (cache_count < cache_max));
263
264 /* Get next session. */
265
2/2
✓ Branch 29 → 30 taken 21604 times.
✓ Branch 29 → 32 taken 4714200 times.
4735804 if (cache_count == cache_max)
266 {
267 /* Do not start another session if this is the end of the chain. */
268
1/2
✓ Branch 30 → 31 taken 21604 times.
✗ Branch 30 → 32 not taken.
21604 if (next_cluster != tail_cluster)
269 {
270 21604 next_session = next_cluster;
271 }
272 }
273
274 /* Update head cluster and next session into log file. */
275 4735804 _fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_next_deletion, next_session);
276
2/2
✓ Branch 33 → 34 taken 14942 times.
✓ Branch 33 → 35 taken 4720862 times.
4735804 if (operation == FX_FAULT_TOLERANT_FAT_CHAIN_RECOVER)
277 {
278 14942 _fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_new, head_cluster);
279 }
280 else
281 {
282 4720862 _fx_utility_32_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_head_original, head_cluster);
283 }
284
285 /* Update checksum. */
286 4735804 _fx_utility_16_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_checksumm, 0);
287 4735804 checksum = _fx_fault_tolerant_calculate_checksum((UCHAR *)FAT_chain, FX_FAULT_TOLERANT_FAT_CHAIN_SIZE);
288 4735804 _fx_utility_16_unsigned_write((UCHAR *)&FAT_chain -> fx_fault_tolerant_FAT_chain_checksumm, checksum);
289
290 /* Flush the fault tolerant log into the file system. */
291 4735804 _fx_fault_tolerant_write_log_file(media_ptr, 0);
292
293 /* Loop to free FAT in cache from back to front. */
294
2/2
✓ Branch 40 → 41 taken 4735690 times.
✓ Branch 40 → 53 taken 114 times.
4735804 if (cache_count > 0)
295 {
296
297 /* Get sector of last FAT entry. */
298 4735690 last_FAT_sector = _fx_utility_FAT_sector_get(media_ptr, cache_ptr[cache_count - 1]);
299 4735690 i = cache_count;
300
2/2
✓ Branch 51 → 43 taken 37508959 times.
✓ Branch 51 → 52 taken 4735674 times.
42244633 while (i > 0)
301 {
302 37508959 i--;
303
304 /* Get sector of current FAT entry. */
305 37508959 FAT_sector = _fx_utility_FAT_sector_get(media_ptr, cache_ptr[i]);
306
2/2
✓ Branch 44 → 45 taken 141771 times.
✓ Branch 44 → 47 taken 37367188 times.
37508959 if (FAT_sector != last_FAT_sector)
307 {
308
309 /* Current FAT entry is located in different sector. Force flush. */
310 /* Flush the cached individual FAT entries */
311 141771 _fx_utility_FAT_flush(media_ptr);
312
313 /* Update sector of current FAT entry. */
314 141763 last_FAT_sector = FAT_sector;
315 }
316
317 /* Free current_cluster. */
318 37508951 status = _fx_utility_FAT_entry_write(media_ptr, cache_ptr[i], FX_FREE_CLUSTER);
319
2/2
✓ Branch 48 → 49 taken 8 times.
✓ Branch 48 → 50 taken 37508943 times.
37508951 if (status != FX_SUCCESS)
320 {
321
322 /* Return the error status. */
323 8 return(status);
324 }
325
326 }
327
328 /* Increase the available clusters in the media control block. */
329 4735674 media_ptr -> fx_media_available_clusters += cache_count;
330 }
331
332 /* Flush the cached individual FAT entries */
333 4735788 _fx_utility_FAT_flush(media_ptr);
334
335
336 /* Get head cluster. */
337
2/2
✓ Branch 54 → 55 taken 44 times.
✓ Branch 54 → 56 taken 4735694 times.
4735738 if (head_cluster == next_session)
338 {
339 44 break;
340 }
341 4735694 head_cluster = next_session;
342 }
343
344 4713940 return(FX_SUCCESS);
345 }
346 #endif /* FX_ENABLE_FAULT_TOLERANT */
347