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 |