GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_utility_logical_sector_flush.c Lines: 108 108 100.0 %
Date: 2024-01-10 21:53:23 Branches: 88 88 100.0 %

Line Branch Exec Source
1
/**************************************************************************/
2
/*                                                                        */
3
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4
/*                                                                        */
5
/*       This software is licensed under the Microsoft Software License   */
6
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8
/*       and in the root directory of this software.                      */
9
/*                                                                        */
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
/*  RELEASE HISTORY                                                       */
71
/*                                                                        */
72
/*    DATE              NAME                      DESCRIPTION             */
73
/*                                                                        */
74
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
75
/*  09-30-2020     William E. Lamie         Modified comment(s), and      */
76
/*                                            added conditional to        */
77
/*                                            disable cache,              */
78
/*                                            resulting in version 6.1    */
79
/*  01-31-2022     William E. Lamie         Modified comment(s), fixed    */
80
/*                                            errors without cache,       */
81
/*                                            resulting in version 6.1.10 */
82
/*                                                                        */
83
/**************************************************************************/
84
4921077
UINT  _fx_utility_logical_sector_flush(FX_MEDIA *media_ptr, ULONG64 starting_sector, ULONG64 sectors, UINT invalidate)
85
{
86
87
#ifndef FX_DISABLE_CACHE
88
FX_CACHED_SECTOR *cache_entry;
89
UINT              cache_size;
90
UINT              i, bit_set, use_starting_sector;
91
ULONG             index;
92
ULONG             remaining_valid;
93
ULONG             remaining_dirty;
94
ULONG64           ending_sector;
95
ULONG             valid_bit_map;
96
97
98
    /* Extended port-specific processing macro, which is by default defined to white space.  */
99

4921077
    FX_UTILITY_LOGICAL_SECTOR_FLUSH_EXTENSION
100
101
    /* Calculate the ending sector.  */
102
4921075
    ending_sector =  starting_sector + sectors - 1;
103
104
    /* Pickup the number of dirty sectors currently in the cache.  */
105
4921075
    remaining_dirty =  media_ptr -> fx_media_sector_cache_dirty_count;
106
107
    /* If trace is enabled, insert this event into the trace buffer.  */
108
    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)
109
110
    /* Determine what type of cache configuration we have.  */
111
4921075
    if (media_ptr -> fx_media_sector_cache_hashed == FX_FALSE)
112
    {
113
114
        /* Linear cache present, simply walk through the search list until
115
           an unused cache entry is present.  */
116
117
        /* Flush and invalidate the internal logical sector cache.  */
118
4572446
        cache_size =            media_ptr -> fx_media_sector_cache_size;
119
4572446
        cache_entry =           media_ptr -> fx_media_sector_cache_list_ptr;
120
121
        /* Look at the cache entries that have been written to.  */
122

9133941
        while ((cache_size--) && (cache_entry -> fx_cached_sector))
123
        {
124
125
            /* Determine if invalidation is not required and there are no
126
               more dirty sectors. */
127

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

7976120
            if ((remaining_dirty == 0) && (invalidate == FX_FALSE))
279
            {
280
281
                /* Yes, nothing left to do.  */
282
4062
                break;
283
            }
284
285
            /* Determine if there are any more sectors to process.  */
286

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

62998750
                    if ((remaining_dirty == 0) && (invalidate == FX_FALSE))
462
                    {
463
464
                        /* Yes, nothing left to do.  */
465
12153
                        break;
466
                    }
467
468
                    /* Determine if there are any more sectors to process.  */
469

62986597
                    if ((sectors == 0) && (invalidate == FX_FALSE))
470
                    {
471
472
                        /* No more sectors required to process.  */
473
91
                        break;
474
                    }
475
476
                    /* Move to the next cache entry.  */
477
62986506
                    cache_entry++;
478
                }
479
480
                /* Move the index to the next position since the bit map can only represent 32
481
                   cache entries.  */
482
15758541
                index =  index + (32 * FX_SECTOR_CACHE_DEPTH);
483
15758541
            } while (index < cache_size);
484
485
            /* Determine if invalidation was required and there are no more valid sectors
486
               associated with this bit position.  */
487

7957811
            if ((invalidate) && (remaining_valid == 0))
488
            {
489
490
                /* Clear this bit position.  */
491
72608
                media_ptr -> fx_media_sector_cache_hashed_sector_valid &=  ~(((ULONG)1) << bit_set);
492
            }
493
494
            /* Determine if the starting sector is being used for examination of the hash.  */
495
7957811
            if (use_starting_sector)
496
            {
497
498
                /* Move to the next sector.  */
499
18480
                starting_sector++;
500
            }
501
            else
502
            {
503
504
                /* Move to next bit in the map.  */
505
7939331
                valid_bit_map =  valid_bit_map >> 1;
506
507
                /* Increment the set bit marker.  */
508
7939331
                bit_set++;
509
            }
510
        }
511
    }
512
#else
513
    FX_PARAMETER_NOT_USED(media_ptr);
514
    FX_PARAMETER_NOT_USED(starting_sector);
515
    FX_PARAMETER_NOT_USED(sectors);
516
    FX_PARAMETER_NOT_USED(invalidate);
517
#endif /* FX_DISABLE_CACHE */
518
519
    /* If we get here, return successful status to the caller.  */
520
4901565
    return(FX_SUCCESS);
521
}
522