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 /** Fault Tolerant */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define FX_SOURCE_CODE
23
24 #include "fx_api.h"
25 #include "fx_utility.h"
26 #include "fx_directory.h"
27 #include "fx_fault_tolerant.h"
28
29
30 #ifdef FX_ENABLE_FAULT_TOLERANT
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _fx_fault_tolerant_enable PORTABLE C */
36 /* 6.2.0 */
37 /* AUTHOR */
38 /* */
39 /* William E. Lamie, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function enables the FileX Fault Tolerant feature. It first */
44 /* searches for a valid log file. A valid log file indicates the */
45 /* previous write operation failed, and appropriate action now must */
46 /* be taken to restore the integrity of the file system. Once the */
47 /* recovery effort is completed, the file system is properly restored. */
48 /* An empty log file indicates the previous write operation was */
49 /* successfully completed and no action needs to be taken at this */
50 /* point. If the file system does not have a log file, or the */
51 /* checksum is not valid, it is an indication either the file system */
52 /* is not under the protection of FileX Fault Tolerant. A new log */
53 /* file is created. */
54 /* */
55 /* INPUT */
56 /* */
57 /* media_ptr Media control block pointer */
58 /* memory_buffer Pointer to memory buffer. */
59 /* memory_size Size of memory buffer. */
60 /* */
61 /* OUTPUT */
62 /* */
63 /* return status */
64 /* */
65 /* CALLS */
66 /* */
67 /* _fx_fault_tolerant_calculate_checksum Compute Checksum of data */
68 /* _fx_fault_tolerant_apply_logs Apply logs into file system */
69 /* _fx_fault_tolerant_recover Recover FAT chain */
70 /* _fx_fault_tolerant_reset_log_file Reset the log file */
71 /* _fx_fault_tolerant_read_log_file Read log file to cache */
72 /* _fx_utility_FAT_entry_read Read a FAT entry */
73 /* _fx_utility_16_unsigned_read Read a USHORT from memory */
74 /* _fx_utility_32_unsigned_read Read a ULONG from memory */
75 /* */
76 /* CALLED BY */
77 /* */
78 /* Application Code */
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), */
86 /* resulting in version 6.1 */
87 /* 10-31-2022 Tiejun Zhou Modified comment(s), */
88 /* fixed memory buffer when */
89 /* cache is disabled, */
90 /* resulting in version 6.2.0 */
91 /* */
92 /**************************************************************************/
_fx_fault_tolerant_enable(FX_MEDIA * media_ptr,VOID * memory_buffer,UINT memory_size)93 UINT _fx_fault_tolerant_enable(FX_MEDIA *media_ptr, VOID *memory_buffer, UINT memory_size)
94 {
95 ULONG start_cluster;
96 ULONG FAT_value;
97 UINT status;
98 ULONG checksum;
99 ULONG total_size;
100 FX_FAULT_TOLERANT_LOG_HEADER *log_header;
101 FX_FAULT_TOLERANT_FAT_CHAIN *FAT_chain;
102 ULONG cluster_number;
103 ULONG i, j;
104 ULONG FAT_entry, FAT_sector, FAT_read_sectors;
105 ULONG bytes_in_buffer;
106 ULONG clusters;
107 ULONG bytes_per_sector;
108 ULONG bytes_per_cluster;
109
110 /* Protect against other threads accessing the media. */
111 FX_PROTECT
112
113 /* Calculate clusters needed for fault tolerant log. */
114 bytes_per_sector = media_ptr -> fx_media_bytes_per_sector;
115 bytes_per_cluster = bytes_per_sector * media_ptr -> fx_media_sectors_per_cluster;
116
117 if (bytes_per_cluster == 0)
118 {
119
120 /* Release media protection. */
121 FX_UNPROTECT
122
123 return(FX_MEDIA_INVALID);
124 }
125
126 clusters = (FX_FAULT_TOLERANT_MAXIMUM_LOG_FILE_SIZE + bytes_per_cluster - 1) / bytes_per_cluster;
127 media_ptr -> fx_media_fault_tolerant_clusters = clusters;
128
129 /* Check buffer size requirement. */
130 if (memory_size < bytes_per_sector)
131 {
132
133 /* Release media protection. */
134 FX_UNPROTECT
135
136 return(FX_NOT_ENOUGH_MEMORY);
137 }
138
139
140 if (media_ptr -> fx_media_FAT32_additional_info_sector)
141 {
142
143 /* A 32-bit FAT is present. Read directly into the logical sector
144 cache memory to optimize I/O on larger devices. Since we are looking for
145 values of zero, endian issues are not important. */
146 /* Force update the available cluster. */
147
148 #ifndef FX_DISABLE_CACHE
149 /* Invalidate the current logical sector cache. */
150 _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_total_sectors), FX_TRUE);
151
152 /* Reset the memory pointer. */
153 media_ptr -> fx_media_memory_buffer = media_ptr -> fx_media_sector_cache[0].fx_cached_sector_memory_buffer;
154 #endif /* FX_DISABLE_CACHE */
155
156 /* Reset the available cluster. */
157 media_ptr -> fx_media_available_clusters = 0;
158
159 /* Loop through all FAT sectors in the primary FAT. The first two entries are
160 examined in this loop, but they are always unavailable. */
161 cluster_number = 0;
162 #ifndef FX_DISABLE_CACHE
163 for (i = 0; i < media_ptr -> fx_media_sectors_per_FAT; i = i + media_ptr -> fx_media_sector_cache_size)
164 {
165
166 /* Calculate the starting next FAT sector. */
167 FAT_sector = media_ptr -> fx_media_reserved_sectors + i;
168
169 /* Calculate how many sectors to read. */
170 FAT_read_sectors = media_ptr -> fx_media_sectors_per_FAT - i;
171
172 /* Determine if there is not enough memory to read the remaining FAT sectors. */
173 if (FAT_read_sectors > media_ptr -> fx_media_sector_cache_size)
174 {
175 FAT_read_sectors = media_ptr -> fx_media_sector_cache_size;
176 }
177 #else
178 /* Reset the buffer sector. */
179 media_ptr -> fx_media_memory_buffer_sector = (ULONG64)-1;
180 for (i = 0; i < media_ptr -> fx_media_sectors_per_FAT; i++)
181 {
182
183 /* Calculate the starting next FAT sector. */
184 FAT_sector = media_ptr -> fx_media_reserved_sectors + i;
185
186 /* Calculate how many sectors to read. */
187 FAT_read_sectors = 1;
188 #endif /* FX_DISABLE_CACHE */
189
190 /* Read the FAT sectors directly from the driver. */
191 media_ptr -> fx_media_driver_request = FX_DRIVER_READ;
192 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
193 media_ptr -> fx_media_driver_buffer = media_ptr -> fx_media_memory_buffer;
194 media_ptr -> fx_media_driver_logical_sector = FAT_sector;
195 media_ptr -> fx_media_driver_sectors = FAT_read_sectors;
196 media_ptr -> fx_media_driver_sector_type = FX_FAT_SECTOR;
197
198 /* If trace is enabled, insert this event into the trace buffer. */
199 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_READ, media_ptr, FAT_sector, FAT_read_sectors, media_ptr -> fx_media_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
200
201 /* Invoke the driver to read the FAT sectors. */
202 (media_ptr -> fx_media_driver_entry) (media_ptr);
203
204 /* Determine if the read was successful. */
205 if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
206 {
207
208 /* Release media protection. */
209 FX_UNPROTECT
210
211 return(FX_FAT_READ_ERROR);
212 }
213
214 /* Calculate the number of bytes in the buffer. */
215 bytes_in_buffer = (media_ptr -> fx_media_bytes_per_sector * FAT_read_sectors);
216
217 /* Walk through the sector cache memory to search for available clusters and the first
218 available if not already found. */
219 for (j = 0; j < bytes_in_buffer;)
220 {
221
222 /* Pickup 32-bit FAT entry. */
223 FAT_entry = *((ULONG *)&(media_ptr -> fx_media_memory_buffer[j]));
224
225 /* Advance to next FAT entry. */
226 j = j + 4;
227
228 /* Determine if the FAT entry is free. */
229 if (FAT_entry == FX_FREE_CLUSTER)
230 {
231
232 /* Entry is free, increment available clusters. */
233 media_ptr -> fx_media_available_clusters++;
234
235 /* Determine if the starting free cluster has been found yet. */
236 if (media_ptr -> fx_media_cluster_search_start == 0)
237 {
238
239 /* Remember the first free cluster to start further searches from. */
240 media_ptr -> fx_media_cluster_search_start = cluster_number;
241 }
242 }
243
244 /* Increment the cluster number. */
245 cluster_number++;
246
247 /* Determine if we have reviewed all FAT entries. */
248 if (cluster_number >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
249 {
250
251 /* Yes, we have looked at all the FAT entries. */
252
253 /* Ensure that the outer loop terminates as well. */
254 i = media_ptr -> fx_media_sectors_per_FAT;
255 break;
256 }
257 }
258 }
259 }
260
261 /* Store memory buffer and size. */
262 media_ptr -> fx_media_fault_tolerant_memory_buffer = (UCHAR *)memory_buffer;
263 if (memory_size > (clusters * bytes_per_cluster))
264 {
265 media_ptr -> fx_media_fault_tolerant_memory_buffer_size = clusters * bytes_per_cluster;
266 }
267 else
268 {
269 media_ptr -> fx_media_fault_tolerant_memory_buffer_size = memory_size / bytes_per_sector * bytes_per_sector;
270 }
271
272 /* Read the boot sector from the device. */
273 media_ptr -> fx_media_driver_request = FX_DRIVER_BOOT_READ;
274 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
275 media_ptr -> fx_media_driver_buffer = (UCHAR *)memory_buffer;
276 media_ptr -> fx_media_driver_sectors = 1;
277 media_ptr -> fx_media_driver_sector_type = FX_BOOT_SECTOR;
278
279 /* If trace is enabled, insert this event into the trace buffer. */
280 FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_BOOT_READ, media_ptr, memory_buffer, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
281
282 /* Invoke the driver to read the boot sector. */
283 (media_ptr -> fx_media_driver_entry) (media_ptr);
284
285 /* Determine if the boot sector was read correctly. */
286 if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
287 {
288
289 /* Release media protection. */
290 FX_UNPROTECT
291
292 /* Return the boot sector error status. */
293 return(FX_BOOT_ERROR);
294 }
295
296 /* Check whether the boot index is used. */
297 start_cluster = _fx_utility_32_unsigned_read((UCHAR *)memory_buffer + FX_FAULT_TOLERANT_BOOT_INDEX);
298 if (start_cluster != 0)
299 {
300
301 /* The location of the fault tolerant log file is found. Need to verify the integrity of the log file. */
302 if ((start_cluster >= FX_FAT_ENTRY_START) && (start_cluster < media_ptr -> fx_media_fat_reserved))
303 {
304
305 /* Check whether this cluster is used. */
306 for (i = 0; i < clusters; i++)
307 {
308
309 /* Read FAT entry. */
310 status = _fx_utility_FAT_entry_read(media_ptr, start_cluster + i, &FAT_value);
311
312 /* Check for a bad status. */
313 if (status != FX_SUCCESS)
314 {
315
316 /* Release media protection. */
317 FX_UNPROTECT
318
319 /* Return the bad status. */
320 return(status);
321 }
322
323 if (i < clusters - 1)
324 {
325 if (FAT_value != (start_cluster + i + 1))
326 {
327
328 /* Mark invalid. */
329 start_cluster = 0;
330 break;
331 }
332 }
333 else if (FAT_value != media_ptr -> fx_media_fat_last)
334 {
335
336 /* Mark invalid. */
337 start_cluster = 0;
338 break;
339 }
340 }
341
342 /* Is this FAT entry occupied by log file? */
343 if (start_cluster)
344 {
345
346 /* Set the start cluster. */
347 media_ptr -> fx_media_fault_tolerant_start_cluster = start_cluster;
348
349 /* Read log file from file system to memory. */
350 status = _fx_fault_tolerant_read_log_file(media_ptr);
351
352 /* Check for good completion status. */
353 if (status != FX_SUCCESS)
354 {
355
356 /* Release media protection. */
357 FX_UNPROTECT
358
359 /* Return the error status. */
360 return(status);
361 }
362
363 /* Set log header and FAT chain pointer. */
364 log_header = (FX_FAULT_TOLERANT_LOG_HEADER *)media_ptr -> fx_media_fault_tolerant_memory_buffer;
365 FAT_chain = (FX_FAULT_TOLERANT_FAT_CHAIN *)(media_ptr -> fx_media_fault_tolerant_memory_buffer +
366 FX_FAULT_TOLERANT_FAT_CHAIN_OFFSET);
367
368 /* Verify ID field. */
369 if (_fx_utility_32_unsigned_read((UCHAR *)&log_header -> fx_fault_tolerant_log_header_id) == FX_FAULT_TOLERANT_ID)
370 {
371
372 /* Calculate checksum of log header. */
373 checksum = _fx_fault_tolerant_calculate_checksum((UCHAR *)log_header,
374 FX_FAULT_TOLERANT_LOG_HEADER_SIZE);
375
376 if (checksum == 0)
377 {
378
379 /* Fault tolerant log file is valid. */
380 /* Initialize file size. */
381 total_size = _fx_utility_16_unsigned_read((UCHAR *)&log_header -> fx_fault_tolerant_log_header_total_size);
382 media_ptr -> fx_media_fault_tolerant_file_size = total_size;
383
384
385 /* Verify the checksum of the FAT chain. */
386 checksum = _fx_fault_tolerant_calculate_checksum((UCHAR *)FAT_chain,
387 FX_FAULT_TOLERANT_FAT_CHAIN_SIZE);
388
389 if (checksum == 0)
390 {
391
392 /* Checksum of FAT chain is correct. */
393
394 if (total_size > (FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET + FX_FAULT_TOLERANT_LOG_HEADER_SIZE))
395 {
396
397 /* Log content is present. */
398 /* Now verify the checksum of log content. */
399 checksum = _fx_fault_tolerant_calculate_checksum((media_ptr -> fx_media_fault_tolerant_memory_buffer +
400 FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET),
401 (total_size - FX_FAULT_TOLERANT_LOG_CONTENT_OFFSET));
402 if (checksum == 0)
403 {
404
405 /* Checksum of log content is correct. */
406
407 /* Extended port-specific processing macro, which is by default defined to white space. */
408 FX_FAULT_TOLERANT_ENABLE_EXTENSION
409
410 /* This is the situation where the log file contains log entries. This is an indication
411 that previous write operation did not complete successfully. Need to apply the log entries
412 to recover the previous write operation, effectively to finish up the previous write operation. */
413 status = _fx_fault_tolerant_apply_logs(media_ptr);
414 }
415 }
416 else
417 {
418
419 /* Extended port-specific processing macro, which is by default defined to white space. */
420 FX_FAULT_TOLERANT_ENABLE_EXTENSION
421
422 /* The log file does not contain log content but the FAT chain operation information is present.
423 This is the situation where the FAT chain has been modified but the rest of the content of these
424 clusters are not updated yet. In this situation, the previous FAT chain operation needs to be
425 reverted to restore the file system back to its state prior to the write operation. */
426 status = _fx_fault_tolerant_recover(media_ptr);
427 }
428
429 if (status != FX_SUCCESS)
430 {
431
432 /* Release media protection. */
433 FX_UNPROTECT
434
435 /* Return the error status. */
436 return(status);
437 }
438 }
439 }
440 }
441 }
442 }
443 else
444 {
445
446 /* Not a valid cluster number. Set the flag to create a new log file. */
447 start_cluster = 0;
448 }
449 }
450
451 /* Check whether or not to create a log file. */
452 if (start_cluster == 0)
453 {
454
455 /* Create log file. */
456 status = _fx_fault_tolerant_create_log_file(media_ptr);
457
458 if (status != FX_SUCCESS)
459 {
460
461 /* Release media protection. */
462 FX_UNPROTECT
463
464 /* Return the error status. */
465 return(status);
466 }
467 }
468
469 /* Reset log file. */
470 status = _fx_fault_tolerant_reset_log_file(media_ptr);
471
472 if (status != FX_SUCCESS)
473 {
474
475 /* Release media protection. */
476 FX_UNPROTECT
477
478 /* Return the error status. */
479 return(status);
480 }
481
482 /* Mark fault tolerant feature is enabled. */
483 media_ptr -> fx_media_fault_tolerant_enabled = FX_TRUE;
484
485 /* Reset the transaction count. */
486 media_ptr -> fx_media_fault_tolerant_transaction_count = 0;
487
488 /* Initialize the sector number of cached FAT entries. */
489 media_ptr -> fx_media_fault_tolerant_cached_FAT_sector = 0;
490
491 /* Release media protection. */
492 FX_UNPROTECT
493
494 /* Return the error status. */
495 return(FX_SUCCESS);
496 }
497
498 #endif /* FX_ENABLE_FAULT_TOLERANT */
499
500