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