1 /*
2  * PROJECT:     VFAT Filesystem
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Shutdown handlers
5  * COPYRIGHT:   Copyright 2000-2013 Eric Kohl <eric.kohl@reactos.org>
6  */
7 
8 /* INCLUDES *****************************************************************/
9 
10 #include "vfat.h"
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* FUNCTIONS ****************************************************************/
16 
17 static
18 NTSTATUS
19 VfatDiskShutDown(
20     PVCB Vcb)
21 {
22     PIRP Irp;
23     KEVENT Event;
24     NTSTATUS Status;
25     IO_STATUS_BLOCK IoStatus;
26 
27     KeInitializeEvent(&Event, NotificationEvent, FALSE);
28     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN, Vcb->StorageDevice,
29                                        NULL, 0, NULL, &Event, &IoStatus);
30     if (Irp)
31     {
32         Status = IoCallDriver(Vcb->StorageDevice, Irp);
33         if (Status == STATUS_PENDING)
34         {
35             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
36             Status = IoStatus.Status;
37         }
38     }
39     else
40     {
41         Status = STATUS_INSUFFICIENT_RESOURCES;
42     }
43 
44     return Status;
45 }
46 
47 
48 NTSTATUS
49 NTAPI
50 VfatShutdown(
51     PDEVICE_OBJECT DeviceObject,
52     PIRP Irp)
53 {
54     NTSTATUS Status;
55     PLIST_ENTRY ListEntry;
56     PDEVICE_EXTENSION DeviceExt;
57 
58     DPRINT("VfatShutdown(DeviceObject %p, Irp %p)\n",DeviceObject, Irp);
59 
60     FsRtlEnterFileSystem();
61 
62     /* FIXME: block new mount requests */
63     VfatGlobalData->ShutdownStarted = TRUE;
64 
65     if (DeviceObject == VfatGlobalData->DeviceObject)
66     {
67         Irp->IoStatus.Status = STATUS_SUCCESS;
68         ExAcquireResourceExclusiveLite(&VfatGlobalData->VolumeListLock, TRUE);
69         ListEntry = VfatGlobalData->VolumeListHead.Flink;
70         while (ListEntry != &VfatGlobalData->VolumeListHead)
71         {
72             DeviceExt = CONTAINING_RECORD(ListEntry, VCB, VolumeListEntry);
73             ListEntry = ListEntry->Flink;
74 
75             ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, TRUE);
76 
77             /* Flush volume & files */
78             Status = VfatFlushVolume(DeviceExt, DeviceExt->VolumeFcb);
79 
80             /* We're performing a clean shutdown */
81             if (BooleanFlagOn(DeviceExt->VolumeFcb->Flags, VCB_CLEAR_DIRTY) &&
82                 BooleanFlagOn(DeviceExt->VolumeFcb->Flags, VCB_IS_DIRTY))
83             {
84                 /* Drop the dirty bit */
85                 if (NT_SUCCESS(SetDirtyStatus(DeviceExt, FALSE)))
86                     DeviceExt->VolumeFcb->Flags &= ~VCB_IS_DIRTY;
87             }
88 
89             if (NT_SUCCESS(Status))
90             {
91                 Status = VfatDiskShutDown(DeviceExt);
92                 if (!NT_SUCCESS(Status))
93                 {
94                     DPRINT1("VfatDiskShutDown failed, status = %x\n", Status);
95                 }
96             }
97             else
98             {
99                 DPRINT1("VfatFlushVolume failed, status = %x\n", Status);
100             }
101             ExReleaseResourceLite(&DeviceExt->DirResource);
102 
103             /* Unmount the logical volume */
104 #ifdef ENABLE_SWAPOUT
105             VfatCheckForDismount(DeviceExt, FALSE);
106 #endif
107 
108             if (!NT_SUCCESS(Status))
109                 Irp->IoStatus.Status = Status;
110         }
111         ExReleaseResourceLite(&VfatGlobalData->VolumeListLock);
112 
113         /* FIXME: Free all global acquired resources */
114 
115         Status = Irp->IoStatus.Status;
116     }
117     else
118     {
119         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
120         Status = STATUS_INVALID_DEVICE_REQUEST;
121     }
122 
123     Irp->IoStatus.Information = 0;
124     IoCompleteRequest(Irp, IO_NO_INCREMENT);
125 
126     FsRtlExitFileSystem();
127 
128     return Status;
129 }
130 
131 /* EOF */
132