GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_media_flush.c Lines: 78 78 100.0 %
Date: 2024-01-10 21:53:23 Branches: 28 28 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
/**   Media                                                               */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
#define FX_SOURCE_CODE
24
25
26
/* Include necessary system files.  */
27
28
#include "fx_api.h"
29
#include "fx_system.h"
30
#include "fx_media.h"
31
#include "fx_file.h"
32
#include "fx_directory.h"
33
#include "fx_utility.h"
34
35
36
/**************************************************************************/
37
/*                                                                        */
38
/*  FUNCTION                                               RELEASE        */
39
/*                                                                        */
40
/*    _fx_media_flush                                     PORTABLE C      */
41
/*                                                           6.1          */
42
/*  AUTHOR                                                                */
43
/*                                                                        */
44
/*    William E. Lamie, Microsoft Corporation                             */
45
/*                                                                        */
46
/*  DESCRIPTION                                                           */
47
/*                                                                        */
48
/*    This function examines the list of open files for this media and    */
49
/*    "flushes" each written open file to the underlying media.  After    */
50
/*    the open files have been flushed, the internal logical sector is    */
51
/*    flushed.  Finally, the attached driver is sent a flush command so   */
52
/*    that it can flush its sector cache (if any) to the media.           */
53
/*                                                                        */
54
/*  INPUT                                                                 */
55
/*                                                                        */
56
/*    media_ptr                             Media control block pointer   */
57
/*                                                                        */
58
/*  OUTPUT                                                                */
59
/*                                                                        */
60
/*    return status                                                       */
61
/*                                                                        */
62
/*  CALLS                                                                 */
63
/*                                                                        */
64
/*    _fx_directory_entry_write             Write the directory entry     */
65
/*    _fx_utility_FAT_flush                 Flush cached FAT entries      */
66
/*    _fx_utility_FAT_map_flush             Flush primary FAT changes to  */
67
/*                                            secondary FAT(s)            */
68
/*    _fx_utility_logical_sector_flush      Flush logical sector cache    */
69
/*    _fx_utility_32_unsigned_read          Read 32-bit unsigned          */
70
/*    _fx_utility_32_unsigned_write         Write 32-bit unsigned         */
71
/*                                                                        */
72
/*  CALLED BY                                                             */
73
/*                                                                        */
74
/*    Application Code                                                    */
75
/*                                                                        */
76
/*  RELEASE HISTORY                                                       */
77
/*                                                                        */
78
/*    DATE              NAME                      DESCRIPTION             */
79
/*                                                                        */
80
/*  05-19-2020     William E. Lamie         Initial Version 6.0           */
81
/*  09-30-2020     William E. Lamie         Modified comment(s), and      */
82
/*                                            added conditional to        */
83
/*                                            disable cache,              */
84
/*                                            resulting in version 6.1    */
85
/*                                                                        */
86
/**************************************************************************/
87
33016
UINT  _fx_media_flush(FX_MEDIA  *media_ptr)
88
{
89
90
UINT     status;
91
ULONG    open_count;
92
FX_FILE *file_ptr;
93
FX_INT_SAVE_AREA
94
95
96
#ifndef FX_MEDIA_STATISTICS_DISABLE
97
98
    /* Increment the number of times this service has been called.  */
99
33016
    media_ptr -> fx_media_flushes++;
100
#endif
101
102
    /* Check the media to make sure it is open.  */
103
33016
    if (media_ptr -> fx_media_id != FX_MEDIA_ID)
104
    {
105
106
        /* Return the media not opened error.  */
107
1
        return(FX_MEDIA_NOT_OPEN);
108
    }
109
110
    /* If trace is enabled, insert this event into the trace buffer.  */
111
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_FLUSH, media_ptr, 0, 0, 0, FX_TRACE_MEDIA_EVENTS, 0, 0)
112
113
    /* Protect against other threads accessing the media.  */
114
33015
    FX_PROTECT
115
116
    /* Check for write protect at the media level (set by driver).  */
117
33015
    if (media_ptr -> fx_media_driver_write_protect)
118
    {
119
120
        /* Release media protection.  */
121
1
        FX_UNPROTECT
122
123
        /* Return write protect error.  */
124
1
        return(FX_WRITE_PROTECT);
125
    }
126
127
    /* Loop through the media's open files.  */
128
33014
    open_count =  media_ptr -> fx_media_opened_file_count;
129
33014
    file_ptr =    media_ptr -> fx_media_opened_file_list;
130
124145
    while (open_count)
131
    {
132
133
        /* Look at each opened file to see if the same file is opened
134
           for writing and has been written to.  */
135
91132
        if ((file_ptr -> fx_file_open_mode == FX_OPEN_FOR_WRITE) &&
136
55581
            (file_ptr -> fx_file_modified))
137
        {
138
139
            /* Protect against update.  */
140
20899
            FX_DISABLE_INTS
141
142
            /* Set the new time and date.  */
143
20899
            file_ptr -> fx_file_dir_entry.fx_dir_entry_time =  _fx_system_time;
144
20899
            file_ptr -> fx_file_dir_entry.fx_dir_entry_date =  _fx_system_date;
145
146
            /* Restore interrupts.  */
147
20899
            FX_RESTORE_INTS
148
149
            /* Copy the new file size into the directory entry.  */
150
20899
            file_ptr -> fx_file_dir_entry.fx_dir_entry_file_size =
151
20899
                file_ptr -> fx_file_current_file_size;
152
153
            /* Write the directory entry to the media.  */
154
#ifdef FX_ENABLE_EXFAT
155
            if (media_ptr -> fx_media_FAT_type == FX_exFAT)
156
            {
157
                status = _fx_directory_exFAT_entry_write(
158
                        media_ptr, &(file_ptr -> fx_file_dir_entry), UPDATE_STREAM);
159
            }
160
            else
161
            {
162
#endif /* FX_ENABLE_EXFAT */
163
20899
                status = _fx_directory_entry_write(media_ptr, &(file_ptr -> fx_file_dir_entry));
164
#ifdef FX_ENABLE_EXFAT
165
            }
166
#endif /* FX_ENABLE_EXFAT */
167
168
            /* Check for a good status.  */
169
20899
            if (status != FX_SUCCESS)
170
            {
171
172
                /* Release media protection.  */
173
1
                FX_UNPROTECT
174
175
                /* Error writing the directory.  */
176
1
                return(status);
177
            }
178
179
            /* Clear the file modified flag.  */
180
20898
            file_ptr -> fx_file_modified =  FX_FALSE;
181
        }
182
183
        /* Adjust the pointer and decrement the opened count.  */
184
91131
        file_ptr =  file_ptr -> fx_file_opened_next;
185
91131
        open_count--;
186
    }
187
188
    /* Flush the cached individual FAT entries */
189
33013
    _fx_utility_FAT_flush(media_ptr);
190
191
    /* Flush changed sector(s) in the primary FAT to secondary FATs.  */
192
33013
    _fx_utility_FAT_map_flush(media_ptr);
193
194
#ifdef FX_ENABLE_EXFAT
195
    if ((media_ptr -> fx_media_FAT_type == FX_exFAT) &&
196
        (FX_TRUE == media_ptr -> fx_media_exfat_bitmap_cache_dirty))
197
    {
198
199
        /* Flush bitmap.  */
200
        _fx_utility_exFAT_bitmap_flush(media_ptr);
201
    }
202
#endif /* FX_ENABLE_EXFAT */
203
204
    /* Flush the internal logical sector cache.  */
205
33013
    status =  _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_total_sectors), FX_FALSE);
206
207
    /* Check for a good status.  */
208
33013
    if (status != FX_SUCCESS)
209
    {
210
211
        /* Release media protection.  */
212
1
        FX_UNPROTECT
213
214
        /* Error writing the directory.  */
215
1
        return(status);
216
    }
217
218
    /* Determine if the media needs to have the additional information sector updated. This will
219
       only be the case for 32-bit FATs. The logic here only needs to be done if the last reported
220
       available cluster count is different that the currently available clusters.  */
221
33012
    if ((media_ptr -> fx_media_FAT32_additional_info_sector) &&
222
1027
        (media_ptr -> fx_media_FAT32_additional_info_last_available != media_ptr -> fx_media_available_clusters))
223
    {
224
225
    UCHAR *buffer_ptr;
226
    ULONG  signature;
227
228
#ifndef FX_DISABLE_CACHE
229
230
        /* Setup a pointer to the first cached entry's buffer.  */
231
1008
        buffer_ptr =  (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_memory_buffer;
232
233
        /* Invalidate this cache entry.  */
234
1008
        (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector =  (~(ULONG64)0);
235
1008
        (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_valid =  FX_FALSE;
236
#else
237
        buffer_ptr =  media_ptr -> fx_media_memory_buffer;
238
#endif /* FX_DISABLE_CACHE */
239
240
        /* Read the FAT32 additional information sector from the device.  */
241
1008
        media_ptr -> fx_media_driver_request =          FX_DRIVER_READ;
242
1008
        media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
243
1008
        media_ptr -> fx_media_driver_buffer =           buffer_ptr;
244
1008
        media_ptr -> fx_media_driver_logical_sector =   media_ptr -> fx_media_FAT32_additional_info_sector;
245
1008
        media_ptr -> fx_media_driver_sectors =          1;
246
1008
        media_ptr -> fx_media_driver_sector_type =      FX_DIRECTORY_SECTOR;
247
248
#ifndef FX_MEDIA_STATISTICS_DISABLE
249
250
        /* Increment the number of driver read sector(s) requests.  */
251
1008
        media_ptr -> fx_media_driver_read_requests++;
252
#endif
253
254
        /* If trace is enabled, insert this event into the trace buffer.  */
255
        FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_READ, media_ptr, media_ptr -> fx_media_FAT32_additional_info_sector, 1, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
256
257
        /* Invoke the driver to read the FAT32 additional information sector.  */
258
1008
        (media_ptr -> fx_media_driver_entry) (media_ptr);
259
260
        /* Determine if the FAT32 sector was read correctly. */
261
1008
        if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
262
        {
263
264
            /* Release media protection.  */
265
205
            FX_UNPROTECT
266
267
            /* Return the error status.  */
268
205
            return(FX_IO_ERROR);
269
        }
270
271
        /* Setup a pointer into the FAT32 additional information sector.  */
272
803
        buffer_ptr =  media_ptr -> fx_media_driver_buffer;
273
274
        /* Pickup the first signature long word.  */
275
803
        signature =  _fx_utility_32_unsigned_read(&buffer_ptr[0]);
276
277
        /* Determine if the signature is correct.  */
278
803
        if (signature == 0x41615252)
279
        {
280
281
            /* Yes, the first signature is correct, now pickup the next signature.  */
282
801
            signature =  _fx_utility_32_unsigned_read(&buffer_ptr[484]);
283
284
            /* Determine if this signature is correct.  */
285
801
            if (signature == 0x61417272)
286
            {
287
288
                /* Yes, we have a good FAT32 additional information sector.  */
289
290
                /* Set the free cluster count to the available clusters in the media control block.  */
291
800
                _fx_utility_32_unsigned_write(&buffer_ptr[488], media_ptr -> fx_media_available_clusters);
292
293
                /* Set the next free cluster number hint to starting search cluster in the media control block.  */
294
800
                _fx_utility_32_unsigned_write(&buffer_ptr[492], media_ptr -> fx_media_cluster_search_start);
295
296
                /* Now write the sector back out to the media.  */
297
800
                media_ptr -> fx_media_driver_request =          FX_DRIVER_WRITE;
298
800
                media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
299
800
                media_ptr -> fx_media_driver_buffer =           buffer_ptr;
300
800
                media_ptr -> fx_media_driver_logical_sector =   media_ptr -> fx_media_FAT32_additional_info_sector;
301
800
                media_ptr -> fx_media_driver_sectors =          1;
302
800
                media_ptr -> fx_media_driver_sector_type =      FX_DIRECTORY_SECTOR;
303
304
                /* Set the system write flag since we are writing a directory sector.  */
305
800
                media_ptr -> fx_media_driver_system_write =  FX_TRUE;
306
307
#ifndef FX_MEDIA_STATISTICS_DISABLE
308
309
                /* Increment the number of driver write sector(s) requests.  */
310
800
                media_ptr -> fx_media_driver_write_requests++;
311
#endif
312
313
                /* If trace is enabled, insert this event into the trace buffer.  */
314
                FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, media_ptr -> fx_media_FAT32_additional_info_sector, 1, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
315
316
                /* Invoke the driver to write the FAT32 additional information sector.  */
317
800
                (media_ptr -> fx_media_driver_entry) (media_ptr);
318
319
                /* Clear the system write flag.  */
320
800
                media_ptr -> fx_media_driver_system_write =  FX_FALSE;
321
322
                /* Determine if the FAT32 sector was written correctly. */
323
800
                if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
324
                {
325
326
                    /* Release media protection.  */
327
90
                    FX_UNPROTECT
328
329
                    /* Return the sector IO error status.  */
330
90
                    return(FX_IO_ERROR);
331
                }
332
333
                /* Successful update of the FAT32 additional information sector. Update the
334
                   last written available cluster count.  */
335
710
                media_ptr -> fx_media_FAT32_additional_info_last_available =  media_ptr -> fx_media_available_clusters;
336
            }
337
        }
338
    }
339
340
#ifndef FX_MEDIA_STATISTICS_DISABLE
341
342
    /* Increment the number of driver flush requests.  */
343
32717
    media_ptr -> fx_media_driver_flush_requests++;
344
#endif
345
346
    /* Build the "flush" I/O driver request.  */
347
32717
    media_ptr -> fx_media_driver_request =      FX_DRIVER_FLUSH;
348
32717
    media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
349
350
    /* If trace is enabled, insert this event into the trace buffer.  */
351
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_FLUSH, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
352
353
    /* Call the specified I/O driver with the flush request.  */
354
32717
    (media_ptr -> fx_media_driver_entry) (media_ptr);
355
356
    /* Determine if the I/O driver flushed successfully.  */
357
32717
    if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
358
    {
359
360
        /* Release media protection.  */
361
100
        FX_UNPROTECT
362
363
        /* Return the driver error status.  */
364
100
        return(FX_IO_ERROR);
365
    }
366
367
    /* Release media protection.  */
368
32617
    FX_UNPROTECT
369
370
    /* If we get here, return successful status to the caller.  */
371
32617
    return(FX_SUCCESS);
372
}
373