]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/EnhancedFatDxe/Flush.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / Flush.c
CommitLineData
cae7420b
DB
1/** @file\r
2 Routines that check references and flush OFiles\r
b9ec9330 3\r
149d6335 4Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
eb6cb4ce 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
b9ec9330
QH
6\r
7\r
cae7420b 8**/\r
b9ec9330 9\r
cae7420b 10#include "Fat.h"\r
b9ec9330 11\r
cae7420b 12/**\r
b9ec9330 13\r
cae7420b 14 Flushes all data associated with the file handle.\r
b9ec9330 15\r
cae7420b
DB
16 @param FHand - Handle to file to flush.\r
17 @param Token - A pointer to the token associated with the transaction.\r
b9ec9330 18\r
cae7420b
DB
19 @retval EFI_SUCCESS - Flushed the file successfully.\r
20 @retval EFI_WRITE_PROTECTED - The volume is read only.\r
21 @retval EFI_ACCESS_DENIED - The file is read only.\r
22 @return Others - Flushing of the file failed.\r
b9ec9330 23\r
cae7420b 24**/\r
b9ec9330
QH
25EFI_STATUS\r
26EFIAPI\r
149d6335
RN
27FatFlushEx (\r
28 IN EFI_FILE_PROTOCOL *FHand,\r
29 IN EFI_FILE_IO_TOKEN *Token\r
b9ec9330 30 )\r
b9ec9330
QH
31{\r
32 FAT_IFILE *IFile;\r
33 FAT_OFILE *OFile;\r
34 FAT_VOLUME *Volume;\r
35 EFI_STATUS Status;\r
149d6335 36 FAT_TASK *Task;\r
b9ec9330 37\r
bcdcc416
MK
38 IFile = IFILE_FROM_FHAND (FHand);\r
39 OFile = IFile->OFile;\r
40 Volume = OFile->Volume;\r
41 Task = NULL;\r
b9ec9330
QH
42\r
43 //\r
44 // If the file has a permanent error, return it\r
45 //\r
46 if (EFI_ERROR (OFile->Error)) {\r
47 return OFile->Error;\r
48 }\r
49\r
50 if (Volume->ReadOnly) {\r
51 return EFI_WRITE_PROTECTED;\r
52 }\r
bcdcc416 53\r
b9ec9330
QH
54 //\r
55 // If read only, return error\r
56 //\r
57 if (IFile->ReadOnly) {\r
58 return EFI_ACCESS_DENIED;\r
59 }\r
149d6335
RN
60\r
61 if (Token == NULL) {\r
62 FatWaitNonblockingTask (IFile);\r
63 } else {\r
64 //\r
65 // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.\r
66 // But if it calls, the below check can avoid crash.\r
67 //\r
68 if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) {\r
69 return EFI_UNSUPPORTED;\r
70 }\r
bcdcc416 71\r
149d6335
RN
72 Task = FatCreateTask (IFile, Token);\r
73 if (Task == NULL) {\r
74 return EFI_OUT_OF_RESOURCES;\r
75 }\r
76 }\r
77\r
b9ec9330
QH
78 //\r
79 // Flush the OFile\r
80 //\r
81 FatAcquireLock ();\r
bcdcc416
MK
82 Status = FatOFileFlush (OFile);\r
83 Status = FatCleanupVolume (OFile->Volume, OFile, Status, Task);\r
b9ec9330 84 FatReleaseLock ();\r
149d6335
RN
85\r
86 if (Token != NULL) {\r
87 if (!EFI_ERROR (Status)) {\r
88 Status = FatQueueTask (IFile, Task);\r
89 } else {\r
90 FatDestroyTask (Task);\r
91 }\r
92 }\r
93\r
b9ec9330
QH
94 return Status;\r
95}\r
96\r
cae7420b 97/**\r
149d6335
RN
98\r
99 Flushes all data associated with the file handle.\r
100\r
cae7420b 101 @param FHand - Handle to file to flush.\r
149d6335 102\r
cae7420b
DB
103 @retval EFI_SUCCESS - Flushed the file successfully.\r
104 @retval EFI_WRITE_PROTECTED - The volume is read only.\r
105 @retval EFI_ACCESS_DENIED - The file is read only.\r
106 @return Others - Flushing of the file failed.\r
149d6335 107\r
cae7420b 108**/\r
b9ec9330
QH
109EFI_STATUS\r
110EFIAPI\r
cae7420b 111FatFlush (\r
dba03ba1 112 IN EFI_FILE_PROTOCOL *FHand\r
b9ec9330 113 )\r
cae7420b
DB
114{\r
115 return FatFlushEx (FHand, NULL);\r
116}\r
b9ec9330 117\r
cae7420b 118/**\r
b9ec9330
QH
119\r
120 Flushes & Closes the file handle.\r
121\r
cae7420b 122 @param FHand - Handle to the file to delete.\r
b9ec9330 123\r
cae7420b 124 @retval EFI_SUCCESS - Closed the file successfully.\r
b9ec9330 125\r
cae7420b
DB
126**/\r
127EFI_STATUS\r
128EFIAPI\r
129FatClose (\r
130 IN EFI_FILE_PROTOCOL *FHand\r
131 )\r
b9ec9330
QH
132{\r
133 FAT_IFILE *IFile;\r
134 FAT_OFILE *OFile;\r
135 FAT_VOLUME *Volume;\r
136\r
bcdcc416
MK
137 IFile = IFILE_FROM_FHAND (FHand);\r
138 OFile = IFile->OFile;\r
139 Volume = OFile->Volume;\r
b9ec9330
QH
140\r
141 //\r
142 // Lock the volume\r
143 //\r
144 FatAcquireLock ();\r
145\r
146 //\r
147 // Close the file instance handle\r
148 //\r
149 FatIFileClose (IFile);\r
150\r
151 //\r
152 // Done. Unlock the volume\r
153 //\r
149d6335 154 FatCleanupVolume (Volume, OFile, EFI_SUCCESS, NULL);\r
b9ec9330
QH
155 FatReleaseLock ();\r
156\r
157 //\r
158 // Close always succeed\r
159 //\r
160 return EFI_SUCCESS;\r
161}\r
162\r
cae7420b 163/**\r
b9ec9330
QH
164\r
165 Close the open file instance.\r
166\r
cae7420b 167 @param IFile - Open file instance.\r
b9ec9330 168\r
cae7420b 169 @retval EFI_SUCCESS - Closed the file successfully.\r
b9ec9330 170\r
cae7420b
DB
171**/\r
172EFI_STATUS\r
173FatIFileClose (\r
bcdcc416 174 FAT_IFILE *IFile\r
cae7420b 175 )\r
b9ec9330
QH
176{\r
177 FAT_OFILE *OFile;\r
178 FAT_VOLUME *Volume;\r
179\r
bcdcc416
MK
180 OFile = IFile->OFile;\r
181 Volume = OFile->Volume;\r
b9ec9330
QH
182\r
183 ASSERT_VOLUME_LOCKED (Volume);\r
184\r
149d6335
RN
185 FatWaitNonblockingTask (IFile);\r
186\r
b9ec9330
QH
187 //\r
188 // Remove the IFile struct\r
189 //\r
190 RemoveEntryList (&IFile->Link);\r
191\r
192 //\r
193 // Add the OFile to the check reference list\r
194 //\r
195 if (OFile->CheckLink.ForwardLink == NULL) {\r
196 InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);\r
197 }\r
bcdcc416 198\r
b9ec9330
QH
199 //\r
200 // Done. Free the open instance structure\r
201 //\r
202 FreePool (IFile);\r
203 return EFI_SUCCESS;\r
204}\r
205\r
cae7420b 206/**\r
b9ec9330
QH
207\r
208 Flush the data associated with an open file.\r
209 In this implementation, only last Mod/Access time is updated.\r
210\r
cae7420b 211 @param OFile - The open file.\r
b9ec9330 212\r
cae7420b
DB
213 @retval EFI_SUCCESS - The OFile is flushed successfully.\r
214 @return Others - An error occurred when flushing this OFile.\r
b9ec9330 215\r
cae7420b
DB
216**/\r
217EFI_STATUS\r
218FatOFileFlush (\r
bcdcc416 219 IN FAT_OFILE *OFile\r
cae7420b 220 )\r
b9ec9330 221{\r
bcdcc416
MK
222 EFI_STATUS Status;\r
223 FAT_OFILE *Parent;\r
224 FAT_DIRENT *DirEnt;\r
225 FAT_DATE_TIME FatNow;\r
b9ec9330
QH
226\r
227 //\r
228 // Flush each entry up the tree while dirty\r
229 //\r
230 do {\r
231 //\r
db62b65c 232 // If the file has a permanent error, then don't write any\r
b9ec9330
QH
233 // of its data to the device (may be from different media)\r
234 //\r
235 if (EFI_ERROR (OFile->Error)) {\r
236 return OFile->Error;\r
237 }\r
238\r
bcdcc416
MK
239 Parent = OFile->Parent;\r
240 DirEnt = OFile->DirEnt;\r
b9ec9330
QH
241 if (OFile->Dirty) {\r
242 //\r
243 // Update the last modification time\r
244 //\r
245 FatGetCurrentFatTime (&FatNow);\r
246 CopyMem (&DirEnt->Entry.FileLastAccess, &FatNow.Date, sizeof (FAT_DATE));\r
247 if (!OFile->PreserveLastModification) {\r
248 FatGetCurrentFatTime (&DirEnt->Entry.FileModificationTime);\r
249 }\r
250\r
251 OFile->PreserveLastModification = FALSE;\r
252 if (OFile->Archive) {\r
253 DirEnt->Entry.Attributes |= FAT_ATTRIBUTE_ARCHIVE;\r
bcdcc416 254 OFile->Archive = FALSE;\r
b9ec9330 255 }\r
bcdcc416 256\r
b9ec9330
QH
257 //\r
258 // Write the directory entry\r
259 //\r
bcdcc416 260 if ((Parent != NULL) && !DirEnt->Invalid) {\r
b9ec9330
QH
261 //\r
262 // Write the OFile's directory entry\r
263 //\r
264 Status = FatStoreDirEnt (Parent, DirEnt);\r
265 if (EFI_ERROR (Status)) {\r
266 return Status;\r
267 }\r
268 }\r
269\r
270 OFile->Dirty = FALSE;\r
271 }\r
bcdcc416 272\r
b9ec9330
QH
273 //\r
274 // Check the parent\r
275 //\r
276 OFile = Parent;\r
277 } while (OFile != NULL);\r
bcdcc416 278\r
b9ec9330
QH
279 return EFI_SUCCESS;\r
280}\r
281\r
cae7420b 282/**\r
b9ec9330
QH
283\r
284 Check the references of the OFile.\r
285 If the OFile (that is checked) is no longer\r
286 referenced, then it is freed.\r
287\r
cae7420b 288 @param OFile - The OFile to be checked.\r
b9ec9330 289\r
cae7420b
DB
290 @retval TRUE - The OFile is not referenced and freed.\r
291 @retval FALSE - The OFile is kept.\r
b9ec9330 292\r
cae7420b
DB
293**/\r
294BOOLEAN\r
295FatCheckOFileRef (\r
bcdcc416 296 IN FAT_OFILE *OFile\r
cae7420b 297 )\r
b9ec9330
QH
298{\r
299 //\r
300 // If the OFile is on the check ref list, remove it\r
301 //\r
302 if (OFile->CheckLink.ForwardLink != NULL) {\r
303 RemoveEntryList (&OFile->CheckLink);\r
304 OFile->CheckLink.ForwardLink = NULL;\r
305 }\r
306\r
307 FatOFileFlush (OFile);\r
308 //\r
309 // Are there any references to this OFile?\r
310 //\r
311 if (!IsListEmpty (&OFile->Opens) || !IsListEmpty (&OFile->ChildHead)) {\r
312 //\r
313 // The OFile cannot be freed\r
314 //\r
315 return FALSE;\r
316 }\r
bcdcc416 317\r
b9ec9330
QH
318 //\r
319 // Free the Ofile\r
320 //\r
321 FatCloseDirEnt (OFile->DirEnt);\r
322 return TRUE;\r
323}\r
324\r
cae7420b 325/**\r
b9ec9330
QH
326\r
327 Check the references of all open files on the volume.\r
328 Any open file (that is checked) that is no longer\r
db62b65c 329 referenced, is freed - and its parent open file\r
b9ec9330
QH
330 is then referenced checked.\r
331\r
cae7420b 332 @param Volume - The volume to check the pending open file list.\r
b9ec9330 333\r
cae7420b
DB
334**/\r
335STATIC\r
336VOID\r
337FatCheckVolumeRef (\r
bcdcc416 338 IN FAT_VOLUME *Volume\r
cae7420b 339 )\r
b9ec9330 340{\r
bcdcc416
MK
341 FAT_OFILE *OFile;\r
342 FAT_OFILE *Parent;\r
b9ec9330
QH
343\r
344 //\r
345 // Check all files on the pending check list\r
346 //\r
347 while (!IsListEmpty (&Volume->CheckRef)) {\r
348 //\r
349 // Start with the first file listed\r
350 //\r
351 Parent = OFILE_FROM_CHECKLINK (Volume->CheckRef.ForwardLink);\r
352 //\r
353 // Go up the tree cleaning up any un-referenced OFiles\r
354 //\r
355 while (Parent != NULL) {\r
bcdcc416
MK
356 OFile = Parent;\r
357 Parent = OFile->Parent;\r
b9ec9330
QH
358 if (!FatCheckOFileRef (OFile)) {\r
359 break;\r
360 }\r
361 }\r
362 }\r
363}\r
364\r
cae7420b 365/**\r
b9ec9330
QH
366\r
367 Set error status for a specific OFile, reference checking the volume.\r
368 If volume is already marked as invalid, and all resources are freed\r
369 after reference checking, the file system protocol is uninstalled and\r
370 the volume structure is freed.\r
371\r
cae7420b
DB
372 @param Volume - the Volume that is to be reference checked and unlocked.\r
373 @param OFile - the OFile whose permanent error code is to be set.\r
374 @param EfiStatus - error code to be set.\r
375 @param Task point to task instance.\r
b9ec9330 376\r
cae7420b
DB
377 @retval EFI_SUCCESS - Clean up the volume successfully.\r
378 @return Others - Cleaning up of the volume is failed.\r
b9ec9330 379\r
cae7420b
DB
380**/\r
381EFI_STATUS\r
382FatCleanupVolume (\r
bcdcc416
MK
383 IN FAT_VOLUME *Volume,\r
384 IN FAT_OFILE *OFile,\r
385 IN EFI_STATUS EfiStatus,\r
386 IN FAT_TASK *Task\r
cae7420b 387 )\r
b9ec9330
QH
388{\r
389 EFI_STATUS Status;\r
bcdcc416 390\r
b9ec9330
QH
391 //\r
392 // Flag the OFile\r
393 //\r
394 if (OFile != NULL) {\r
395 FatSetVolumeError (OFile, EfiStatus);\r
396 }\r
bcdcc416 397\r
b9ec9330
QH
398 //\r
399 // Clean up any dangling OFiles that don't have IFiles\r
400 // we don't check return status here because we want the\r
401 // volume be cleaned up even the volume is invalid.\r
402 //\r
403 FatCheckVolumeRef (Volume);\r
404 if (Volume->Valid) {\r
405 //\r
406 // Update the free hint info. Volume->FreeInfoPos != 0\r
407 // indicates this a FAT32 volume\r
408 //\r
409 if (Volume->FreeInfoValid && Volume->FatDirty && Volume->FreeInfoPos) {\r
c1680e88 410 Status = FatDiskIo (Volume, WriteDisk, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector, Task);\r
b9ec9330
QH
411 if (EFI_ERROR (Status)) {\r
412 return Status;\r
413 }\r
414 }\r
bcdcc416 415\r
b9ec9330
QH
416 //\r
417 // Update that the volume is not dirty\r
418 //\r
bcdcc416
MK
419 if (Volume->FatDirty && (Volume->FatType != Fat12)) {\r
420 Volume->FatDirty = FALSE;\r
421 Status = FatAccessVolumeDirty (Volume, WriteFat, &Volume->NotDirtyValue);\r
b9ec9330
QH
422 if (EFI_ERROR (Status)) {\r
423 return Status;\r
424 }\r
425 }\r
bcdcc416 426\r
b9ec9330
QH
427 //\r
428 // Flush all dirty cache entries to disk\r
429 //\r
149d6335 430 Status = FatVolumeFlushCache (Volume, Task);\r
b9ec9330
QH
431 if (EFI_ERROR (Status)) {\r
432 return Status;\r
433 }\r
434 }\r
bcdcc416 435\r
b9ec9330
QH
436 //\r
437 // If the volume is cleared , remove it.\r
438 // The only time volume be invalidated is in DriverBindingStop.\r
439 //\r
bcdcc416 440 if ((Volume->Root == NULL) && !Volume->Valid) {\r
b9ec9330
QH
441 //\r
442 // Free the volume structure\r
443 //\r
444 FatFreeVolume (Volume);\r
445 }\r
446\r
447 return EfiStatus;\r
448}\r
449\r
cae7420b
DB
450/**\r
451\r
452 Set the OFile and its child OFile with the error Status\r
453\r
454 @param OFile - The OFile whose permanent error code is to be set.\r
455 @param Status - Error code to be set.\r
456\r
457**/\r
b9ec9330
QH
458VOID\r
459FatSetVolumeError (\r
bcdcc416
MK
460 IN FAT_OFILE *OFile,\r
461 IN EFI_STATUS Status\r
b9ec9330 462 )\r
b9ec9330 463{\r
bcdcc416
MK
464 LIST_ENTRY *Link;\r
465 FAT_OFILE *ChildOFile;\r
b9ec9330
QH
466\r
467 //\r
468 // If this OFile doesn't already have an error, set one\r
469 //\r
470 if (!EFI_ERROR (OFile->Error)) {\r
471 OFile->Error = Status;\r
472 }\r
bcdcc416 473\r
b9ec9330
QH
474 //\r
475 // Set the error on each child OFile\r
476 //\r
477 for (Link = OFile->ChildHead.ForwardLink; Link != &OFile->ChildHead; Link = Link->ForwardLink) {\r
478 ChildOFile = OFILE_FROM_CHILDLINK (Link);\r
479 FatSetVolumeError (ChildOFile, Status);\r
480 }\r
481}\r