GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_utility_logical_sector_write.c Lines: 63 63 100.0 %
Date: 2026-03-06 18:49:02 Branches: 48 48 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
#ifdef FX_ENABLE_FAULT_TOLERANT
32
#include "fx_fault_tolerant.h"
33
#endif /* FX_ENABLE_FAULT_TOLERANT */
34
35
36
/**************************************************************************/
37
/*                                                                        */
38
/*  FUNCTION                                               RELEASE        */
39
/*                                                                        */
40
/*    _fx_utility_logical_sector_write                    PORTABLE C      */
41
/*                                                           6.1.6        */
42
/*  AUTHOR                                                                */
43
/*                                                                        */
44
/*    William E. Lamie, Microsoft Corporation                             */
45
/*                                                                        */
46
/*  DESCRIPTION                                                           */
47
/*                                                                        */
48
/*    This function handles logical sector write requests for all FileX   */
49
/*    components.  If the logical sector is currently in the media's      */
50
/*    buffer supplied by the caller, the function simply marks the buffer */
51
/*    as written to.  Otherwise, physical I/O is requested through the    */
52
/*    corresponding I/O driver.                                           */
53
/*                                                                        */
54
/*    Note: Conversion of the logical sector is done inside the driver.   */
55
/*          This results in a performance boost for FLASH or RAM media    */
56
/*          devices.                                                      */
57
/*                                                                        */
58
/*  INPUT                                                                 */
59
/*                                                                        */
60
/*    media_ptr                             Media control block pointer   */
61
/*    logical_sector                        Logical sector number         */
62
/*    buffer_ptr                            Pointer of sector buffer      */
63
/*    sectors                               Number of sectors to write    */
64
/*    sector_type                           Type of sector(s) to write    */
65
/*                                                                        */
66
/*  OUTPUT                                                                */
67
/*                                                                        */
68
/*    return status                                                       */
69
/*                                                                        */
70
/*  CALLS                                                                 */
71
/*                                                                        */
72
/*    _fx_utility_logical_sector_flush      Flush and invalidate sectors  */
73
/*                                          that overlap with non-cache   */
74
/*                                          sector I/O.                   */
75
/*    I/O Driver                                                          */
76
/*                                                                        */
77
/*  CALLED BY                                                             */
78
/*                                                                        */
79
/*    FileX System Functions                                              */
80
/*                                                                        */
81
/**************************************************************************/
82
4467652
UINT  _fx_utility_logical_sector_write(FX_MEDIA *media_ptr, ULONG64 logical_sector,
83
                                       VOID *buffer_ptr, ULONG sectors, UCHAR sector_type)
84
{
85
86
#ifndef FX_DISABLE_CACHE
87
FX_CACHED_SECTOR *cache_entry;
88
UINT              cache_size;
89
UINT              index;
90
UINT              i;
91
4467652
UCHAR             cache_found = FX_FALSE;
92
#endif /* FX_DISABLE_CACHE */
93
94
#ifndef FX_MEDIA_STATISTICS_DISABLE
95
96
    /* Determine if the request is for FAT sector.  */
97
4467652
    if (sector_type == FX_FAT_SECTOR)
98
    {
99
100
        /* Increment the number of FAT sector writes.  */
101
3547771
        media_ptr -> fx_media_fat_sector_writes++;
102
    }
103
104
    /* Increment the number of logical sectors written.  */
105
4467652
    media_ptr -> fx_media_logical_sector_writes++;
106
#endif
107
108
    /* Extended port-specific processing macro, which is by default defined to white space.  */
109

4467652
    FX_UTILITY_LOGICAL_SECTOR_WRITE_EXTENSION
110
111
#ifndef FX_DISABLE_CACHE
112
    /* Determine if the request is from the internal media buffer area.  */
113
4463055
    if ((((UCHAR *)buffer_ptr) >= media_ptr -> fx_media_memory_buffer) &&
114
4426074
        (((UCHAR *)buffer_ptr) <= media_ptr -> fx_media_sector_cache_end))
115
    {
116
117
        /* Internal cache buffer is requested.  */
118
119
        /* Determine if the logical sector cache access should use the hash function.  */
120
4426063
        if (media_ptr -> fx_media_sector_cache_hashed)
121
        {
122
123
            /* Calculate the area of the cache for this logical sector.  */
124
2166735
            index =  (ULONG)(logical_sector & media_ptr -> fx_media_sector_cache_hash_mask) * FX_SECTOR_CACHE_DEPTH;
125
126
            /* Build a pointer to the cache entry.  */
127
2166735
            cache_entry =  &(media_ptr -> fx_media_sector_cache[index]);
128
129
8488147
            for (i = 0; i < FX_SECTOR_CACHE_DEPTH; i++, cache_entry++)
130
            {
131
132
133
                /* Determine if the logical sector is in the cache - assuming the depth of the
134
                   sector cache is 4 entries.  */
135

6907937
                if ((cache_entry -> fx_cached_sector_valid) && (cache_entry -> fx_cached_sector == logical_sector))
136
                {
137
586525
                    cache_found = FX_TRUE;
138
586525
                    break;
139
                }
140
            }
141
        }
142
        else
143
        {
144
145
            /* Search for an entry in the cache that matches this request.  */
146
2259328
            cache_size =            media_ptr -> fx_media_sector_cache_size;
147
2259328
            cache_entry =           media_ptr -> fx_media_sector_cache_list_ptr;
148
149
            /* Look at the cache entries until a match is found or the end of
150
               the cache is reached.  */
151
405836871
            while (cache_size--)
152
            {
153
154
                /* Determine if the requested sector has been found.  */
155

404254132
                if ((cache_entry -> fx_cached_sector_valid) && (cache_entry -> fx_cached_sector == logical_sector))
156
                {
157
676589
                    cache_found = FX_TRUE;
158
676589
                    break;
159
                }
160
161
                /* Otherwise, we have not found the cached entry yet.  */
162
163
                /* If there are more entries, move to the next one.  */
164
403577543
                if (cache_entry -> fx_cached_sector_next_used)
165
                {
166
167
                    /* Move to the next cache entry.  */
168
401994804
                    cache_entry =  cache_entry -> fx_cached_sector_next_used;
169
                }
170
            }
171
        }
172
173
#ifdef FX_ENABLE_FAULT_TOLERANT
174
        if (media_ptr -> fx_media_fault_tolerant_enabled &&
175
            (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED) &&
176
            (sector_type == FX_DATA_SECTOR) &&
177
            !(cache_found && (cache_entry -> fx_cached_sector_memory_buffer == buffer_ptr)))
178
        {
179
180
            /* Special use case for file write when fault tolerant is enabled. */
181
            /* Data are read from one sector but write to another sector. */
182
            /* Need to invalidate both of original and new caches. */
183
            if (cache_found)
184
            {
185
186
                /* Invalidate the new cache. */
187
                cache_entry -> fx_cached_sector_valid = FX_FALSE;
188
                cache_found = FX_FALSE;
189
            }
190
191
            /* Search for original cache.  */
192
            cache_size =            media_ptr -> fx_media_sector_cache_size;
193
            cache_entry =           media_ptr -> fx_media_sector_cache_list_ptr;
194
195
            /* Look at the cache entries until a match is found or the end of
196
               the cache is reached.  */
197
            while (cache_size--)
198
            {
199
200
                /* Determine if the original sector has been found.  */
201
                if ((cache_entry -> fx_cached_sector_valid) &&
202
                    (cache_entry -> fx_cached_sector_memory_buffer == buffer_ptr))
203
                {
204
205
                    /* Invalidate the original cache. */
206
                    cache_entry -> fx_cached_sector_valid = FX_FALSE;
207
                    break;
208
                }
209
210
                /* Otherwise, we have not found the cached entry yet.  */
211
212
                /* If there are more entries, move to the next one.  */
213
                if (cache_entry -> fx_cached_sector_next_used)
214
                {
215
216
                    /* Move to the next cache entry.  */
217
                    cache_entry =  cache_entry -> fx_cached_sector_next_used;
218
                }
219
            }
220
        }
221
#endif /* FX_ENABLE_FAULT_TOLERANT */
222
223
4426063
        if (cache_found)
224
        {
225
226
            /* Yes, we found a match.  */
227
228
#ifdef FX_FAULT_TOLERANT
229
230
            /* Check for a system sector. Data sector fault tolerance is selected with
231
               the FX_FAULT_TOLERANT_DATA option.  */
232
            if (sector_type != FX_DATA_SECTOR)
233
            {
234
235
                /* With the fault tolerant option enabled, system sectors are written immediately to
236
                   the media.  */
237
238
#ifndef FX_MEDIA_STATISTICS_DISABLE
239
240
                /* Increment the number of driver write sector(s) requests.  */
241
                media_ptr -> fx_media_driver_write_requests++;
242
#endif
243
244
                /* Build write request to the driver.  */
245
                media_ptr -> fx_media_driver_request =          FX_DRIVER_WRITE;
246
                media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
247
                media_ptr -> fx_media_driver_buffer =           cache_entry -> fx_cached_sector_memory_buffer;
248
#ifdef FX_DRIVER_USE_64BIT_LBA
249
                media_ptr -> fx_media_driver_logical_sector =   logical_sector;
250
#else
251
                media_ptr -> fx_media_driver_logical_sector =   (ULONG)logical_sector;
252
#endif
253
                media_ptr -> fx_media_driver_sectors =          1;
254
                media_ptr -> fx_media_driver_sector_type =      sector_type;
255
256
                /* Yes, a system sector write is present so set the flag.  The driver
257
                   can use this flag to make extra safeguards in writing the sector
258
                   out, yielding more fault tolerance.  */
259
                media_ptr -> fx_media_driver_system_write =  FX_TRUE;
260
261
                /* If trace is enabled, insert this event into the trace buffer.  */
262
                FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, logical_sector, 1, cache_entry -> fx_cached_sector_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
263
264
                /* Invoke the driver to write the sector(s).  */
265
                (media_ptr -> fx_media_driver_entry) (media_ptr);
266
267
                /* Clear the system write flag.  */
268
                media_ptr -> fx_media_driver_system_write =  FX_FALSE;
269
270
                /* Return success.  */
271
                return(media_ptr -> fx_media_driver_status);
272
            }
273
#endif
274
275
            /* Determine if this is the first write of this logical sector.  */
276
1263114
            if (cache_entry -> fx_cached_sector_buffer_dirty == FX_FALSE)
277
            {
278
279
                /* Yes, increment the number of outstanding dirty sectors.  */
280
306017
                media_ptr -> fx_media_sector_cache_dirty_count++;
281
282
                /* Simply mark this entry as dirty.  */
283
306017
                cache_entry -> fx_cached_sector_buffer_dirty =  FX_TRUE;
284
            }
285
286
            /* Don't bother updating the cache linked list since writes are
287
               preceded by reads anyway.  */
288
289
            /* Success, return to caller immediately!  */
290
1263114
            return(FX_SUCCESS);
291
        }
292
293
294
        /* Okay, so if we are here the request must be for the additional FAT writes, since this is the
295
           only time a write request is made without a preceding read request.  */
296
297
        /* Is the logical sector valid?  */
298

3162949
        if ((logical_sector == 0) || (logical_sector == ((ULONG)0xFFFFFFFF)))
299
        {
300
4
            return(FX_SECTOR_INVALID);
301
        }
302
303
        /* Compare logical sector against total sectors to make sure it is valid.  */
304
3162945
        if ((logical_sector + sectors - 1) >= media_ptr -> fx_media_total_sectors)
305
        {
306
1
            return(FX_SECTOR_INVALID);
307
        }
308
309
        /* Just write the buffer to the media.  */
310
311
#ifndef FX_MEDIA_STATISTICS_DISABLE
312
313
        /* Increment the number of driver write sector(s) requests.  */
314
3162944
        media_ptr -> fx_media_driver_write_requests++;
315
#endif
316
317
        /* Build write request to the driver.  */
318
3162944
        media_ptr -> fx_media_driver_request =          FX_DRIVER_WRITE;
319
3162944
        media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
320
3162944
        media_ptr -> fx_media_driver_buffer =           buffer_ptr;
321
#ifdef FX_DRIVER_USE_64BIT_LBA
322
        media_ptr -> fx_media_driver_logical_sector =   logical_sector;
323
#else
324
3162944
        media_ptr -> fx_media_driver_logical_sector =   (ULONG)logical_sector;
325
#endif
326
3162944
        media_ptr -> fx_media_driver_sectors =          sectors;
327
3162944
        media_ptr -> fx_media_driver_sector_type =      sector_type;
328
329
        /* Determine if the system write flag needs to be set.  */
330
3162944
        if (sector_type != FX_DATA_SECTOR)
331
        {
332
333
            /* Yes, a system sector write is present so set the flag.  The driver
334
               can use this flag to make extra safeguards in writing the sector
335
               out, yielding more fault tolerance.  */
336
3162853
            media_ptr -> fx_media_driver_system_write =  FX_TRUE;
337
        }
338
339
        /* If trace is enabled, insert this event into the trace buffer.  */
340
        FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, logical_sector, sectors, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
341
342
        /* Invoke the driver to write the sector(s).  */
343
3162944
        (media_ptr -> fx_media_driver_entry) (media_ptr);
344
345
        /* Clear the system write flag.  */
346
3162944
        media_ptr -> fx_media_driver_system_write =  FX_FALSE;
347
348
        /* Check for successful completion.  */
349
3162944
        if (media_ptr -> fx_media_driver_status)
350
        {
351
352
            /* Error writing a internal sector out.  Return the
353
               error status.  */
354
1
            return(media_ptr -> fx_media_driver_status);
355
        }
356
357
        /* At this point, we have a successful write.  */
358
3162943
        return(FX_SUCCESS);
359
    }
360
    else
361
#endif /* FX_DISABLE_CACHE */
362
    {
363
364
        /* Otherwise, the write request is being made directly from an application
365
           buffer. Determine if the logical sector is valid.  */
366
367
        /* Is the logical sector valid? */
368

36992
        if ((logical_sector == 0) || (logical_sector == ((ULONG)0xFFFFFFFF)))
369
        {
370
4
            return(FX_SECTOR_INVALID);
371
        }
372
373
        /* Compare logical sector against total sectors to make sure it is valid.  */
374
36988
        if ((logical_sector + sectors - 1) >= media_ptr -> fx_media_total_sectors)
375
        {
376
3
            return(FX_SECTOR_INVALID);
377
        }
378
379
        /* Flush and invalidate for any entries in the cache that are in this direct I/O read request range.  */
380
36985
        _fx_utility_logical_sector_flush(media_ptr, logical_sector, (ULONG64) sectors, FX_TRUE);
381
382
#ifdef FX_DISABLE_CACHE
383
        if ((logical_sector <= media_ptr -> fx_media_memory_buffer_sector) && (logical_sector + sectors >= media_ptr -> fx_media_memory_buffer_sector))
384
        {
385
            media_ptr -> fx_media_memory_buffer_sector = (ULONG64)-1;
386
        }
387
#endif /* FX_DISABLE_CACHE */
388
389
#ifndef FX_MEDIA_STATISTICS_DISABLE
390
391
        /* Increment the number of driver write sector(s) requests.  */
392
36985
        media_ptr -> fx_media_driver_write_requests++;
393
#endif
394
395
        /* Build request to the driver.  */
396
36985
        media_ptr -> fx_media_driver_request =          FX_DRIVER_WRITE;
397
36985
        media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
398
36985
        media_ptr -> fx_media_driver_buffer =           buffer_ptr;
399
#ifdef FX_DRIVER_USE_64BIT_LBA
400
        media_ptr -> fx_media_driver_logical_sector =   logical_sector;
401
#else
402
36985
        media_ptr -> fx_media_driver_logical_sector =   (ULONG)logical_sector;
403
#endif
404
36985
        media_ptr -> fx_media_driver_sectors =          sectors;
405
36985
        media_ptr -> fx_media_driver_sector_type =      sector_type;
406
407
        /* Determine if the system write flag needs to be set.  */
408
36985
        if (sector_type != FX_DATA_SECTOR)
409
        {
410
411
            /* Yes, a system sector write is present so set the flag.  The driver
412
               can use this flag to make extra safeguards in writing the sector
413
               out, yielding more fault tolerance.  */
414
2
            media_ptr -> fx_media_driver_system_write =  FX_TRUE;
415
        }
416
417
        /* If trace is enabled, insert this event into the trace buffer.  */
418
        FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, logical_sector, sectors, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
419
420
        /* Invoke the driver to write the sector(s).  */
421
36985
        (media_ptr -> fx_media_driver_entry) (media_ptr);
422
423
        /* Clear the system write flag.  */
424
36985
        media_ptr -> fx_media_driver_system_write =  FX_FALSE;
425
426
        /* Return driver status.  */
427
36985
        return(media_ptr -> fx_media_driver_status);
428
    }
429
}
430