GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_utility_logical_sector_flush.c Lines: 108 108 100.0 %
Date: 2026-03-06 18:49:02 Branches: 88 88 100.0 %

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
/**   Utility                                                             */
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_utility.h"
31
32
33
/**************************************************************************/
34
/*                                                                        */
35
/*  FUNCTION                                               RELEASE        */
36
/*                                                                        */
37
/*    _fx_utility_logical_sector_flush                    PORTABLE C      */
38
/*                                                           6.1.10       */
39
/*  AUTHOR                                                                */
40
/*                                                                        */
41
/*    William E. Lamie, Microsoft Corporation                             */
42
/*                                                                        */
43
/*  DESCRIPTION                                                           */
44
/*                                                                        */
45
/*    This function handles logical sector flush requests for all FileX   */
46
/*    components. It will process all dirty logical sectors in the        */
47
/*    logical sector cache within the range specified. This function      */
48
/*    optionally invalidates sectors.                                     */
49
/*                                                                        */
50
/*  INPUT                                                                 */
51
/*                                                                        */
52
/*    media_ptr                             Media control block pointer   */
53
/*    starting_sector                       Starting sector number        */
54
/*    sectors                               Number of sectors             */
55
/*    invalidate                            Invalidate flag               */
56
/*                                            (FX_TRUE -> invalidate)     */
57
/*                                                                        */
58
/*  OUTPUT                                                                */
59
/*                                                                        */
60
/*    return status                                                       */
61
/*                                                                        */
62
/*  CALLS                                                                 */
63
/*                                                                        */
64
/*    I/O Driver                                                          */
65
/*                                                                        */
66
/*  CALLED BY                                                             */
67
/*                                                                        */
68
/*    FileX System Functions                                              */
69
/*                                                                        */
70
/**************************************************************************/
71
4921077
UINT  _fx_utility_logical_sector_flush(FX_MEDIA *media_ptr, ULONG64 starting_sector, ULONG64 sectors, UINT invalidate)
72
{
73
74
#ifndef FX_DISABLE_CACHE
75
FX_CACHED_SECTOR *cache_entry;
76
UINT              cache_size;
77
UINT              i, bit_set, use_starting_sector;
78
ULONG             index;
79
ULONG             remaining_valid;
80
ULONG             remaining_dirty;
81
ULONG64           ending_sector;
82
ULONG             valid_bit_map;
83
84
85
/* Extended port-specific processing macro, which is by default defined to white space.  */
86

4921077
FX_UTILITY_LOGICAL_SECTOR_FLUSH_EXTENSION
87
88
/* Calculate the ending sector.  */
89
4921075
                  ending_sector =  starting_sector + sectors - 1;
90
91
    /* Pickup the number of dirty sectors currently in the cache.  */
92
4921075
    remaining_dirty =  media_ptr -> fx_media_sector_cache_dirty_count;
93
94
    /* If trace is enabled, insert this event into the trace buffer.  */
95
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_MEDIA_FLUSH, media_ptr, media_ptr -> fx_media_sector_cache_dirty_count, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
96
97
    /* Determine what type of cache configuration we have.  */
98
4921075
    if (media_ptr -> fx_media_sector_cache_hashed == FX_FALSE)
99
    {
100
101
        /* Linear cache present, simply walk through the search list until
102
           an unused cache entry is present.  */
103
104
        /* Flush and invalidate the internal logical sector cache.  */
105
4572446
        cache_size =            media_ptr -> fx_media_sector_cache_size;
106
4572446
        cache_entry =           media_ptr -> fx_media_sector_cache_list_ptr;
107
108
        /* Look at the cache entries that have been written to.  */
109

9133941
        while ((cache_size--) && (cache_entry -> fx_cached_sector))
110
        {
111
112
            /* Determine if invalidation is not required and there are no
113
               more dirty sectors. */
114

4595678
            if ((remaining_dirty == 0) && (invalidate == FX_FALSE))
115
            {
116
117
                /* Yes, nothing left to do.  */
118
14546
                break;
119
            }
120
121
            /* Determine if there are any more sectors to process.  */
122
4581132
            if (sectors == 0)
123
            {
124
125
                /* No more sectors required to process.  */
126
130
                break;
127
            }
128
129
            /* Determine if this cached sector is within the specified range and is valid.  */
130
4581002
            if ((cache_entry -> fx_cached_sector_valid) &&
131
1020587
                (cache_entry -> fx_cached_sector >= starting_sector) &&
132
985809
                (cache_entry -> fx_cached_sector <= ending_sector))
133
            {
134
135
                /* Yes, the cache entry is valid and within the specified range. Determine if
136
                   the requested sector has been written to.  */
137
974058
                if (cache_entry -> fx_cached_sector_buffer_dirty)
138
                {
139
140
                    /* Yes, write the cached sector out to the media.  */
141
142
                    /* Check for write protect at the media level (set by driver).  */
143
84232
                    if (media_ptr -> fx_media_driver_write_protect == FX_FALSE)
144
                    {
145
146
#ifndef FX_MEDIA_STATISTICS_DISABLE
147
148
                        /* Increment the number of driver write sector(s) requests.  */
149
83977
                        media_ptr -> fx_media_driver_write_requests++;
150
#endif
151
152
                        /* Build write request to the driver.  */
153
83977
                        media_ptr -> fx_media_driver_request =          FX_DRIVER_WRITE;
154
83977
                        media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
155
83977
                        media_ptr -> fx_media_driver_buffer =           cache_entry -> fx_cached_sector_memory_buffer;
156
#ifdef FX_DRIVER_USE_64BIT_LBA
157
                        media_ptr -> fx_media_driver_logical_sector =   cache_entry -> fx_cached_sector;
158
#else
159
83977
                        media_ptr -> fx_media_driver_logical_sector =   (ULONG)cache_entry -> fx_cached_sector;
160
#endif
161
83977
                        media_ptr -> fx_media_driver_sectors =          1;
162
83977
                        media_ptr -> fx_media_driver_sector_type =      cache_entry -> fx_cached_sector_type;
163
164
                        /* Sectors other than FX_DATA_SECTOR will never be dirty when FX_FAULT_TOLERANT is defined. */
165
#ifndef FX_FAULT_TOLERANT
166
                        /* Determine if the system write flag needs to be set.  */
167
83977
                        if (cache_entry -> fx_cached_sector_type != FX_DATA_SECTOR)
168
                        {
169
170
                            /* Yes, a system sector write is present so set the flag.  The driver
171
                               can use this flag to make extra safeguards in writing the sector
172
                               out, yielding more fault tolerance.  */
173
83244
                            media_ptr -> fx_media_driver_system_write =  FX_TRUE;
174
                        }
175
#endif /* FX_FAULT_TOLERANT */
176
177
                        /* If trace is enabled, insert this event into the trace buffer.  */
178
                        FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, cache_entry -> fx_cached_sector, 1, cache_entry -> fx_cached_sector_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
179
180
                        /* Invoke the driver to write the sector.  */
181
83977
                        (media_ptr -> fx_media_driver_entry) (media_ptr);
182
183
                        /* Clear the system write flag.  */
184
83977
                        media_ptr -> fx_media_driver_system_write =  FX_FALSE;
185
186
                        /* Check for successful completion.  */
187
83977
                        if (media_ptr -> fx_media_driver_status)
188
                        {
189
190
                            /* Error writing a cached sector out.  Return the
191
                               error status.  */
192
19507
                            return(media_ptr -> fx_media_driver_status);
193
                        }
194
195
                        /* Clear the buffer dirty flag since it has been flushed
196
                           out.  */
197
64470
                        cache_entry -> fx_cached_sector_buffer_dirty =  FX_FALSE;
198
199
                        /* Decrement the number of dirty sectors currently in the cache.  */
200
64470
                        media_ptr -> fx_media_sector_cache_dirty_count--;
201
64470
                        remaining_dirty--;
202
                    }
203
                }
204
205
                /* Determine if the invalidate option is specified.  */
206
954551
                if (invalidate)
207
                {
208
209
                    /* Invalidate the cache entry.  */
210
949378
                    cache_entry -> fx_cached_sector_valid =  FX_FALSE;
211
212
                    /* Place all ones in the sector number.  */
213
949378
                    cache_entry -> fx_cached_sector =  (~(ULONG64)0);
214
215
                    /* Determine if this sector is still dirty, this could be the case if
216
                       write protection was turned on.  */
217
949378
                    if (cache_entry -> fx_cached_sector_buffer_dirty)
218
                    {
219
220
                        /* Yes, clear the dirty flag.  */
221
255
                        cache_entry -> fx_cached_sector_buffer_dirty =  FX_FALSE;
222
223
                        /* Decrement the number of dirty sectors currently in the cache.  */
224
255
                        media_ptr -> fx_media_sector_cache_dirty_count--;
225
255
                        remaining_dirty--;
226
                    }
227
                }
228
229
                /* Decrement the number of sectors in the range that have been processed.  */
230
954551
                sectors--;
231
            }
232
233
            /* Move to the next entry in the sector cache.  */
234
4561495
            cache_entry =  cache_entry -> fx_cached_sector_next_used;
235
        }
236
    }
237
    else
238
    {
239
240
        /* Hashed cache is present. Pickup the cache size.  */
241
348629
        cache_size =            media_ptr -> fx_media_sector_cache_size;
242
243
        /* Initialize the loop control parameters.  */
244
348629
        bit_set =  0;
245
348629
        valid_bit_map =  media_ptr -> fx_media_sector_cache_hashed_sector_valid;
246
247
        /* Determine how to process the hashed cache based on the number of sectors
248
           to process. If the sequential sector range is less than the bit map size,
249
           simply use the starting sector to derive the index into the cache.  */
250
348629
        if (sectors < 32)
251
        {
252
14673
            use_starting_sector =  FX_TRUE;
253
        }
254
        else
255
        {
256
333956
            use_starting_sector =  FX_FALSE;
257
        }
258
259
        /* Determine if there is anything valid in the cache.  */
260
8306440
        while (valid_bit_map)
261
        {
262
263
            /* Determine if invalidation is not required and there are no
264
               more dirty sectors. */
265

7976120
            if ((remaining_dirty == 0) && (invalidate == FX_FALSE))
266
            {
267
268
                /* Yes, nothing left to do.  */
269
4062
                break;
270
            }
271
272
            /* Determine if there are any more sectors to process.  */
273

7972058
            if ((sectors == 0) || (starting_sector > ending_sector))
274
            {
275
276
                /* No more sectors required to process.  */
277
                break;
278
            }
279
280
            /* Determine how to compute the hash index.  */
281
7957814
            if (use_starting_sector)
282
            {
283
284
                /* Calculate the hash value of this sector using the lower bits.  */
285
18480
                index =  (ULONG)(starting_sector & media_ptr -> fx_media_sector_cache_hash_mask);
286
287
                /* Calculate the bit set indicating there is one or more valid sectors at this cache index.  */
288
18480
                bit_set =  (index % 32);
289
290
                /* Compute the actual array index by multiplying by the cache depth.  */
291
18480
                index =  (bit_set * FX_SECTOR_CACHE_DEPTH);
292
            }
293
            else
294
            {
295
296
                /* Walk the bit map to find the next valid entry.  */
297
298
                /* Find the next set bit.  */
299
10367994
                while ((valid_bit_map & 1) == 0)
300
                {
301
302
                    /* Otherwise, shift down the bit in the bit map.  */
303
2428660
                    valid_bit_map =  valid_bit_map >> 1;
304
305
                    /* Increment the set bit marker.  */
306
2428660
                    bit_set++;
307
                }
308
309
                /* Compute the first actual index into the hashed cache.  */
310
7939334
                index =  (bit_set * FX_SECTOR_CACHE_DEPTH);
311
            }
312
313
            /* At this point, bit_set represents the next group of hashed sectors that could
314
               have valid cache entries and index represents the index into the sector cache
315
               of that sector group.  */
316
317
            /* Clear the remaining valid sectors for this entry in the bit map.  */
318
7957814
            remaining_valid =  0;
319
320
            /* Loop to check the corresponding hash entries.  */
321
            do
322
            {
323
324
                /* Setup pointer to the cache entry.  */
325
15758544
                cache_entry =  &(media_ptr -> fx_media_sector_cache[index]);
326
327
                /* Loop to examine the full depth of the hashed cache.  */
328
78745050
                for (i = 0; i < 4; i++)
329
                {
330
331
                    /* Determine if this cached sector is within the specified range and is valid.  */
332
62998753
                    if ((cache_entry -> fx_cached_sector_valid) &&
333
8918284
                        (cache_entry -> fx_cached_sector >= starting_sector) &&
334
159236
                        (cache_entry -> fx_cached_sector <= ending_sector))
335
                    {
336
337
                        /* Determine if the requested sector has been written to.  */
338
149707
                        if (cache_entry -> fx_cached_sector_buffer_dirty)
339
                        {
340
341
342
                            /* Yes, write the cached sector out to the media.  */
343
344
                            /* Check for write protect at the media level (set by driver).  */
345
29717
                            if (media_ptr -> fx_media_driver_write_protect == FX_FALSE)
346
                            {
347
348
#ifndef FX_MEDIA_STATISTICS_DISABLE
349
350
                                /* Increment the number of driver write sector(s) requests.  */
351
29461
                                media_ptr -> fx_media_driver_write_requests++;
352
#endif
353
354
                                /* Build Write request to the driver.  */
355
29461
                                media_ptr -> fx_media_driver_request =          FX_DRIVER_WRITE;
356
29461
                                media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
357
29461
                                media_ptr -> fx_media_driver_buffer =           cache_entry -> fx_cached_sector_memory_buffer;
358
#ifdef FX_DRIVER_USE_64BIT_LBA
359
                                media_ptr -> fx_media_driver_logical_sector =   cache_entry -> fx_cached_sector;
360
#else
361
29461
                                media_ptr -> fx_media_driver_logical_sector =   (ULONG)cache_entry -> fx_cached_sector;
362
#endif
363
29461
                                media_ptr -> fx_media_driver_sectors =          1;
364
29461
                                media_ptr -> fx_media_driver_sector_type =      cache_entry -> fx_cached_sector_type;
365
366
                                /* Sectors other than FX_DATA_SECTOR will never be dirty when FX_FAULT_TOLERANT is defined. */
367
#ifndef FX_FAULT_TOLERANT
368
                                /* Determine if the system write flag needs to be set.  */
369
29461
                                if (cache_entry -> fx_cached_sector_type != FX_DATA_SECTOR)
370
                                {
371
372
                                    /* Yes, a system sector write is present so set the flag.  The driver
373
                                       can use this flag to make extra safeguards in writing the sector
374
                                       out, yielding more fault tolerance.  */
375
14060
                                    media_ptr -> fx_media_driver_system_write =  FX_TRUE;
376
                                }
377
#endif /* FX_FAULT_TOLERANT */
378
379
                                /* If trace is enabled, insert this event into the trace buffer.  */
380
                                FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, cache_entry -> fx_cached_sector, 1, cache_entry -> fx_cached_sector_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
381
382
                                /* Invoke the driver to write the sector.  */
383
29461
                                (media_ptr -> fx_media_driver_entry) (media_ptr);
384
385
                                /* Clear the system write flag.  */
386
29461
                                media_ptr -> fx_media_driver_system_write =  FX_FALSE;
387
388
                                /* Check for successful completion.  */
389
29461
                                if (media_ptr -> fx_media_driver_status)
390
                                {
391
392
                                    /* Error writing a cached sector out.  Return the
393
                                       error status.  */
394
3
                                    return(media_ptr -> fx_media_driver_status);
395
                                }
396
397
                                /* Clear the buffer dirty flag since it has been flushed
398
                                   out.  */
399
29458
                                cache_entry -> fx_cached_sector_buffer_dirty =  FX_FALSE;
400
401
                                /* Decrement the number of dirty sectors currently in the cache.  */
402
29458
                                media_ptr -> fx_media_sector_cache_dirty_count--;
403
29458
                                remaining_dirty--;
404
                            }
405
                        }
406
407
                        /* Determine if the invalidate option is specified.  */
408
149704
                        if (invalidate)
409
                        {
410
411
                            /* Invalidate the cache entry.  */
412
77399
                            cache_entry -> fx_cached_sector_valid =  FX_FALSE;
413
414
                            /* Place all ones in the sector number.  */
415
77399
                            cache_entry -> fx_cached_sector =  (~(ULONG64)0);
416
417
                            /* Determine if this sector is still dirty, this could be the case if
418
                               write protection was turned on.  */
419
77399
                            if (cache_entry -> fx_cached_sector_buffer_dirty)
420
                            {
421
422
                                /* Yes, clear the dirty flag.  */
423
256
                                cache_entry -> fx_cached_sector_buffer_dirty =  FX_FALSE;
424
425
                                /* Decrement the number of dirty sectors currently in the cache.  */
426
256
                                media_ptr -> fx_media_sector_cache_dirty_count--;
427
256
                                remaining_dirty--;
428
                            }
429
                        }
430
431
                        /* Decrement the number of sectors in the range that have been processed.  */
432
149704
                        sectors--;
433
                    }
434
                    else
435
                    {
436
437
                        /* Determine if the sector is valid.  */
438
62849046
                        if (cache_entry -> fx_cached_sector_valid)
439
                        {
440
441
                            /* Increment the number of still remaining but out of range sectors.  */
442
8768577
                            remaining_valid++;
443
                        }
444
                    }
445
446
                    /* Determine if invalidation is not required and there are no
447
                       more dirty sectors. */
448

62998750
                    if ((remaining_dirty == 0) && (invalidate == FX_FALSE))
449
                    {
450
451
                        /* Yes, nothing left to do.  */
452
12153
                        break;
453
                    }
454
455
                    /* Determine if there are any more sectors to process.  */
456

62986597
                    if ((sectors == 0) && (invalidate == FX_FALSE))
457
                    {
458
459
                        /* No more sectors required to process.  */
460
91
                        break;
461
                    }
462
463
                    /* Move to the next cache entry.  */
464
62986506
                    cache_entry++;
465
                }
466
467
                /* Move the index to the next position since the bit map can only represent 32
468
                   cache entries.  */
469
15758541
                index =  index + (32 * FX_SECTOR_CACHE_DEPTH);
470
15758541
            } while (index < cache_size);
471
472
            /* Determine if invalidation was required and there are no more valid sectors
473
               associated with this bit position.  */
474

7957811
            if ((invalidate) && (remaining_valid == 0))
475
            {
476
477
                /* Clear this bit position.  */
478
72608
                media_ptr -> fx_media_sector_cache_hashed_sector_valid &=  ~(((ULONG)1) << bit_set);
479
            }
480
481
            /* Determine if the starting sector is being used for examination of the hash.  */
482
7957811
            if (use_starting_sector)
483
            {
484
485
                /* Move to the next sector.  */
486
18480
                starting_sector++;
487
            }
488
            else
489
            {
490
491
                /* Move to next bit in the map.  */
492
7939331
                valid_bit_map =  valid_bit_map >> 1;
493
494
                /* Increment the set bit marker.  */
495
7939331
                bit_set++;
496
            }
497
        }
498
    }
499
#else
500
    FX_PARAMETER_NOT_USED(media_ptr);
501
    FX_PARAMETER_NOT_USED(starting_sector);
502
    FX_PARAMETER_NOT_USED(sectors);
503
    FX_PARAMETER_NOT_USED(invalidate);
504
#endif /* FX_DISABLE_CACHE */
505
506
    /* If we get here, return successful status to the caller.  */
507
4901565
    return(FX_SUCCESS);
508
}
509