fx_media_flush.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 | /** Media */ | ||
| 19 | /** */ | ||
| 20 | /**************************************************************************/ | ||
| 21 | /**************************************************************************/ | ||
| 22 | |||
| 23 | #define FX_SOURCE_CODE | ||
| 24 | |||
| 25 | |||
| 26 | /* Include necessary system files. */ | ||
| 27 | |||
| 28 | #include "fx_api.h" | ||
| 29 | #include "fx_system.h" | ||
| 30 | #include "fx_media.h" | ||
| 31 | #include "fx_file.h" | ||
| 32 | #include "fx_directory.h" | ||
| 33 | #include "fx_utility.h" | ||
| 34 | |||
| 35 | |||
| 36 | /**************************************************************************/ | ||
| 37 | /* */ | ||
| 38 | /* FUNCTION RELEASE */ | ||
| 39 | /* */ | ||
| 40 | /* _fx_media_flush PORTABLE C */ | ||
| 41 | /* 6.1 */ | ||
| 42 | /* AUTHOR */ | ||
| 43 | /* */ | ||
| 44 | /* William E. Lamie, Microsoft Corporation */ | ||
| 45 | /* */ | ||
| 46 | /* DESCRIPTION */ | ||
| 47 | /* */ | ||
| 48 | /* This function examines the list of open files for this media and */ | ||
| 49 | /* "flushes" each written open file to the underlying media. After */ | ||
| 50 | /* the open files have been flushed, the internal logical sector is */ | ||
| 51 | /* flushed. Finally, the attached driver is sent a flush command so */ | ||
| 52 | /* that it can flush its sector cache (if any) to the media. */ | ||
| 53 | /* */ | ||
| 54 | /* INPUT */ | ||
| 55 | /* */ | ||
| 56 | /* media_ptr Media control block pointer */ | ||
| 57 | /* */ | ||
| 58 | /* OUTPUT */ | ||
| 59 | /* */ | ||
| 60 | /* return status */ | ||
| 61 | /* */ | ||
| 62 | /* CALLS */ | ||
| 63 | /* */ | ||
| 64 | /* _fx_directory_entry_write Write the directory entry */ | ||
| 65 | /* _fx_utility_FAT_flush Flush cached FAT entries */ | ||
| 66 | /* _fx_utility_FAT_map_flush Flush primary FAT changes to */ | ||
| 67 | /* secondary FAT(s) */ | ||
| 68 | /* _fx_utility_logical_sector_flush Flush logical sector cache */ | ||
| 69 | /* _fx_utility_32_unsigned_read Read 32-bit unsigned */ | ||
| 70 | /* _fx_utility_32_unsigned_write Write 32-bit unsigned */ | ||
| 71 | /* */ | ||
| 72 | /* CALLED BY */ | ||
| 73 | /* */ | ||
| 74 | /* Application Code */ | ||
| 75 | /* */ | ||
| 76 | /**************************************************************************/ | ||
| 77 | 366186 | UINT _fx_media_flush(FX_MEDIA *media_ptr) | |
| 78 | { | ||
| 79 | |||
| 80 | UINT status; | ||
| 81 | ULONG open_count; | ||
| 82 | FX_FILE *file_ptr; | ||
| 83 | FX_INT_SAVE_AREA | ||
| 84 | |||
| 85 | |||
| 86 | #ifndef FX_MEDIA_STATISTICS_DISABLE | ||
| 87 | |||
| 88 | /* Increment the number of times this service has been called. */ | ||
| 89 | 366186 | media_ptr -> fx_media_flushes++; | |
| 90 | #endif | ||
| 91 | |||
| 92 | /* Check the media to make sure it is open. */ | ||
| 93 |
2/2✓ Branch 2 → 3 taken 9 times.
✓ Branch 2 → 4 taken 366177 times.
|
366186 | if (media_ptr -> fx_media_id != FX_MEDIA_ID) |
| 94 | { | ||
| 95 | |||
| 96 | /* Return the media not opened error. */ | ||
| 97 | 9 | return(FX_MEDIA_NOT_OPEN); | |
| 98 | } | ||
| 99 | |||
| 100 | /* If trace is enabled, insert this event into the trace buffer. */ | ||
| 101 | FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_FLUSH, media_ptr, 0, 0, 0, FX_TRACE_MEDIA_EVENTS, 0, 0) | ||
| 102 | |||
| 103 | /* Protect against other threads accessing the media. */ | ||
| 104 | 199598 | FX_PROTECT | |
| 105 | |||
| 106 | /* Check for write protect at the media level (set by driver). */ | ||
| 107 |
4/4✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 6 taken 166575 times.
✓ Branch 5 → 6 taken 5 times.
✓ Branch 5 → 8 taken 199593 times.
|
366177 | if (media_ptr -> fx_media_driver_write_protect) |
| 108 | { | ||
| 109 | |||
| 110 | /* Release media protection. */ | ||
| 111 | 5 | FX_UNPROTECT | |
| 112 | |||
| 113 | /* Return write protect error. */ | ||
| 114 | 9 | return(FX_WRITE_PROTECT); | |
| 115 | } | ||
| 116 | |||
| 117 | /* Loop through the media's open files. */ | ||
| 118 | 366168 | open_count = media_ptr -> fx_media_opened_file_count; | |
| 119 | 366168 | file_ptr = media_ptr -> fx_media_opened_file_list; | |
| 120 |
4/4✓ Branch 14 → 7 taken 502615 times.
✓ Branch 14 → 15 taken 166570 times.
✓ Branch 19 → 9 taken 593747 times.
✓ Branch 19 → 20 taken 199587 times.
|
1462519 | while (open_count) |
| 121 | { | ||
| 122 | |||
| 123 | /* Look at each opened file to see if the same file is opened | ||
| 124 | for writing and has been written to. */ | ||
| 125 |
4/4✓ Branch 7 → 8 taken 291367 times.
✓ Branch 7 → 13 taken 211248 times.
✓ Branch 9 → 10 taken 346948 times.
✓ Branch 9 → 18 taken 246799 times.
|
1096362 | if ((file_ptr -> fx_file_open_mode == FX_OPEN_FOR_WRITE) && |
| 126 |
4/4✓ Branch 8 → 9 taken 94527 times.
✓ Branch 8 → 13 taken 196840 times.
✓ Branch 10 → 11 taken 115426 times.
✓ Branch 10 → 18 taken 231522 times.
|
638315 | (file_ptr -> fx_file_modified)) |
| 127 | { | ||
| 128 | |||
| 129 | /* Protect against update. */ | ||
| 130 | 115426 | FX_DISABLE_INTS | |
| 131 | |||
| 132 | /* Set the new time and date. */ | ||
| 133 | 209953 | file_ptr -> fx_file_dir_entry.fx_dir_entry_time = _fx_system_time; | |
| 134 | 209953 | file_ptr -> fx_file_dir_entry.fx_dir_entry_date = _fx_system_date; | |
| 135 | |||
| 136 | /* Restore interrupts. */ | ||
| 137 | 115426 | FX_RESTORE_INTS | |
| 138 | |||
| 139 | /* Copy the new file size into the directory entry. */ | ||
| 140 | 209953 | file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size = | |
| 141 | 209953 | file_ptr -> fx_file_current_file_size; | |
| 142 | |||
| 143 | /* Write the directory entry to the media. */ | ||
| 144 | 209953 | status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry)); | |
| 145 | |||
| 146 | /* Check for a good status. */ | ||
| 147 |
4/4✓ Branch 10 → 11 taken 5 times.
✓ Branch 10 → 12 taken 94522 times.
✓ Branch 14 → 15 taken 6 times.
✓ Branch 14 → 17 taken 115420 times.
|
209953 | if (status != FX_SUCCESS) |
| 148 | { | ||
| 149 | |||
| 150 | /* Release media protection. */ | ||
| 151 | 6 | FX_UNPROTECT | |
| 152 | |||
| 153 | /* Error writing the directory. */ | ||
| 154 | 11 | return(status); | |
| 155 | } | ||
| 156 | |||
| 157 | /* Clear the file modified flag. */ | ||
| 158 | 209942 | file_ptr -> fx_file_modified = FX_FALSE; | |
| 159 | } | ||
| 160 | |||
| 161 | /* Adjust the pointer and decrement the opened count. */ | ||
| 162 | 1096351 | file_ptr = file_ptr -> fx_file_opened_next; | |
| 163 | 1096351 | open_count--; | |
| 164 | } | ||
| 165 | |||
| 166 | /* Flush the cached individual FAT entries */ | ||
| 167 | 366157 | _fx_utility_FAT_flush(media_ptr); | |
| 168 | |||
| 169 | /* Flush changed sector(s) in the primary FAT to secondary FATs. */ | ||
| 170 | 366157 | _fx_utility_FAT_map_flush(media_ptr); | |
| 171 | |||
| 172 | |||
| 173 | /* Flush the internal logical sector cache. */ | ||
| 174 | 366157 | status = _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_total_sectors), FX_FALSE); | |
| 175 | |||
| 176 | /* Check for a good status. */ | ||
| 177 |
4/4✓ Branch 18 → 19 taken 2 times.
✓ Branch 18 → 20 taken 166568 times.
✓ Branch 23 → 24 taken 3 times.
✓ Branch 23 → 26 taken 199584 times.
|
366157 | if (status != FX_SUCCESS) |
| 178 | { | ||
| 179 | |||
| 180 | /* Release media protection. */ | ||
| 181 | 3 | FX_UNPROTECT | |
| 182 | |||
| 183 | /* Error writing the directory. */ | ||
| 184 | 5 | return(status); | |
| 185 | } | ||
| 186 | |||
| 187 | /* Determine if the media needs to have the additional information sector updated. This will | ||
| 188 | only be the case for 32-bit FATs. The logic here only needs to be done if the last reported | ||
| 189 | available cluster count is different that the currently available clusters. */ | ||
| 190 |
4/4✓ Branch 20 → 21 taken 4110 times.
✓ Branch 20 → 35 taken 162458 times.
✓ Branch 26 → 27 taken 5137 times.
✓ Branch 26 → 43 taken 194447 times.
|
366152 | if ((media_ptr -> fx_media_FAT32_additional_info_sector) && |
| 191 |
4/4✓ Branch 21 → 22 taken 4034 times.
✓ Branch 21 → 35 taken 76 times.
✓ Branch 27 → 28 taken 5042 times.
✓ Branch 27 → 43 taken 95 times.
|
9247 | (media_ptr -> fx_media_FAT32_additional_info_last_available != media_ptr -> fx_media_available_clusters)) |
| 192 | { | ||
| 193 | |||
| 194 | UCHAR *buffer_ptr; | ||
| 195 | ULONG signature; | ||
| 196 | |||
| 197 | #ifndef FX_DISABLE_CACHE | ||
| 198 | |||
| 199 | /* Setup a pointer to the first cached entry's buffer. */ | ||
| 200 | 5042 | buffer_ptr = (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_memory_buffer; | |
| 201 | |||
| 202 | /* Invalidate this cache entry. */ | ||
| 203 | 5042 | (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector = (~(ULONG64)0); | |
| 204 | 5042 | (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_valid = FX_FALSE; | |
| 205 | #else | ||
| 206 | 4034 | buffer_ptr = media_ptr -> fx_media_memory_buffer; | |
| 207 | #endif /* FX_DISABLE_CACHE */ | ||
| 208 | |||
| 209 | /* Read the FAT32 additional information sector from the device. */ | ||
| 210 | 9076 | media_ptr -> fx_media_driver_request = FX_DRIVER_READ; | |
| 211 | 9076 | media_ptr -> fx_media_driver_status = FX_IO_ERROR; | |
| 212 | 9076 | media_ptr -> fx_media_driver_buffer = buffer_ptr; | |
| 213 | 9076 | media_ptr -> fx_media_driver_logical_sector = media_ptr -> fx_media_FAT32_additional_info_sector; | |
| 214 | 9076 | media_ptr -> fx_media_driver_sectors = 1; | |
| 215 | 9076 | media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR; | |
| 216 | |||
| 217 | #ifndef FX_MEDIA_STATISTICS_DISABLE | ||
| 218 | |||
| 219 | /* Increment the number of driver read sector(s) requests. */ | ||
| 220 | 9076 | media_ptr -> fx_media_driver_read_requests++; | |
| 221 | #endif | ||
| 222 | |||
| 223 | /* If trace is enabled, insert this event into the trace buffer. */ | ||
| 224 | FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_READ, media_ptr, media_ptr -> fx_media_FAT32_additional_info_sector, 1, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0) | ||
| 225 | |||
| 226 | /* Invoke the driver to read the FAT32 additional information sector. */ | ||
| 227 | 9076 | (media_ptr -> fx_media_driver_entry) (media_ptr); | |
| 228 | |||
| 229 | /* Determine if the FAT32 sector was read correctly. */ | ||
| 230 |
4/4✓ Branch 23 → 24 taken 820 times.
✓ Branch 23 → 25 taken 3214 times.
✓ Branch 29 → 30 taken 1025 times.
✓ Branch 29 → 32 taken 4017 times.
|
9076 | if (media_ptr -> fx_media_driver_status != FX_SUCCESS) |
| 231 | { | ||
| 232 | |||
| 233 | /* Release media protection. */ | ||
| 234 | 1025 | FX_UNPROTECT | |
| 235 | |||
| 236 | /* Return the error status. */ | ||
| 237 | 1845 | return(FX_IO_ERROR); | |
| 238 | } | ||
| 239 | |||
| 240 | /* Setup a pointer into the FAT32 additional information sector. */ | ||
| 241 | 7231 | buffer_ptr = media_ptr -> fx_media_driver_buffer; | |
| 242 | |||
| 243 | /* Pickup the first signature long word. */ | ||
| 244 | 7231 | signature = _fx_utility_32_unsigned_read(&buffer_ptr[0]); | |
| 245 | |||
| 246 | /* Determine if the signature is correct. */ | ||
| 247 |
4/4✓ Branch 26 → 27 taken 3206 times.
✓ Branch 26 → 35 taken 8 times.
✓ Branch 33 → 34 taken 4007 times.
✓ Branch 33 → 43 taken 10 times.
|
7231 | if (signature == 0x41615252) |
| 248 | { | ||
| 249 | |||
| 250 | /* Yes, the first signature is correct, now pickup the next signature. */ | ||
| 251 | 7213 | signature = _fx_utility_32_unsigned_read(&buffer_ptr[484]); | |
| 252 | |||
| 253 | /* Determine if this signature is correct. */ | ||
| 254 |
4/4✓ Branch 28 → 29 taken 3202 times.
✓ Branch 28 → 35 taken 4 times.
✓ Branch 35 → 36 taken 4002 times.
✓ Branch 35 → 43 taken 5 times.
|
7213 | if (signature == 0x61417272) |
| 255 | { | ||
| 256 | |||
| 257 | /* Yes, we have a good FAT32 additional information sector. */ | ||
| 258 | |||
| 259 | /* Set the free cluster count to the available clusters in the media control block. */ | ||
| 260 | 7204 | _fx_utility_32_unsigned_write(&buffer_ptr[488], media_ptr -> fx_media_available_clusters); | |
| 261 | |||
| 262 | /* Set the next free cluster number hint to starting search cluster in the media control block. */ | ||
| 263 | 7204 | _fx_utility_32_unsigned_write(&buffer_ptr[492], media_ptr -> fx_media_cluster_search_start); | |
| 264 | |||
| 265 | /* Now write the sector back out to the media. */ | ||
| 266 | 7204 | media_ptr -> fx_media_driver_request = FX_DRIVER_WRITE; | |
| 267 | 7204 | media_ptr -> fx_media_driver_status = FX_IO_ERROR; | |
| 268 | 7204 | media_ptr -> fx_media_driver_buffer = buffer_ptr; | |
| 269 | 7204 | media_ptr -> fx_media_driver_logical_sector = media_ptr -> fx_media_FAT32_additional_info_sector; | |
| 270 | 7204 | media_ptr -> fx_media_driver_sectors = 1; | |
| 271 | 7204 | media_ptr -> fx_media_driver_sector_type = FX_DIRECTORY_SECTOR; | |
| 272 | |||
| 273 | /* Set the system write flag since we are writing a directory sector. */ | ||
| 274 | 7204 | media_ptr -> fx_media_driver_system_write = FX_TRUE; | |
| 275 | |||
| 276 | #ifndef FX_MEDIA_STATISTICS_DISABLE | ||
| 277 | |||
| 278 | /* Increment the number of driver write sector(s) requests. */ | ||
| 279 | 7204 | media_ptr -> fx_media_driver_write_requests++; | |
| 280 | #endif | ||
| 281 | |||
| 282 | /* If trace is enabled, insert this event into the trace buffer. */ | ||
| 283 | FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, media_ptr -> fx_media_FAT32_additional_info_sector, 1, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0) | ||
| 284 | |||
| 285 | /* Invoke the driver to write the FAT32 additional information sector. */ | ||
| 286 | 7204 | (media_ptr -> fx_media_driver_entry) (media_ptr); | |
| 287 | |||
| 288 | /* Clear the system write flag. */ | ||
| 289 | 7204 | media_ptr -> fx_media_driver_system_write = FX_FALSE; | |
| 290 | |||
| 291 | /* Determine if the FAT32 sector was written correctly. */ | ||
| 292 |
4/4✓ Branch 32 → 33 taken 360 times.
✓ Branch 32 → 34 taken 2842 times.
✓ Branch 39 → 40 taken 450 times.
✓ Branch 39 → 42 taken 3552 times.
|
7204 | if (media_ptr -> fx_media_driver_status != FX_SUCCESS) |
| 293 | { | ||
| 294 | |||
| 295 | /* Release media protection. */ | ||
| 296 | 450 | FX_UNPROTECT | |
| 297 | |||
| 298 | /* Return the sector IO error status. */ | ||
| 299 | 810 | return(FX_IO_ERROR); | |
| 300 | } | ||
| 301 | |||
| 302 | /* Successful update of the FAT32 additional information sector. Update the | ||
| 303 | last written available cluster count. */ | ||
| 304 | 6394 | media_ptr -> fx_media_FAT32_additional_info_last_available = media_ptr -> fx_media_available_clusters; | |
| 305 | } | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | #ifndef FX_MEDIA_STATISTICS_DISABLE | ||
| 310 | |||
| 311 | /* Increment the number of driver flush requests. */ | ||
| 312 | 363497 | media_ptr -> fx_media_driver_flush_requests++; | |
| 313 | #endif | ||
| 314 | |||
| 315 | /* Build the "flush" I/O driver request. */ | ||
| 316 | 363497 | media_ptr -> fx_media_driver_request = FX_DRIVER_FLUSH; | |
| 317 | 363497 | media_ptr -> fx_media_driver_status = FX_IO_ERROR; | |
| 318 | |||
| 319 | /* If trace is enabled, insert this event into the trace buffer. */ | ||
| 320 | FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_FLUSH, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0) | ||
| 321 | |||
| 322 | /* Call the specified I/O driver with the flush request. */ | ||
| 323 | 363497 | (media_ptr -> fx_media_driver_entry) (media_ptr); | |
| 324 | |||
| 325 | /* Determine if the I/O driver flushed successfully. */ | ||
| 326 |
4/4✓ Branch 36 → 37 taken 400 times.
✓ Branch 36 → 38 taken 164988 times.
✓ Branch 44 → 45 taken 500 times.
✓ Branch 44 → 47 taken 197609 times.
|
363497 | if (media_ptr -> fx_media_driver_status != FX_SUCCESS) |
| 327 | { | ||
| 328 | |||
| 329 | /* Release media protection. */ | ||
| 330 | 500 | FX_UNPROTECT | |
| 331 | |||
| 332 | /* Return the driver error status. */ | ||
| 333 | 900 | return(FX_IO_ERROR); | |
| 334 | } | ||
| 335 | |||
| 336 | /* Release media protection. */ | ||
| 337 | 197609 | FX_UNPROTECT | |
| 338 | |||
| 339 | /* If we get here, return successful status to the caller. */ | ||
| 340 | 362597 | return(FX_SUCCESS); | |
| 341 | } | ||
| 342 | |||
| 343 |