Merge my current work done on the kd++ branch:
[reactos.git] / reactos / ntoskrnl / cc / fs.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/cc/fs.c
5 * PURPOSE: Implements cache managers functions useful for File Systems
6 *
7 * PROGRAMMERS: Alex Ionescu
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #ifndef VACB_MAPPING_GRANULARITY
17 #define VACB_MAPPING_GRANULARITY (256 * 1024)
18 #endif
19
20 /* GLOBALS *****************************************************************/
21
22 extern KGUARDED_MUTEX ViewLock;
23 extern ULONG DirtyPageCount;
24
25 NTSTATUS CcRosInternalFreeCacheSegment(PCACHE_SEGMENT CacheSeg);
26
27 /* FUNCTIONS *****************************************************************/
28
29 /*
30 * @unimplemented
31 */
32 LARGE_INTEGER
33 NTAPI
34 CcGetDirtyPages (
35 IN PVOID LogHandle,
36 IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine,
37 IN PVOID Context1,
38 IN PVOID Context2)
39 {
40 LARGE_INTEGER i;
41 UNIMPLEMENTED;
42 i.QuadPart = 0;
43 return i;
44 }
45
46 /*
47 * @implemented
48 */
49 PFILE_OBJECT
50 NTAPI
51 CcGetFileObjectFromBcb (
52 IN PVOID Bcb)
53 {
54 PINTERNAL_BCB iBcb = (PINTERNAL_BCB)Bcb;
55 return iBcb->CacheSegment->Bcb->FileObject;
56 }
57
58 /*
59 * @unimplemented
60 */
61 LARGE_INTEGER
62 NTAPI
63 CcGetLsnForFileObject (
64 IN PFILE_OBJECT FileObject,
65 OUT PLARGE_INTEGER OldestLsn OPTIONAL)
66 {
67 LARGE_INTEGER i;
68 UNIMPLEMENTED;
69 i.QuadPart = 0;
70 return i;
71 }
72
73 /*
74 * @unimplemented
75 */
76 VOID
77 NTAPI
78 CcInitializeCacheMap (
79 IN PFILE_OBJECT FileObject,
80 IN PCC_FILE_SIZES FileSizes,
81 IN BOOLEAN PinAccess,
82 IN PCACHE_MANAGER_CALLBACKS CallBacks,
83 IN PVOID LazyWriterContext)
84 {
85 ASSERT(FileObject);
86 ASSERT(FileSizes);
87
88 /* Call old ROS cache init function */
89 CcRosInitializeFileCache(FileObject,
90 /*PAGE_SIZE*/ VACB_MAPPING_GRANULARITY, CallBacks,
91 LazyWriterContext);
92 }
93
94 /*
95 * @unimplemented
96 */
97 BOOLEAN
98 NTAPI
99 CcIsThereDirtyData (
100 IN PVPB Vpb)
101 {
102 UNIMPLEMENTED;
103 return FALSE;
104 }
105
106 /*
107 * @unimplemented
108 */
109 BOOLEAN
110 NTAPI
111 CcPurgeCacheSection (
112 IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
113 IN PLARGE_INTEGER FileOffset OPTIONAL,
114 IN ULONG Length,
115 IN BOOLEAN UninitializeCacheMaps)
116 {
117 //UNIMPLEMENTED;
118 return FALSE;
119 }
120
121
122 /*
123 * @implemented
124 */
125 VOID NTAPI
126 CcSetFileSizes (
127 IN PFILE_OBJECT FileObject,
128 IN PCC_FILE_SIZES FileSizes)
129 {
130 KIRQL oldirql;
131 PBCB Bcb;
132 PLIST_ENTRY current_entry;
133 PCACHE_SEGMENT current;
134 LIST_ENTRY FreeListHead;
135 NTSTATUS Status;
136
137 DPRINT("CcSetFileSizes(FileObject 0x%p, FileSizes 0x%p)\n",
138 FileObject, FileSizes);
139 DPRINT("AllocationSize %I64d, FileSize %I64d, ValidDataLength %I64d\n",
140 FileSizes->AllocationSize.QuadPart,
141 FileSizes->FileSize.QuadPart,
142 FileSizes->ValidDataLength.QuadPart);
143
144 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
145
146 /*
147 * It is valid to call this function on file objects that weren't
148 * initialized for caching. In this case it's simple no-op.
149 */
150 if (Bcb == NULL)
151 return;
152
153 if (FileSizes->AllocationSize.QuadPart < Bcb->AllocationSize.QuadPart)
154 {
155 InitializeListHead(&FreeListHead);
156 KeAcquireGuardedMutex(&ViewLock);
157 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
158
159 current_entry = Bcb->BcbSegmentListHead.Flink;
160 while (current_entry != &Bcb->BcbSegmentListHead)
161 {
162 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
163 current_entry = current_entry->Flink;
164 if (current->FileOffset > FileSizes->AllocationSize.QuadPart ||
165 (current->FileOffset == 0 && FileSizes->AllocationSize.QuadPart == 0))
166 {
167 if ((current->ReferenceCount == 0) || ((current->ReferenceCount == 1) && current->Dirty))
168 {
169 RemoveEntryList(&current->BcbSegmentListEntry);
170 RemoveEntryList(&current->CacheSegmentListEntry);
171 RemoveEntryList(&current->CacheSegmentLRUListEntry);
172 if (current->Dirty)
173 {
174 RemoveEntryList(&current->DirtySegmentListEntry);
175 DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE;
176 }
177 InsertHeadList(&FreeListHead, &current->BcbSegmentListEntry);
178 }
179 else
180 {
181 DPRINT1("Anyone has referenced a cache segment behind the new size.\n");
182 KeBugCheck(CACHE_MANAGER);
183 }
184 }
185 }
186
187 Bcb->AllocationSize = FileSizes->AllocationSize;
188 Bcb->FileSize = FileSizes->FileSize;
189 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
190 KeReleaseGuardedMutex(&ViewLock);
191
192 current_entry = FreeListHead.Flink;
193 while(current_entry != &FreeListHead)
194 {
195 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
196 current_entry = current_entry->Flink;
197 Status = CcRosInternalFreeCacheSegment(current);
198 if (!NT_SUCCESS(Status))
199 {
200 DPRINT1("CcRosInternalFreeCacheSegment failed, status = %x\n", Status);
201 KeBugCheck(CACHE_MANAGER);
202 }
203 }
204 }
205 else
206 {
207 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
208 Bcb->AllocationSize = FileSizes->AllocationSize;
209 Bcb->FileSize = FileSizes->FileSize;
210 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
211 }
212 }
213
214 /*
215 * @unimplemented
216 */
217 VOID
218 NTAPI
219 CcSetLogHandleForFile (
220 IN PFILE_OBJECT FileObject,
221 IN PVOID LogHandle,
222 IN PFLUSH_TO_LSN FlushToLsnRoutine)
223 {
224 UNIMPLEMENTED;
225 }
226
227 /*
228 * @unimplemented
229 */
230 BOOLEAN
231 NTAPI
232 CcUninitializeCacheMap (
233 IN PFILE_OBJECT FileObject,
234 IN PLARGE_INTEGER TruncateSize OPTIONAL,
235 IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL)
236 {
237 #if 0
238 UNIMPLEMENTED;
239 return FALSE;
240 #else
241 return NT_SUCCESS(CcRosReleaseFileCache(FileObject));
242 #endif
243 }
244
245 BOOLEAN
246 NTAPI
247 CcGetFileSizes (
248 IN PFILE_OBJECT FileObject,
249 IN PCC_FILE_SIZES FileSizes)
250 {
251 PBCB Bcb;
252
253 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
254
255 if (!Bcb)
256 return FALSE;
257
258 FileSizes->AllocationSize = Bcb->AllocationSize;
259 FileSizes->FileSize = FileSizes->ValidDataLength = Bcb->FileSize;
260 return TRUE;
261 }