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 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _fx_utility_logical_sector_cache_entry_read         PORTABLE C      */
37 /*                                                           6.1.10       */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    William E. Lamie, Microsoft Corporation                             */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function handles logical sector cache read requests for the    */
45 /*    logical sector read function. If the function finds the requested   */
46 /*    sector in the cache, it setup the appropriate pointers and          */
47 /*    returns a FX_NULL.                                                  */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    media_ptr                             Media control block pointer   */
52 /*    logical_sector                        Logical sector number         */
53 /*    previous_cache_entry                  Pointer to previous entry in  */
54 /*                                            non-hashed cache            */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    FX_CACHED_SECTOR *                    Cache entry to setup          */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    None                                                                */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    _fx_utility_logical_sector_read       Logical sector read function  */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
73 /*  09-30-2020     William E. Lamie         Modified comment(s), and      */
74 /*                                            added conditional to        */
75 /*                                            disable cache,              */
76 /*                                            resulting in version 6.1    */
77 /*  01-31-2022     William E. Lamie         Modified comment(s), fixed    */
78 /*                                            errors without cache,       */
79 /*                                            resulting in version 6.1.10 */
80 /*                                                                        */
81 /**************************************************************************/
_fx_utility_logical_sector_cache_entry_read(FX_MEDIA * media_ptr,ULONG64 logical_sector,FX_CACHED_SECTOR ** previous_cache_entry)82 FX_CACHED_SECTOR  *_fx_utility_logical_sector_cache_entry_read(FX_MEDIA *media_ptr, ULONG64 logical_sector,
83                                                                FX_CACHED_SECTOR **previous_cache_entry)
84 {
85 
86 #ifndef FX_DISABLE_CACHE
87 FX_CACHED_SECTOR *cache_entry;
88 FX_CACHED_SECTOR  temp_storage;
89 ULONG             cache_size;
90 ULONG             index;
91 
92 
93     /* Determine if the logical sector cache access should use the hash function.  */
94     if (media_ptr -> fx_media_sector_cache_hashed)
95     {
96 
97         /* Calculate the area of the cache for this logical sector.  */
98 
99         /* First compute the hashed value of this index by simply using the lower bits of
100            the sector number.  */
101         index =  (ULONG)(logical_sector & media_ptr -> fx_media_sector_cache_hash_mask);
102 
103         /* Set the bit indicating there is one or more valid sectors at this cache index.  */
104         media_ptr -> fx_media_sector_cache_hashed_sector_valid |=  ((ULONG)1) << (index % 32);
105 
106         /* Compute the actual array index by multiplying by the cache depth.  */
107         index =  index * FX_SECTOR_CACHE_DEPTH;
108 
109         /* Build a pointer to the cache entry.  */
110         cache_entry =  &(media_ptr -> fx_media_sector_cache[index]);
111 
112         /* Determine if the logical sector is in the cache - assuming the depth of the
113            sector cache is 4 entries.  */
114         if ((cache_entry -> fx_cached_sector_valid) && (cache_entry -> fx_cached_sector == logical_sector))
115         {
116 
117             /* Yes, we found a match.  Simply setup the pointer to this
118                buffer and return.  */
119             media_ptr -> fx_media_memory_buffer =  cache_entry -> fx_cached_sector_memory_buffer;
120 
121 #ifndef FX_MEDIA_STATISTICS_DISABLE
122 
123             /* Increment the number of logical sectors cache read hits.  */
124             media_ptr -> fx_media_logical_sector_cache_read_hits++;
125 #endif
126             /* Success, return to caller immediately!  */
127             return(FX_NULL);
128         }
129         else if (((cache_entry + 1) -> fx_cached_sector_valid) && ((cache_entry + 1) -> fx_cached_sector == logical_sector))
130         {
131 
132             /* Yes, we found a match.  Simply setup the pointer to this
133                buffer and return.  */
134             media_ptr -> fx_media_memory_buffer =  (cache_entry + 1) -> fx_cached_sector_memory_buffer;
135 
136 #ifndef FX_MEDIA_STATISTICS_DISABLE
137 
138             /* Increment the number of logical sectors cache read hits.  */
139             media_ptr -> fx_media_logical_sector_cache_read_hits++;
140 #endif
141 
142             /* Swap the first and second cache entries to keep the most recently used
143                at the top.  */
144             temp_storage.fx_cached_sector_memory_buffer =           (cache_entry) -> fx_cached_sector_memory_buffer;
145             temp_storage.fx_cached_sector =                         (cache_entry) -> fx_cached_sector;
146             temp_storage.fx_cached_sector_buffer_dirty =            (cache_entry) -> fx_cached_sector_buffer_dirty;
147             temp_storage.fx_cached_sector_valid =                   (cache_entry) -> fx_cached_sector_valid;
148             temp_storage.fx_cached_sector_type =                    (cache_entry) -> fx_cached_sector_type;
149 
150             (cache_entry) -> fx_cached_sector_memory_buffer =       (cache_entry + 1) -> fx_cached_sector_memory_buffer;
151             (cache_entry) -> fx_cached_sector =                     (cache_entry + 1) -> fx_cached_sector;
152             (cache_entry) -> fx_cached_sector_buffer_dirty =        (cache_entry + 1) -> fx_cached_sector_buffer_dirty;
153             (cache_entry) -> fx_cached_sector_valid =               (cache_entry + 1) -> fx_cached_sector_valid;
154             (cache_entry) -> fx_cached_sector_type =                (cache_entry + 1) -> fx_cached_sector_type;
155 
156             (cache_entry + 1) -> fx_cached_sector_memory_buffer =   temp_storage.fx_cached_sector_memory_buffer;
157             (cache_entry + 1) -> fx_cached_sector =                 temp_storage.fx_cached_sector;
158             (cache_entry + 1) -> fx_cached_sector_buffer_dirty =    temp_storage.fx_cached_sector_buffer_dirty;
159             (cache_entry + 1) -> fx_cached_sector_valid =           temp_storage.fx_cached_sector_valid;
160             (cache_entry + 1) -> fx_cached_sector_type =            temp_storage.fx_cached_sector_type;
161 
162             /* Success, return to caller immediately!  */
163             return(FX_NULL);
164         }
165         else if (((cache_entry + 2) -> fx_cached_sector_valid) && ((cache_entry + 2) -> fx_cached_sector == logical_sector))
166         {
167 
168             /* Yes, we found a match.  Simply setup the pointer to this
169                buffer and return.  */
170             media_ptr -> fx_media_memory_buffer =  (cache_entry + 2) -> fx_cached_sector_memory_buffer;
171 
172 #ifndef FX_MEDIA_STATISTICS_DISABLE
173 
174             /* Increment the number of logical sectors cache read hits.  */
175             media_ptr -> fx_media_logical_sector_cache_read_hits++;
176 #endif
177 
178             /* Move the third entry to the top and the first two entries down.  */
179             temp_storage.fx_cached_sector_memory_buffer =           (cache_entry) -> fx_cached_sector_memory_buffer;
180             temp_storage.fx_cached_sector =                         (cache_entry) -> fx_cached_sector;
181             temp_storage.fx_cached_sector_buffer_dirty =            (cache_entry) -> fx_cached_sector_buffer_dirty;
182             temp_storage.fx_cached_sector_valid =                   (cache_entry) -> fx_cached_sector_valid;
183             temp_storage.fx_cached_sector_type =                    (cache_entry) -> fx_cached_sector_type;
184 
185             (cache_entry) -> fx_cached_sector_memory_buffer =       (cache_entry + 2) -> fx_cached_sector_memory_buffer;
186             (cache_entry) -> fx_cached_sector =                     (cache_entry + 2) -> fx_cached_sector;
187             (cache_entry) -> fx_cached_sector_buffer_dirty =        (cache_entry + 2) -> fx_cached_sector_buffer_dirty;
188             (cache_entry) -> fx_cached_sector_valid =               (cache_entry + 2) -> fx_cached_sector_valid;
189             (cache_entry) -> fx_cached_sector_type =                (cache_entry + 2) -> fx_cached_sector_type;
190 
191             (cache_entry + 2) -> fx_cached_sector_memory_buffer =   (cache_entry + 1) -> fx_cached_sector_memory_buffer;
192             (cache_entry + 2) -> fx_cached_sector =                 (cache_entry + 1) -> fx_cached_sector;
193             (cache_entry + 2) -> fx_cached_sector_buffer_dirty =    (cache_entry + 1) -> fx_cached_sector_buffer_dirty;
194             (cache_entry + 2) -> fx_cached_sector_valid =           (cache_entry + 1) -> fx_cached_sector_valid;
195             (cache_entry + 2) -> fx_cached_sector_type =            (cache_entry + 1) -> fx_cached_sector_type;
196 
197             (cache_entry + 1) -> fx_cached_sector_memory_buffer =   temp_storage.fx_cached_sector_memory_buffer;
198             (cache_entry + 1) -> fx_cached_sector =                 temp_storage.fx_cached_sector;
199             (cache_entry + 1) -> fx_cached_sector_buffer_dirty =    temp_storage.fx_cached_sector_buffer_dirty;
200             (cache_entry + 1) -> fx_cached_sector_valid =           temp_storage.fx_cached_sector_valid;
201             (cache_entry + 1) -> fx_cached_sector_type =            temp_storage.fx_cached_sector_type;
202 
203             /* Success, return to caller immediately!  */
204             return(FX_NULL);
205         }
206         else if (((cache_entry + 3) -> fx_cached_sector_valid) && ((cache_entry + 3) -> fx_cached_sector == logical_sector))
207         {
208 
209             /* Yes, we found a match.  Simply setup the pointer to this
210                buffer and return.  */
211             media_ptr -> fx_media_memory_buffer =  (cache_entry + 3) -> fx_cached_sector_memory_buffer;
212 
213 #ifndef FX_MEDIA_STATISTICS_DISABLE
214 
215             /* Increment the number of logical sectors cache read hits.  */
216             media_ptr -> fx_media_logical_sector_cache_read_hits++;
217 #endif
218 
219             /* Move the last entry to the top and the first three entries down.  */
220             temp_storage.fx_cached_sector_memory_buffer =           (cache_entry) -> fx_cached_sector_memory_buffer;
221             temp_storage.fx_cached_sector =                         (cache_entry) -> fx_cached_sector;
222             temp_storage.fx_cached_sector_buffer_dirty =            (cache_entry) -> fx_cached_sector_buffer_dirty;
223             temp_storage.fx_cached_sector_valid =                   (cache_entry) -> fx_cached_sector_valid;
224             temp_storage.fx_cached_sector_type =                    (cache_entry) -> fx_cached_sector_type;
225 
226             (cache_entry) -> fx_cached_sector_memory_buffer =       (cache_entry + 3) -> fx_cached_sector_memory_buffer;
227             (cache_entry) -> fx_cached_sector =                     (cache_entry + 3) -> fx_cached_sector;
228             (cache_entry) -> fx_cached_sector_buffer_dirty =        (cache_entry + 3) -> fx_cached_sector_buffer_dirty;
229             (cache_entry) -> fx_cached_sector_valid =               (cache_entry + 3) -> fx_cached_sector_valid;
230             (cache_entry) -> fx_cached_sector_type =                (cache_entry + 3) -> fx_cached_sector_type;
231 
232             (cache_entry + 3) -> fx_cached_sector_memory_buffer =   (cache_entry + 2) -> fx_cached_sector_memory_buffer;
233             (cache_entry + 3) -> fx_cached_sector =                 (cache_entry + 2) -> fx_cached_sector;
234             (cache_entry + 3) -> fx_cached_sector_buffer_dirty =    (cache_entry + 2) -> fx_cached_sector_buffer_dirty;
235             (cache_entry + 3) -> fx_cached_sector_valid =           (cache_entry + 2) -> fx_cached_sector_valid;
236             (cache_entry + 3) -> fx_cached_sector_type =            (cache_entry + 2) -> fx_cached_sector_type;
237 
238             (cache_entry + 2) -> fx_cached_sector_memory_buffer =   (cache_entry + 1) -> fx_cached_sector_memory_buffer;
239             (cache_entry + 2) -> fx_cached_sector =                 (cache_entry + 1) -> fx_cached_sector;
240             (cache_entry + 2) -> fx_cached_sector_buffer_dirty =    (cache_entry + 1) -> fx_cached_sector_buffer_dirty;
241             (cache_entry + 2) -> fx_cached_sector_valid =           (cache_entry + 1) -> fx_cached_sector_valid;
242             (cache_entry + 2) -> fx_cached_sector_type =            (cache_entry + 1) -> fx_cached_sector_type;
243 
244             (cache_entry + 1) -> fx_cached_sector_memory_buffer =   temp_storage.fx_cached_sector_memory_buffer;
245             (cache_entry + 1) -> fx_cached_sector =                 temp_storage.fx_cached_sector;
246             (cache_entry + 1) -> fx_cached_sector_buffer_dirty =    temp_storage.fx_cached_sector_buffer_dirty;
247             (cache_entry + 1) -> fx_cached_sector_valid =           temp_storage.fx_cached_sector_valid;
248             (cache_entry + 1) -> fx_cached_sector_type =            temp_storage.fx_cached_sector_type;
249 
250             /* Success, return to caller immediately!  */
251             return(FX_NULL);
252         }
253 
254         /* At this point we have a cache miss.  We need to move all of the sectors down one slot, swapping
255            the 4th entry with the first.  */
256         temp_storage.fx_cached_sector_memory_buffer =           (cache_entry + 3) -> fx_cached_sector_memory_buffer;
257         temp_storage.fx_cached_sector =                         (cache_entry + 3) -> fx_cached_sector;
258         temp_storage.fx_cached_sector_buffer_dirty =            (cache_entry + 3) -> fx_cached_sector_buffer_dirty;
259         temp_storage.fx_cached_sector_valid =                   (cache_entry + 3) -> fx_cached_sector_valid;
260         temp_storage.fx_cached_sector_type =                    (cache_entry + 3) -> fx_cached_sector_type;
261 
262         (cache_entry + 3) -> fx_cached_sector_memory_buffer =   (cache_entry + 2) -> fx_cached_sector_memory_buffer;
263         (cache_entry + 3) -> fx_cached_sector =                 (cache_entry + 2) -> fx_cached_sector;
264         (cache_entry + 3) -> fx_cached_sector_buffer_dirty =    (cache_entry + 2) -> fx_cached_sector_buffer_dirty;
265         (cache_entry + 3) -> fx_cached_sector_valid =           (cache_entry + 2) -> fx_cached_sector_valid;
266         (cache_entry + 3) -> fx_cached_sector_type =            (cache_entry + 2) -> fx_cached_sector_type;
267 
268         (cache_entry + 2) -> fx_cached_sector_memory_buffer =   (cache_entry + 1) -> fx_cached_sector_memory_buffer;
269         (cache_entry + 2) -> fx_cached_sector =                 (cache_entry + 1) -> fx_cached_sector;
270         (cache_entry + 2) -> fx_cached_sector_buffer_dirty =    (cache_entry + 1) -> fx_cached_sector_buffer_dirty;
271         (cache_entry + 2) -> fx_cached_sector_valid =           (cache_entry + 1) -> fx_cached_sector_valid;
272         (cache_entry + 2) -> fx_cached_sector_type =            (cache_entry + 1) -> fx_cached_sector_type;
273 
274         (cache_entry + 1) -> fx_cached_sector_memory_buffer =   (cache_entry) -> fx_cached_sector_memory_buffer;
275         (cache_entry + 1) -> fx_cached_sector =                 (cache_entry) -> fx_cached_sector;
276         (cache_entry + 1) -> fx_cached_sector_buffer_dirty =    (cache_entry) -> fx_cached_sector_buffer_dirty;
277         (cache_entry + 1) -> fx_cached_sector_valid =           (cache_entry) -> fx_cached_sector_valid;
278         (cache_entry + 1) -> fx_cached_sector_type =            (cache_entry) -> fx_cached_sector_type;
279 
280         (cache_entry) -> fx_cached_sector_memory_buffer =       temp_storage.fx_cached_sector_memory_buffer;
281         (cache_entry) -> fx_cached_sector =                     temp_storage.fx_cached_sector;
282         (cache_entry) -> fx_cached_sector_buffer_dirty =        temp_storage.fx_cached_sector_buffer_dirty;
283         (cache_entry) -> fx_cached_sector_valid =               temp_storage.fx_cached_sector_valid;
284         (cache_entry) -> fx_cached_sector_type =                temp_storage.fx_cached_sector_type;
285 
286         /* Set the previous pointer to NULL to avoid the linked list update below.  */
287         *previous_cache_entry =  FX_NULL;
288     }
289     else
290     {
291 
292         /* Search for an entry in the cache that matches this request.  */
293         cache_size =            media_ptr -> fx_media_sector_cache_size;
294         cache_entry =           media_ptr -> fx_media_sector_cache_list_ptr;
295         *previous_cache_entry =  FX_NULL;
296 
297         /* Look at the cache entries until a match is found or the end of
298            the cache is reached.  */
299         while (cache_size--)
300         {
301 
302             /* Determine if the requested sector has been found.  */
303             if ((cache_entry -> fx_cached_sector_valid) && (cache_entry -> fx_cached_sector == logical_sector))
304             {
305 
306                 /* Yes, we found a match.  Simply setup the pointer to this
307                    buffer and return.  */
308                 media_ptr -> fx_media_memory_buffer =  cache_entry -> fx_cached_sector_memory_buffer;
309 
310                 /* Determine if we need to update the last used list.  */
311                 if (*previous_cache_entry)
312                 {
313 
314                     /* Yes, the current entry is not at the front of the list
315                        so we need to change the order.  */
316 
317                     /* Link the previous entry to this entry's next pointer.  */
318                     (*previous_cache_entry) -> fx_cached_sector_next_used =
319                         cache_entry -> fx_cached_sector_next_used;
320 
321                     /* Place this entry at the head of the list.  */
322                     cache_entry -> fx_cached_sector_next_used =
323                         media_ptr -> fx_media_sector_cache_list_ptr;
324                     media_ptr -> fx_media_sector_cache_list_ptr =  cache_entry;
325                 }
326 
327 #ifndef FX_MEDIA_STATISTICS_DISABLE
328 
329                 /* Increment the number of logical sectors cache read hits.  */
330                 media_ptr -> fx_media_logical_sector_cache_read_hits++;
331 #endif
332 
333                 /* Success, return to caller immediately!  */
334                 return(FX_NULL);
335             }
336 
337             /* Otherwise, we have not found the cached entry yet.  */
338 
339             /* If there are more entries, move to the next one.  */
340             if (cache_entry -> fx_cached_sector_next_used)
341             {
342 
343                 *previous_cache_entry =  cache_entry;
344                 cache_entry =           cache_entry -> fx_cached_sector_next_used;
345             }
346         }
347     }
348 
349     /* The requested sector is not in cache, return the last cache entry.  */
350     return(cache_entry);
351 #else
352     FX_PARAMETER_NOT_USED(media_ptr);
353     FX_PARAMETER_NOT_USED(logical_sector);
354     FX_PARAMETER_NOT_USED(previous_cache_entry);
355     return(FX_NULL);
356 #endif /* FX_DISABLE_CACHE */
357 }
358 
359