Merge trunk head (r43756)
[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 {
41 LARGE_INTEGER i;
42 UNIMPLEMENTED;
43 i.QuadPart = 0;
44 return i;
45 }
46
47 /*
48 * @implemented
49 */
50 PFILE_OBJECT
51 NTAPI
52 CcGetFileObjectFromBcb (
53 IN PVOID Bcb
54 )
55 {
56 PINTERNAL_BCB iBcb = (PINTERNAL_BCB)Bcb;
57 return iBcb->CacheSegment->Bcb->FileObject;
58 }
59
60 /*
61 * @unimplemented
62 */
63 LARGE_INTEGER
64 NTAPI
65 CcGetLsnForFileObject (
66 IN PFILE_OBJECT FileObject,
67 OUT PLARGE_INTEGER OldestLsn OPTIONAL
68 )
69 {
70 LARGE_INTEGER i;
71 UNIMPLEMENTED;
72 i.QuadPart = 0;
73 return i;
74 }
75
76 /*
77 * @unimplemented
78 */
79 VOID
80 NTAPI
81 CcInitializeCacheMap (
82 IN PFILE_OBJECT FileObject,
83 IN PCC_FILE_SIZES FileSizes,
84 IN BOOLEAN PinAccess,
85 IN PCACHE_MANAGER_CALLBACKS CallBacks,
86 IN PVOID LazyWriterContext
87 )
88 {
89 ASSERT(FileObject);
90 ASSERT(FileSizes);
91
92 /* Call old ROS cache init function */
93 CcRosInitializeFileCache(FileObject,
94 /*PAGE_SIZE*/ VACB_MAPPING_GRANULARITY, CallBacks,
95 LazyWriterContext);
96 }
97
98 /*
99 * @unimplemented
100 */
101 BOOLEAN
102 NTAPI
103 CcIsThereDirtyData (
104 IN PVPB Vpb
105 )
106 {
107 UNIMPLEMENTED;
108 return FALSE;
109 }
110
111 /*
112 * @unimplemented
113 */
114 BOOLEAN
115 NTAPI
116 CcPurgeCacheSection (
117 IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
118 IN PLARGE_INTEGER FileOffset OPTIONAL,
119 IN ULONG Length,
120 IN BOOLEAN UninitializeCacheMaps
121 )
122 {
123 //UNIMPLEMENTED;
124 return FALSE;
125 }
126
127
128 /*
129 * @implemented
130 */
131 VOID NTAPI
132 CcSetFileSizes (IN PFILE_OBJECT FileObject,
133 IN PCC_FILE_SIZES FileSizes)
134 {
135 KIRQL oldirql;
136 PBCB Bcb;
137 PLIST_ENTRY current_entry;
138 PCACHE_SEGMENT current;
139 LIST_ENTRY FreeListHead;
140 NTSTATUS Status;
141
142 DPRINT("CcSetFileSizes(FileObject 0x%p, FileSizes 0x%p)\n",
143 FileObject, FileSizes);
144 DPRINT("AllocationSize %d, FileSize %d, ValidDataLength %d\n",
145 (ULONG)FileSizes->AllocationSize.QuadPart,
146 (ULONG)FileSizes->FileSize.QuadPart,
147 (ULONG)FileSizes->ValidDataLength.QuadPart);
148
149 Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
150
151 /*
152 * It is valid to call this function on file objects that weren't
153 * initialized for caching. In this case it's simple no-op.
154 */
155 if (Bcb == NULL)
156 return;
157
158 if (FileSizes->AllocationSize.QuadPart < Bcb->AllocationSize.QuadPart)
159 {
160 InitializeListHead(&FreeListHead);
161 KeAcquireGuardedMutex(&ViewLock);
162 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
163
164 current_entry = Bcb->BcbSegmentListHead.Flink;
165 while (current_entry != &Bcb->BcbSegmentListHead)
166 {
167 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
168 current_entry = current_entry->Flink;
169 if (current->FileOffset > FileSizes->AllocationSize.QuadPart)
170 {
171 if (current->ReferenceCount == 0 || (current->ReferenceCount == 1 && current->Dirty))
172 {
173 RemoveEntryList(&current->BcbSegmentListEntry);
174 RemoveEntryList(&current->CacheSegmentListEntry);
175 RemoveEntryList(&current->CacheSegmentLRUListEntry);
176 if (current->Dirty)
177 {
178 RemoveEntryList(&current->DirtySegmentListEntry);
179 DirtyPageCount -= Bcb->CacheSegmentSize / PAGE_SIZE;
180 }
181 InsertHeadList(&FreeListHead, &current->BcbSegmentListEntry);
182 }
183 else
184 {
185 DPRINT1("Anyone has referenced a cache segment behind the new size.\n");
186 KeBugCheck(CACHE_MANAGER);
187 }
188 }
189 }
190
191 Bcb->AllocationSize = FileSizes->AllocationSize;
192 Bcb->FileSize = FileSizes->FileSize;
193 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
194 KeReleaseGuardedMutex(&ViewLock);
195
196 current_entry = FreeListHead.Flink;
197 while(current_entry != &FreeListHead)
198 {
199 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, BcbSegmentListEntry);
200 current_entry = current_entry->Flink;
201 Status = CcRosInternalFreeCacheSegment(current);
202 if (!NT_SUCCESS(Status))
203 {
204 DPRINT1("CcRosInternalFreeCacheSegment failed, status = %x\n", Status);
205 KeBugCheck(CACHE_MANAGER);
206 }
207 }
208 }
209 else
210 {
211 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
212 Bcb->AllocationSize = FileSizes->AllocationSize;
213 Bcb->FileSize = FileSizes->FileSize;
214 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
215 }
216 }
217
218 /*
219 * @unimplemented
220 */
221 VOID
222 NTAPI
223 CcSetLogHandleForFile (
224 IN PFILE_OBJECT FileObject,
225 IN PVOID LogHandle,
226 IN PFLUSH_TO_LSN FlushToLsnRoutine
227 )
228 {
229 UNIMPLEMENTED;
230 }
231
232 /*
233 * @unimplemented
234 */
235 BOOLEAN
236 NTAPI
237 CcUninitializeCacheMap (
238 IN PFILE_OBJECT FileObject,
239 IN PLARGE_INTEGER TruncateSize OPTIONAL,
240 IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL
241 )
242 {
243 #if 0
244 UNIMPLEMENTED;
245 return FALSE;
246 #else
247 return NT_SUCCESS(CcRosReleaseFileCache(FileObject));
248 #endif
249 }