GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_utility_logical_sector_write.c Lines: 63 63 100.0 %
Date: 2024-03-11 05:15:45 Branches: 48 48 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 *
4
 * This program and the accompanying materials are made available under the
5
 * terms of the MIT License which is available at
6
 * https://opensource.org/licenses/MIT.
7
 *
8
 * SPDX-License-Identifier: MIT
9
 **************************************************************************/
10
11
12
/**************************************************************************/
13
/**************************************************************************/
14
/**                                                                       */
15
/** FileX Component                                                       */
16
/**                                                                       */
17
/**   Utility                                                             */
18
/**                                                                       */
19
/**************************************************************************/
20
/**************************************************************************/
21
22
#define FX_SOURCE_CODE
23
24
25
/* Include necessary system files.  */
26
27
#include "fx_api.h"
28
#include "fx_system.h"
29
#include "fx_utility.h"
30
#ifdef FX_ENABLE_FAULT_TOLERANT
31
#include "fx_fault_tolerant.h"
32
#endif /* FX_ENABLE_FAULT_TOLERANT */
33
34
35
/**************************************************************************/
36
/*                                                                        */
37
/*  FUNCTION                                               RELEASE        */
38
/*                                                                        */
39
/*    _fx_utility_logical_sector_write                    PORTABLE C      */
40
/*                                                           6.1.6        */
41
/*  AUTHOR                                                                */
42
/*                                                                        */
43
/*    William E. Lamie, Microsoft Corporation                             */
44
/*                                                                        */
45
/*  DESCRIPTION                                                           */
46
/*                                                                        */
47
/*    This function handles logical sector write requests for all FileX   */
48
/*    components.  If the logical sector is currently in the media's      */
49
/*    buffer supplied by the caller, the function simply marks the buffer */
50
/*    as written to.  Otherwise, physical I/O is requested through the    */
51
/*    corresponding I/O driver.                                           */
52
/*                                                                        */
53
/*    Note: Conversion of the logical sector is done inside the driver.   */
54
/*          This results in a performance boost for FLASH or RAM media    */
55
/*          devices.                                                      */
56
/*                                                                        */
57
/*  INPUT                                                                 */
58
/*                                                                        */
59
/*    media_ptr                             Media control block pointer   */
60
/*    logical_sector                        Logical sector number         */
61
/*    buffer_ptr                            Pointer of sector buffer      */
62
/*    sectors                               Number of sectors to write    */
63
/*    sector_type                           Type of sector(s) to write    */
64
/*                                                                        */
65
/*  OUTPUT                                                                */
66
/*                                                                        */
67
/*    return status                                                       */
68
/*                                                                        */
69
/*  CALLS                                                                 */
70
/*                                                                        */
71
/*    _fx_utility_logical_sector_flush      Flush and invalidate sectors  */
72
/*                                          that overlap with non-cache   */
73
/*                                          sector I/O.                   */
74
/*    I/O Driver                                                          */
75
/*                                                                        */
76
/*  CALLED BY                                                             */
77
/*                                                                        */
78
/*    FileX System Functions                                              */
79
/*                                                                        */
80
/*  RELEASE HISTORY                                                       */
81
/*                                                                        */
82
/*    DATE              NAME                      DESCRIPTION             */
83
/*                                                                        */
84
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
85
/*  09-30-2020     William E. Lamie         Modified comment(s), and      */
86
/*                                            added conditional to        */
87
/*                                            disable cache,              */
88
/*                                            resulting in version 6.1    */
89
/*  04-02-2021     Bhupendra Naphade        Modified comment(s),          */
90
/*                                            updated check for logical   */
91
/*                                            sector value,               */
92
/*                                            resulting in version 6.1.6  */
93
/*                                                                        */
94
/**************************************************************************/
95
4467652
UINT  _fx_utility_logical_sector_write(FX_MEDIA *media_ptr, ULONG64 logical_sector,
96
                                       VOID *buffer_ptr, ULONG sectors, UCHAR sector_type)
97
{
98
99
#ifndef FX_DISABLE_CACHE
100
FX_CACHED_SECTOR *cache_entry;
101
UINT              cache_size;
102
UINT              index;
103
UINT              i;
104
4467652
UCHAR             cache_found = FX_FALSE;
105
#endif /* FX_DISABLE_CACHE */
106
107
#ifndef FX_MEDIA_STATISTICS_DISABLE
108
109
    /* Determine if the request is for FAT sector.  */
110
4467652
    if (sector_type == FX_FAT_SECTOR)
111
    {
112
113
        /* Increment the number of FAT sector writes.  */
114
3547771
        media_ptr -> fx_media_fat_sector_writes++;
115
    }
116
117
    /* Increment the number of logical sectors written.  */
118
4467652
    media_ptr -> fx_media_logical_sector_writes++;
119
#endif
120
121
    /* Extended port-specific processing macro, which is by default defined to white space.  */
122

4467652
    FX_UTILITY_LOGICAL_SECTOR_WRITE_EXTENSION
123
124
#ifndef FX_DISABLE_CACHE
125
    /* Determine if the request is from the internal media buffer area.  */
126
4463055
    if ((((UCHAR *)buffer_ptr) >= media_ptr -> fx_media_memory_buffer) &&
127
4426074
        (((UCHAR *)buffer_ptr) <= media_ptr -> fx_media_sector_cache_end))
128
    {
129
130
        /* Internal cache buffer is requested.  */
131
132
        /* Determine if the logical sector cache access should use the hash function.  */
133
4426063
        if (media_ptr -> fx_media_sector_cache_hashed)
134
        {
135
136
            /* Calculate the area of the cache for this logical sector.  */
137
2166735
            index =  (ULONG)(logical_sector & media_ptr -> fx_media_sector_cache_hash_mask) * FX_SECTOR_CACHE_DEPTH;
138
139
            /* Build a pointer to the cache entry.  */
140
2166735
            cache_entry =  &(media_ptr -> fx_media_sector_cache[index]);
141
142
8488147
            for (i = 0; i < FX_SECTOR_CACHE_DEPTH; i++, cache_entry++)
143
            {
144
145
146
                /* Determine if the logical sector is in the cache - assuming the depth of the
147
                   sector cache is 4 entries.  */
148

6907937
                if ((cache_entry -> fx_cached_sector_valid) && (cache_entry -> fx_cached_sector == logical_sector))
149
                {
150
586525
                    cache_found = FX_TRUE;
151
586525
                    break;
152
                }
153
            }
154
        }
155
        else
156
        {
157
158
            /* Search for an entry in the cache that matches this request.  */
159
2259328
            cache_size =            media_ptr -> fx_media_sector_cache_size;
160
2259328
            cache_entry =           media_ptr -> fx_media_sector_cache_list_ptr;
161
162
            /* Look at the cache entries until a match is found or the end of
163
               the cache is reached.  */
164
405836871
            while (cache_size--)
165
            {
166
167
                /* Determine if the requested sector has been found.  */
168

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

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

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