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_FAT_entry_write                         PORTABLE C      */
40 /*                                                           6.1          */
41 /*  AUTHOR                                                                */
42 /*                                                                        */
43 /*    William E. Lamie, Microsoft Corporation                             */
44 /*                                                                        */
45 /*  DESCRIPTION                                                           */
46 /*                                                                        */
47 /*    This function writes to the supplied FAT entry to all FATs in       */
48 /*    the media.  12-bit, 16-bit, and 32-bit FAT writing is supported.    */
49 /*                                                                        */
50 /*  INPUT                                                                 */
51 /*                                                                        */
52 /*    media_ptr                             Media control block pointer   */
53 /*    cluster                               Cluster entry number          */
54 /*    next_cluster                          Next cluster integer pointer  */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    return status                                                       */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _fx_utility_FAT_flush                 FLUSH dirty entries in the    */
63 /*                                            FAT cache                   */
64 /*    _fx_fault_tolerant_add_fat_log        Add FAT redo log              */
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),          */
76 /*                                            resulting in version 6.1    */
77 /*                                                                        */
78 /**************************************************************************/
_fx_utility_FAT_entry_write(FX_MEDIA * media_ptr,ULONG cluster,ULONG next_cluster)79 UINT  _fx_utility_FAT_entry_write(FX_MEDIA *media_ptr, ULONG cluster, ULONG next_cluster)
80 {
81 
82 UINT                status, index, i;
83 FX_FAT_CACHE_ENTRY *cache_entry_ptr;
84 #ifdef FX_ENABLE_FAULT_TOLERANT
85 ULONG               FAT_sector;
86 
87     /* While fault_tolerant is enabled, only FAT entries in the same sector are allowed to be cached. */
88     /* We must flush FAT sectors in the order of FAT chains. */
89     if (media_ptr -> fx_media_fault_tolerant_enabled &&
90         (media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_STARTED))
91     {
92 
93         if (!(media_ptr -> fx_media_fault_tolerant_state & FX_FAULT_TOLERANT_STATE_SET_FAT_CHAIN))
94         {
95 
96             /* Redirect this request to log file. */
97             return(_fx_fault_tolerant_add_FAT_log(media_ptr, cluster, next_cluster));
98         }
99 
100         /* Get sector number of the incoming FAT entry. */
101         FAT_sector = _fx_utility_FAT_sector_get(media_ptr, cluster);
102 
103         /* Is FAT sector changed? */
104         if (FAT_sector != media_ptr -> fx_media_fault_tolerant_cached_FAT_sector)
105         {
106 
107             /* Are there any cached FAT entries? */
108             if (media_ptr -> fx_media_fault_tolerant_cached_FAT_sector)
109             {
110 
111                 /* Current FAT entry is located in different sector. Force flush. */
112                 /* Flush the cached individual FAT entries */
113                 _fx_utility_FAT_flush(media_ptr);
114 
115             }
116 
117             /* Record sector number of current FAT entry. */
118             media_ptr -> fx_media_fault_tolerant_cached_FAT_sector = FAT_sector;
119         }
120     }
121 #endif /* FX_ENABLE_FAULT_TOLERANT */
122 
123 #ifndef FX_MEDIA_STATISTICS_DISABLE
124 /* Increment the number of FAT entry writes and cache hits.  */
125 media_ptr -> fx_media_fat_entry_writes++;
126 media_ptr -> fx_media_fat_entry_cache_write_hits++;
127 #endif
128 
129 /* Extended port-specific processing macro, which is by default defined to white space.  */
130 FX_UTILITY_FAT_ENTRY_WRITE_EXTENSION
131 
132 /* Calculate the area of the cache for this FAT entry.  */
133     index =  (cluster & FX_FAT_CACHE_HASH_MASK) * FX_FAT_CACHE_DEPTH;
134 
135     /* Build a pointer to the cache entry.  */
136     cache_entry_ptr =  &media_ptr -> fx_media_fat_cache[index];
137 
138     /* First search for the entry in the FAT entry cache.  */
139     for (i = 0; i < FX_FAT_CACHE_DEPTH; i++)
140     {
141 
142         /* See if the entry matches the write request.  */
143         if (((cache_entry_ptr + i) -> fx_fat_cache_entry_cluster) == cluster)
144         {
145 
146             /* Yes, we have a matching entry.  Save the new information in the FAT
147                cache and mark this entry as dirty.  */
148             (cache_entry_ptr + i) -> fx_fat_cache_entry_value =     next_cluster;
149             (cache_entry_ptr + i) -> fx_fat_cache_entry_dirty =     1;
150 
151             /* Determine if the driver has requested notification when data sectors in the media
152                become free.  This can be useful to FLASH manager software.  */
153             if ((media_ptr -> fx_media_driver_free_sector_update) && (next_cluster == FX_FREE_CLUSTER))
154             {
155 
156                 /* Yes, the driver does wish to know that these specific sector(s) are
157                    not in use.  */
158 
159 #ifndef FX_MEDIA_STATISTICS_DISABLE
160 
161                 /* Increment the number of driver release sectors requests.  */
162                 media_ptr -> fx_media_driver_release_sectors_requests++;
163 #endif
164 
165                 /* This cluster is being released so inform the driver that the
166                    corresponding sectors are now available.  */
167                 media_ptr -> fx_media_driver_request =          FX_DRIVER_RELEASE_SECTORS;
168                 media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
169                 media_ptr -> fx_media_driver_logical_sector =   (media_ptr -> fx_media_data_sector_start +
170                                                                  ((cluster - FX_FAT_ENTRY_START) * media_ptr -> fx_media_sectors_per_cluster));
171                 media_ptr -> fx_media_driver_sectors =          media_ptr -> fx_media_sectors_per_cluster;
172 
173                 /* If trace is enabled, insert this event into the trace buffer.  */
174                 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_RELEASE_SECTORS, media_ptr, media_ptr -> fx_media_driver_logical_sector, media_ptr -> fx_media_driver_sectors, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
175 
176                 /* Call the driver.  */
177                 (media_ptr -> fx_media_driver_entry)(media_ptr);
178             }
179 
180             /* Done, return successful status.  */
181             return(FX_SUCCESS);
182         }
183     }
184 
185     /* If we reach this point, we know that the FAT write request is not in
186        the cache.  */
187 
188 #ifndef FX_MEDIA_STATISTICS_DISABLE
189     /* Decrement the number of cache hits.  */
190     media_ptr -> fx_media_fat_entry_cache_write_hits--;
191 
192     /* Increment the number of cache misses.  */
193     media_ptr -> fx_media_fat_entry_cache_write_misses++;
194 #endif
195 
196     /* Determine if the oldest entry is dirty and needs to be flushed.  */
197     if (media_ptr -> fx_media_fat_cache[index + 3].fx_fat_cache_entry_dirty == 1)
198     {
199 
200         /* Flush the dirty entry so it can be used to hold the current
201            FAT entry write request.  */
202         status = _fx_utility_FAT_flush(media_ptr);
203 
204         /* Determine if the write was successful.  */
205         if (status != FX_SUCCESS)
206         {
207 
208             /* No, return error status to caller.  */
209             return(status);
210         }
211 
212     }
213 
214     /* Move all the cache entries down so the oldest is at the bottom.  */
215     *(cache_entry_ptr + 3) =  *(cache_entry_ptr + 2);
216     *(cache_entry_ptr + 2) =  *(cache_entry_ptr + 1);
217     *(cache_entry_ptr + 1) =  *(cache_entry_ptr);
218 
219     /* Save the current FAT entry write request and mark as dirty.  */
220     cache_entry_ptr -> fx_fat_cache_entry_dirty =    1;
221     cache_entry_ptr -> fx_fat_cache_entry_cluster =  cluster;
222     cache_entry_ptr -> fx_fat_cache_entry_value =    next_cluster;
223 
224     /* Determine if the driver has requested notification when data sectors in the media
225        become free.  This can be useful to FLASH manager software.  */
226     if ((media_ptr -> fx_media_driver_free_sector_update) && (next_cluster == FX_FREE_CLUSTER))
227     {
228 
229         /* Yes, the driver does wish to know that these specific sector(s) are
230            not in use.  */
231 
232 #ifndef FX_MEDIA_STATISTICS_DISABLE
233 
234         /* Increment the number of driver release sectors requests.  */
235         media_ptr -> fx_media_driver_release_sectors_requests++;
236 #endif
237 
238         /* This cluster is being released so inform the driver that the
239               corresponding sectors are now available.  */
240         media_ptr -> fx_media_driver_request =          FX_DRIVER_RELEASE_SECTORS;
241         media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
242         media_ptr -> fx_media_driver_logical_sector =   (media_ptr -> fx_media_data_sector_start +
243                                                          ((cluster - FX_FAT_ENTRY_START) * media_ptr -> fx_media_sectors_per_cluster));
244         media_ptr -> fx_media_driver_sectors =          media_ptr -> fx_media_sectors_per_cluster;
245 
246         /* If trace is enabled, insert this event into the trace buffer.  */
247         FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_RELEASE_SECTORS, media_ptr, media_ptr -> fx_media_driver_logical_sector, media_ptr -> fx_media_driver_sectors, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
248 
249         /* Call the driver.  */
250         (media_ptr -> fx_media_driver_entry)(media_ptr);
251     }
252 
253     /* Return success to caller.  */
254     return(FX_SUCCESS);
255 }
256 
257