Close section handle after NtCreateProces in KERNEL32.CreateProcess
[reactos.git] / reactos / ntoskrnl / cc / view.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 David Welch <welch@cwcom.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: view.c,v 1.18 2001/03/09 14:40:27 dwelch Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: ntoskrnl/cc/view.c
24 * PURPOSE: Cache manager
25 * PROGRAMMER: David Welch (welch@mcmail.com)
26 * UPDATE HISTORY:
27 * Created 22/05/98
28 */
29
30 /* NOTES **********************************************************************
31 *
32 * This is not the NT implementation of a file cache nor anything much like
33 * it.
34 *
35 * The general procedure for a filesystem to implement a read or write
36 * dispatch routine is as follows
37 *
38 * (1) If caching for the FCB hasn't been initiated then so do by calling
39 * CcInitializeFileCache.
40 *
41 * (2) For each 4k region which is being read or written obtain a cache page
42 * by calling CcRequestCachePage.
43 *
44 * (3) If either the page is being read or not completely written, and it is
45 * not up to date then read its data from the underlying medium. If the read
46 * fails then call CcReleaseCachePage with VALID as FALSE and return a error.
47 *
48 * (4) Copy the data into or out of the page as necessary.
49 *
50 * (5) Release the cache page
51 */
52 /* INCLUDES ******************************************************************/
53
54 #include <ddk/ntddk.h>
55 #include <ddk/ntifs.h>
56 #include <internal/mm.h>
57 #include <internal/cc.h>
58 #include <internal/pool.h>
59
60 #define NDEBUG
61 #include <internal/debug.h>
62
63 /* GLOBALS *******************************************************************/
64
65 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
66 #define ROUND_DOWN(N, S) (ROUND_UP(N, S) - S)
67
68 #define TAG_CSEG TAG('C', 'S', 'E', 'G')
69 #define TAG_BCB TAG('B', 'C', 'B', ' ')
70
71 /* FUNCTIONS *****************************************************************/
72
73 NTSTATUS STDCALL
74 CcFlushCacheSegment(PCACHE_SEGMENT CacheSeg)
75 /*
76 * FUNCTION: Asks the FSD to flush the contents of the page back to disk
77 */
78 {
79 KeWaitForSingleObject(&CacheSeg->Lock,
80 Executive,
81 KernelMode,
82 FALSE,
83 NULL);
84 /* FIXME: Build an IRP_MJ_WRITE and send it to the filesystem */
85 KeSetEvent(&CacheSeg->Lock, IO_NO_INCREMENT, 0);
86 return(STATUS_NOT_IMPLEMENTED);
87 }
88
89 NTSTATUS STDCALL
90 CcReleaseCacheSegment(PBCB Bcb,
91 PCACHE_SEGMENT CacheSeg,
92 BOOLEAN Valid)
93 {
94 DPRINT("CcReleaseCachePage(Bcb %x, CacheSeg %x, Valid %d)\n",
95 Bcb, CacheSeg, Valid);
96
97 CacheSeg->ReferenceCount--;
98 CacheSeg->Valid = Valid;
99 KeSetEvent(&CacheSeg->Lock, IO_NO_INCREMENT, FALSE);
100
101 DPRINT("CcReleaseCachePage() finished\n");
102
103 return(STATUS_SUCCESS);
104 }
105
106 NTSTATUS STDCALL
107 CcRequestCacheSegment(PBCB Bcb,
108 ULONG FileOffset,
109 PVOID* BaseAddress,
110 PBOOLEAN UptoDate,
111 PCACHE_SEGMENT* CacheSeg)
112 /*
113 * FUNCTION: Request a page mapping for a BCB
114 */
115 {
116 KIRQL oldirql;
117 PLIST_ENTRY current_entry;
118 PCACHE_SEGMENT current;
119 ULONG i;
120
121 if ((FileOffset % Bcb->CacheSegmentSize) != 0)
122 {
123 KeBugCheck(0);
124 }
125
126 DPRINT("CcRequestCachePage(Bcb %x, FileOffset %x, BaseAddress %x, "
127 "UptoDate %x, CacheSeg %x)\n", Bcb, FileOffset, BaseAddress,
128 UptoDate, CacheSeg);
129
130 KeAcquireSpinLock(&Bcb->BcbLock, &oldirql);
131
132 current_entry = Bcb->CacheSegmentListHead.Flink;
133 while (current_entry != &Bcb->CacheSegmentListHead)
134 {
135 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, ListEntry);
136 if (current->FileOffset == FileOffset)
137 {
138 DPRINT("Found existing segment at %x\n", current);
139 current->ReferenceCount++;
140 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
141 DPRINT("Waiting for segment\n");
142 KeWaitForSingleObject(&current->Lock,
143 Executive,
144 KernelMode,
145 FALSE,
146 NULL);
147 *UptoDate = current->Valid;
148 *BaseAddress = current->BaseAddress;
149 *CacheSeg = current;
150 DPRINT("Returning %x (UptoDate %d)\n", current, current->Valid);
151 return(STATUS_SUCCESS);
152 }
153 current_entry = current_entry->Flink;
154 }
155
156 DPRINT("Creating new segment\n");
157
158 KeReleaseSpinLock(&Bcb->BcbLock, oldirql);
159
160 current = ExAllocatePoolWithTag(NonPagedPool, sizeof(CACHE_SEGMENT),
161 TAG_CSEG);
162 current->BaseAddress = NULL;
163 MmCreateMemoryArea(KernelMode,
164 MmGetKernelAddressSpace(),
165 MEMORY_AREA_CACHE_SEGMENT,
166 &current->BaseAddress,
167 Bcb->CacheSegmentSize,
168 PAGE_READWRITE,
169 (PMEMORY_AREA*)&current->MemoryArea);
170 current->Valid = FALSE;
171 current->FileOffset = FileOffset;
172 current->Bcb = Bcb;
173 KeInitializeEvent(&current->Lock, SynchronizationEvent, FALSE);
174 current->ReferenceCount = 1;
175 InsertTailList(&Bcb->CacheSegmentListHead, &current->ListEntry);
176 *UptoDate = current->Valid;
177 *BaseAddress = current->BaseAddress;
178 *CacheSeg = current;
179 for (i = 0; i < (Bcb->CacheSegmentSize / PAGESIZE); i++)
180 {
181 MmCreateVirtualMapping(NULL,
182 current->BaseAddress + (i * PAGESIZE),
183 PAGE_READWRITE,
184 (ULONG)MmAllocPage(0));
185 }
186
187
188 DPRINT("Returning %x (BaseAddress %x)\n", current, *BaseAddress);
189
190 return(STATUS_SUCCESS);
191 }
192
193 STATIC VOID
194 CcFreeCachePage(PVOID Context, PVOID Address, ULONG PhysAddr)
195 {
196 if (PhysAddr != 0)
197 {
198 MmDereferencePage((PVOID)PhysAddr);
199 }
200 }
201
202 NTSTATUS STDCALL
203 CcFreeCacheSegment(PBCB Bcb, PCACHE_SEGMENT CacheSeg)
204 /*
205 * FUNCTION: Releases a cache segment associated with a BCB
206 */
207 {
208 DPRINT("Freeing cache segment %x\n", CacheSeg);
209 MmFreeMemoryArea(MmGetKernelAddressSpace(),
210 CacheSeg->BaseAddress,
211 Bcb->CacheSegmentSize,
212 CcFreeCachePage,
213 NULL);
214 ExFreePool(CacheSeg);
215 return(STATUS_SUCCESS);
216 }
217
218 NTSTATUS STDCALL
219 CcReleaseFileCache(PFILE_OBJECT FileObject, PBCB Bcb)
220 /*
221 * FUNCTION: Releases the BCB associated with a file object
222 */
223 {
224 PLIST_ENTRY current_entry;
225 PCACHE_SEGMENT current;
226
227 DPRINT("CcReleaseFileCache(FileObject %x, Bcb %x)\n", FileObject, Bcb);
228
229 MmFreeSectionSegments(FileObject);
230
231 current_entry = Bcb->CacheSegmentListHead.Flink;
232 while (current_entry != &Bcb->CacheSegmentListHead)
233 {
234 current = CONTAINING_RECORD(current_entry, CACHE_SEGMENT, ListEntry);
235 current_entry = current_entry->Flink;
236 CcFreeCacheSegment(Bcb, current);
237 }
238
239 ExFreePool(Bcb);
240
241 DPRINT("CcReleaseFileCache() finished\n");
242
243 return(STATUS_SUCCESS);
244 }
245
246 NTSTATUS STDCALL
247 CcInitializeFileCache(PFILE_OBJECT FileObject,
248 PBCB* Bcb,
249 ULONG CacheSegmentSize)
250 /*
251 * FUNCTION: Initializes a BCB for a file object
252 */
253 {
254 DPRINT("CcInitializeFileCache(FileObject %x)\n",FileObject);
255
256 (*Bcb) = ExAllocatePoolWithTag(NonPagedPool, sizeof(BCB), TAG_BCB);
257 if ((*Bcb) == NULL)
258 {
259 return(STATUS_UNSUCCESSFUL);
260 }
261
262 (*Bcb)->FileObject = FileObject;
263 InitializeListHead(&(*Bcb)->CacheSegmentListHead);
264 KeInitializeSpinLock(&(*Bcb)->BcbLock);
265 (*Bcb)->CacheSegmentSize = CacheSegmentSize;
266
267 DPRINT("Finished CcInitializeFileCache() = %x\n", *Bcb);
268
269 return(STATUS_SUCCESS);
270 }
271
272
273 /**********************************************************************
274 * NAME INTERNAL
275 * CcMdlReadCompleteDev@8
276 *
277 * DESCRIPTION
278 *
279 * ARGUMENTS
280 * MdlChain
281 * DeviceObject
282 *
283 * RETURN VALUE
284 * None.
285 *
286 * NOTE
287 * Used by CcMdlReadComplete@8 and FsRtl
288 */
289 VOID STDCALL
290 CcMdlReadCompleteDev (IN PMDL MdlChain,
291 IN PDEVICE_OBJECT DeviceObject)
292 {
293 UNIMPLEMENTED;
294 }
295
296
297 /**********************************************************************
298 * NAME EXPORTED
299 * CcMdlReadComplete@8
300 *
301 * DESCRIPTION
302 *
303 * ARGUMENTS
304 *
305 * RETURN VALUE
306 * None.
307 *
308 * NOTE
309 * From Bo Branten's ntifs.h v13.
310 */
311 VOID STDCALL
312 CcMdlReadComplete (IN PFILE_OBJECT FileObject,
313 IN PMDL MdlChain)
314 {
315 PDEVICE_OBJECT DeviceObject = NULL;
316
317 DeviceObject = IoGetRelatedDeviceObject (FileObject);
318 /* FIXME: try fast I/O first */
319 CcMdlReadCompleteDev (MdlChain,
320 DeviceObject);
321 }
322
323
324 /* EOF */