1c2c66affSColin Finck /*
2c2c66affSColin Finck * PROJECT: ReactOS Kernel
3c2c66affSColin Finck * LICENSE: GPL - See COPYING in the top level directory
4c2c66affSColin Finck * FILE: ntoskrnl/config/cmdelay.c
5c2c66affSColin Finck * PURPOSE: Routines for handling delay close and allocate.
6c2c66affSColin Finck * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7c2c66affSColin Finck */
8c2c66affSColin Finck
9c2c66affSColin Finck /* INCLUDES ******************************************************************/
10c2c66affSColin Finck
11c2c66affSColin Finck #include <ntoskrnl.h>
12c2c66affSColin Finck #define NDEBUG
13c2c66affSColin Finck #include <debug.h>
14c2c66affSColin Finck
15c2c66affSColin Finck /* GLOBALS *******************************************************************/
16c2c66affSColin Finck
17c2c66affSColin Finck WORK_QUEUE_ITEM CmpDelayDerefKCBWorkItem;
18c2c66affSColin Finck
19c2c66affSColin Finck ULONG CmpDelayedCloseSize = 2048;
20c2c66affSColin Finck ULONG CmpDelayedCloseElements;
21c2c66affSColin Finck KGUARDED_MUTEX CmpDelayedCloseTableLock;
22c2c66affSColin Finck BOOLEAN CmpDelayCloseWorkItemActive;
23c2c66affSColin Finck WORK_QUEUE_ITEM CmpDelayCloseWorkItem;
24c2c66affSColin Finck LIST_ENTRY CmpDelayedLRUListHead;
25c2c66affSColin Finck ULONG CmpDelayCloseIntervalInSeconds = 5;
26c2c66affSColin Finck KDPC CmpDelayCloseDpc;
27c2c66affSColin Finck KTIMER CmpDelayCloseTimer;
28c2c66affSColin Finck
29c2c66affSColin Finck KGUARDED_MUTEX CmpDelayDerefKCBLock;
30c2c66affSColin Finck BOOLEAN CmpDelayDerefKCBWorkItemActive;
31c2c66affSColin Finck LIST_ENTRY CmpDelayDerefKCBListHead;
32c2c66affSColin Finck ULONG CmpDelayDerefKCBIntervalInSeconds = 5;
33c2c66affSColin Finck KDPC CmpDelayDerefKCBDpc;
34c2c66affSColin Finck KTIMER CmpDelayDerefKCBTimer;
35c2c66affSColin Finck
36c2c66affSColin Finck /* FUNCTIONS *****************************************************************/
37c2c66affSColin Finck
_Function_class_(KDEFERRED_ROUTINE)38c2c66affSColin Finck _Function_class_(KDEFERRED_ROUTINE)
39c2c66affSColin Finck VOID
40c2c66affSColin Finck NTAPI
41c2c66affSColin Finck CmpDelayCloseDpcRoutine(IN PKDPC Dpc,
42c2c66affSColin Finck IN PVOID DeferredContext,
43c2c66affSColin Finck IN PVOID SystemArgument1,
44c2c66affSColin Finck IN PVOID SystemArgument2)
45c2c66affSColin Finck {
46c2c66affSColin Finck /* Sanity check */
47c2c66affSColin Finck ASSERT(CmpDelayCloseWorkItemActive);
48c2c66affSColin Finck
49c2c66affSColin Finck /* Queue the work item */
50c2c66affSColin Finck ExQueueWorkItem(&CmpDelayCloseWorkItem, DelayedWorkQueue);
51c2c66affSColin Finck }
52c2c66affSColin Finck
_Function_class_(WORKER_THREAD_ROUTINE)53c2c66affSColin Finck _Function_class_(WORKER_THREAD_ROUTINE)
54c2c66affSColin Finck VOID
55c2c66affSColin Finck NTAPI
56c2c66affSColin Finck CmpDelayCloseWorker(IN PVOID Context)
57c2c66affSColin Finck {
58c2c66affSColin Finck PCM_DELAYED_CLOSE_ENTRY ListEntry;
59c2c66affSColin Finck ULONG i, ConvKey;
60c2c66affSColin Finck PAGED_CODE();
61c2c66affSColin Finck
62c2c66affSColin Finck /* Sanity check */
63c2c66affSColin Finck ASSERT(CmpDelayCloseWorkItemActive);
64c2c66affSColin Finck
65c2c66affSColin Finck /* Lock the registry */
66c2c66affSColin Finck CmpLockRegistry();
67c2c66affSColin Finck
68c2c66affSColin Finck /* Acquire the delayed close table lock */
69c2c66affSColin Finck KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
70c2c66affSColin Finck
71c2c66affSColin Finck /* Iterate */
72c2c66affSColin Finck for (i = 0; i < (CmpDelayedCloseSize >> 2); i++)
73c2c66affSColin Finck {
74c2c66affSColin Finck /* Break out of the loop if there is nothing to process */
75c2c66affSColin Finck if (CmpDelayedCloseElements <= CmpDelayedCloseSize) break;
76c2c66affSColin Finck
77c2c66affSColin Finck /* Sanity check */
78c2c66affSColin Finck ASSERT(!IsListEmpty(&CmpDelayedLRUListHead));
79c2c66affSColin Finck
80c2c66affSColin Finck /* Get the entry */
81c2c66affSColin Finck ListEntry = CONTAINING_RECORD(CmpDelayedLRUListHead.Blink,
82c2c66affSColin Finck CM_DELAYED_CLOSE_ENTRY,
83c2c66affSColin Finck DelayedLRUList);
84c2c66affSColin Finck
85c2c66affSColin Finck /* Save the ConvKey value of the KCB */
86c2c66affSColin Finck ConvKey = ListEntry->KeyControlBlock->ConvKey;
87c2c66affSColin Finck
88c2c66affSColin Finck /* Release the delayed close table lock */
89c2c66affSColin Finck KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
90c2c66affSColin Finck
91c2c66affSColin Finck /* Acquire the KCB lock */
92c2c66affSColin Finck CmpAcquireKcbLockExclusiveByKey(ConvKey);
93c2c66affSColin Finck
94c2c66affSColin Finck /* Reacquire the delayed close table lock */
95c2c66affSColin Finck KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
96c2c66affSColin Finck
97c2c66affSColin Finck /* Get the entry */
98c2c66affSColin Finck ListEntry = CONTAINING_RECORD(CmpDelayedLRUListHead.Blink,
99c2c66affSColin Finck CM_DELAYED_CLOSE_ENTRY,
100c2c66affSColin Finck DelayedLRUList);
101c2c66affSColin Finck
102c2c66affSColin Finck /* Is the entry we have still the first one? */
103c2c66affSColin Finck if (CmpDelayedCloseElements <= CmpDelayedCloseSize)
104c2c66affSColin Finck {
105c2c66affSColin Finck /* No, someone already inserted an entry there */
106c2c66affSColin Finck CmpReleaseKcbLockByKey(ConvKey);
107c2c66affSColin Finck break;
108c2c66affSColin Finck }
109c2c66affSColin Finck
110c2c66affSColin Finck /* Is it a different entry? */
111c2c66affSColin Finck if (ConvKey != ListEntry->KeyControlBlock->ConvKey)
112c2c66affSColin Finck {
113c2c66affSColin Finck /* Release the delayed close table lock */
114c2c66affSColin Finck KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
115c2c66affSColin Finck
116c2c66affSColin Finck /* Release the KCB lock */
117c2c66affSColin Finck CmpReleaseKcbLockByKey(ConvKey);
118c2c66affSColin Finck
119c2c66affSColin Finck /* Reacquire the delayed close table lock */
120c2c66affSColin Finck KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
121c2c66affSColin Finck
122c2c66affSColin Finck /* Iterate again */
123c2c66affSColin Finck continue;
124c2c66affSColin Finck }
125c2c66affSColin Finck
126c2c66affSColin Finck /* Remove it from the end of the list */
127c2c66affSColin Finck ListEntry =
128c2c66affSColin Finck (PCM_DELAYED_CLOSE_ENTRY)RemoveTailList(&CmpDelayedLRUListHead);
129c2c66affSColin Finck
130c2c66affSColin Finck /* Get the containing entry */
131c2c66affSColin Finck ListEntry = CONTAINING_RECORD(ListEntry,
132c2c66affSColin Finck CM_DELAYED_CLOSE_ENTRY,
133c2c66affSColin Finck DelayedLRUList);
134c2c66affSColin Finck
135c2c66affSColin Finck /* Process the entry */
136c2c66affSColin Finck if ((ListEntry->KeyControlBlock->RefCount) ||
137c2c66affSColin Finck (ListEntry->KeyControlBlock->DelayedCloseIndex))
138c2c66affSColin Finck {
139c2c66affSColin Finck /* Add it to the beginning of the list */
140c2c66affSColin Finck InsertHeadList(&CmpDelayedLRUListHead, &ListEntry->DelayedLRUList);
141c2c66affSColin Finck
142c2c66affSColin Finck /* Release the delayed close table lock */
143c2c66affSColin Finck KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
144c2c66affSColin Finck }
145c2c66affSColin Finck else
146c2c66affSColin Finck {
147c2c66affSColin Finck /* Release the delayed close table lock */
148c2c66affSColin Finck KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
149c2c66affSColin Finck
150c2c66affSColin Finck /* Zero out the DelayCloseEntry pointer */
151c2c66affSColin Finck ListEntry->KeyControlBlock->DelayCloseEntry = NULL;
152c2c66affSColin Finck
153c2c66affSColin Finck /* Cleanup the KCB cache */
154c2c66affSColin Finck CmpCleanUpKcbCacheWithLock(ListEntry->KeyControlBlock, FALSE);
155c2c66affSColin Finck
156c2c66affSColin Finck /* Free the delay item */
157c2c66affSColin Finck CmpFreeDelayItem(ListEntry);
158c2c66affSColin Finck
159c2c66affSColin Finck /* Decrement delayed close elements count */
160c2c66affSColin Finck InterlockedDecrement((PLONG)&CmpDelayedCloseElements);
161c2c66affSColin Finck }
162c2c66affSColin Finck
163c2c66affSColin Finck /* Release the KCB lock */
164c2c66affSColin Finck CmpReleaseKcbLockByKey(ConvKey);
165c2c66affSColin Finck
166c2c66affSColin Finck /* Reacquire the delayed close table lock */
167c2c66affSColin Finck KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
168c2c66affSColin Finck }
169c2c66affSColin Finck
170c2c66affSColin Finck if (CmpDelayedCloseElements <= CmpDelayedCloseSize)
171c2c66affSColin Finck {
172c2c66affSColin Finck /* We're not active anymore */
173c2c66affSColin Finck CmpDelayCloseWorkItemActive = FALSE;
174c2c66affSColin Finck }
175c2c66affSColin Finck else
176c2c66affSColin Finck {
177c2c66affSColin Finck /* We didn't process all things, so reschedule for the next time */
178c2c66affSColin Finck CmpArmDelayedCloseTimer();
179c2c66affSColin Finck }
180c2c66affSColin Finck
181c2c66affSColin Finck /* Release the delayed close table lock */
182c2c66affSColin Finck KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
183c2c66affSColin Finck
184c2c66affSColin Finck /* Unlock the registry */
185c2c66affSColin Finck CmpUnlockRegistry();
186c2c66affSColin Finck }
187c2c66affSColin Finck
188*5c7ce447SVictor Perevertkin CODE_SEG("INIT")
189c2c66affSColin Finck VOID
190c2c66affSColin Finck NTAPI
CmpInitializeDelayedCloseTable(VOID)191c2c66affSColin Finck CmpInitializeDelayedCloseTable(VOID)
192c2c66affSColin Finck {
193c2c66affSColin Finck
194c2c66affSColin Finck /* Setup the delayed close lock */
195c2c66affSColin Finck KeInitializeGuardedMutex(&CmpDelayedCloseTableLock);
196c2c66affSColin Finck
197c2c66affSColin Finck /* Setup the work item */
198c2c66affSColin Finck ExInitializeWorkItem(&CmpDelayCloseWorkItem, CmpDelayCloseWorker, NULL);
199c2c66affSColin Finck
200c2c66affSColin Finck /* Setup the list head */
201c2c66affSColin Finck InitializeListHead(&CmpDelayedLRUListHead);
202c2c66affSColin Finck
203c2c66affSColin Finck /* Setup the DPC and its timer */
204c2c66affSColin Finck KeInitializeDpc(&CmpDelayCloseDpc, CmpDelayCloseDpcRoutine, NULL);
205c2c66affSColin Finck KeInitializeTimer(&CmpDelayCloseTimer);
206c2c66affSColin Finck }
207c2c66affSColin Finck
_Function_class_(KDEFERRED_ROUTINE)208c2c66affSColin Finck _Function_class_(KDEFERRED_ROUTINE)
209c2c66affSColin Finck VOID
210c2c66affSColin Finck NTAPI
211c2c66affSColin Finck CmpDelayDerefKCBDpcRoutine(IN PKDPC Dpc,
212c2c66affSColin Finck IN PVOID DeferredContext,
213c2c66affSColin Finck IN PVOID SystemArgument1,
214c2c66affSColin Finck IN PVOID SystemArgument2)
215c2c66affSColin Finck {
216c2c66affSColin Finck /* Sanity check */
217c2c66affSColin Finck ASSERT(CmpDelayDerefKCBWorkItemActive);
218c2c66affSColin Finck
219c2c66affSColin Finck /* Queue the work item */
220c2c66affSColin Finck ExQueueWorkItem(&CmpDelayDerefKCBWorkItem, DelayedWorkQueue);
221c2c66affSColin Finck }
222c2c66affSColin Finck
_Function_class_(WORKER_THREAD_ROUTINE)223c2c66affSColin Finck _Function_class_(WORKER_THREAD_ROUTINE)
224c2c66affSColin Finck VOID
225c2c66affSColin Finck NTAPI
226c2c66affSColin Finck CmpDelayDerefKCBWorker(IN PVOID Context)
227c2c66affSColin Finck {
228c2c66affSColin Finck PCM_DELAY_DEREF_KCB_ITEM Entry;
229c2c66affSColin Finck PAGED_CODE();
230c2c66affSColin Finck
231c2c66affSColin Finck /* Sanity check */
232c2c66affSColin Finck ASSERT(CmpDelayDerefKCBWorkItemActive);
233c2c66affSColin Finck
234c2c66affSColin Finck /* Lock the registry and and list lock */
235c2c66affSColin Finck CmpLockRegistry();
236c2c66affSColin Finck KeAcquireGuardedMutex(&CmpDelayDerefKCBLock);
237c2c66affSColin Finck
238c2c66affSColin Finck /* Check if the list is empty */
239c2c66affSColin Finck while (!IsListEmpty(&CmpDelayDerefKCBListHead))
240c2c66affSColin Finck {
241c2c66affSColin Finck /* Grab an entry */
242c2c66affSColin Finck Entry = (PVOID)RemoveHeadList(&CmpDelayDerefKCBListHead);
243c2c66affSColin Finck
244c2c66affSColin Finck /* We can release the lock now */
245c2c66affSColin Finck KeReleaseGuardedMutex(&CmpDelayDerefKCBLock);
246c2c66affSColin Finck
247c2c66affSColin Finck /* Now grab the actual entry */
248c2c66affSColin Finck Entry = CONTAINING_RECORD(Entry, CM_DELAY_DEREF_KCB_ITEM, ListEntry);
249c2c66affSColin Finck Entry->ListEntry.Flink = Entry->ListEntry.Blink = NULL;
250c2c66affSColin Finck
251c2c66affSColin Finck /* Dereference and free */
252c2c66affSColin Finck CmpDereferenceKeyControlBlock(Entry->Kcb);
253c2c66affSColin Finck CmpFreeDelayItem(Entry);
254c2c66affSColin Finck
255c2c66affSColin Finck /* Lock the list again */
256c2c66affSColin Finck KeAcquireGuardedMutex(&CmpDelayDerefKCBLock);
257c2c66affSColin Finck }
258c2c66affSColin Finck
259c2c66affSColin Finck /* We're done */
260c2c66affSColin Finck CmpDelayDerefKCBWorkItemActive = FALSE;
261c2c66affSColin Finck KeReleaseGuardedMutex(&CmpDelayDerefKCBLock);
262c2c66affSColin Finck CmpUnlockRegistry();
263c2c66affSColin Finck }
264c2c66affSColin Finck
265*5c7ce447SVictor Perevertkin CODE_SEG("INIT")
266c2c66affSColin Finck VOID
267c2c66affSColin Finck NTAPI
CmpInitDelayDerefKCBEngine(VOID)268c2c66affSColin Finck CmpInitDelayDerefKCBEngine(VOID)
269c2c66affSColin Finck {
270c2c66affSColin Finck /* Initialize lock and list */
271c2c66affSColin Finck KeInitializeGuardedMutex(&CmpDelayDerefKCBLock);
272c2c66affSColin Finck InitializeListHead(&CmpDelayDerefKCBListHead);
273c2c66affSColin Finck
274c2c66affSColin Finck /* Setup the work item */
275c2c66affSColin Finck ExInitializeWorkItem(&CmpDelayDerefKCBWorkItem,
276c2c66affSColin Finck CmpDelayDerefKCBWorker,
277c2c66affSColin Finck NULL);
278c2c66affSColin Finck
279c2c66affSColin Finck /* Setup the DPC and timer for it */
280c2c66affSColin Finck KeInitializeDpc(&CmpDelayDerefKCBDpc, CmpDelayDerefKCBDpcRoutine, NULL);
281c2c66affSColin Finck KeInitializeTimer(&CmpDelayDerefKCBTimer);
282c2c66affSColin Finck }
283c2c66affSColin Finck
284c2c66affSColin Finck VOID
285c2c66affSColin Finck NTAPI
CmpDelayDerefKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)286c2c66affSColin Finck CmpDelayDerefKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
287c2c66affSColin Finck {
288c2c66affSColin Finck LONG OldRefCount, NewRefCount;
289c2c66affSColin Finck LARGE_INTEGER Timeout;
290c2c66affSColin Finck PCM_DELAY_DEREF_KCB_ITEM Entry;
291c2c66affSColin Finck PAGED_CODE();
292c2c66affSColin Finck CMTRACE(CM_REFERENCE_DEBUG,
293c2c66affSColin Finck "%s - Dereferencing KCB: %p\n", __FUNCTION__, Kcb);
294c2c66affSColin Finck
295c2c66affSColin Finck /* Get the previous reference count */
296c2c66affSColin Finck OldRefCount = *(PLONG)&Kcb->RefCount;
297c2c66affSColin Finck NewRefCount = OldRefCount - 1;
298c2c66affSColin Finck if (((NewRefCount & 0xFFFF) > 0) &&
299c2c66affSColin Finck (InterlockedCompareExchange((PLONG)&Kcb->RefCount,
300c2c66affSColin Finck NewRefCount,
301c2c66affSColin Finck OldRefCount) == OldRefCount))
302c2c66affSColin Finck {
303c2c66affSColin Finck /* KCB still had references, so we're done */
304c2c66affSColin Finck return;
305c2c66affSColin Finck }
306c2c66affSColin Finck
307c2c66affSColin Finck /* Allocate a delay item */
308c2c66affSColin Finck Entry = CmpAllocateDelayItem();
309c2c66affSColin Finck if (!Entry) return;
310c2c66affSColin Finck
311c2c66affSColin Finck /* Set the KCB */
312c2c66affSColin Finck Entry->Kcb = Kcb;
313c2c66affSColin Finck
314c2c66affSColin Finck /* Acquire the delayed deref table lock */
315c2c66affSColin Finck KeAcquireGuardedMutex(&CmpDelayDerefKCBLock);
316c2c66affSColin Finck
317c2c66affSColin Finck /* Insert the entry into the list */
318c2c66affSColin Finck InsertTailList(&CmpDelayDerefKCBListHead, &Entry->ListEntry);
319c2c66affSColin Finck
320c2c66affSColin Finck /* Check if we need to enable anything */
321c2c66affSColin Finck if (!CmpDelayDerefKCBWorkItemActive)
322c2c66affSColin Finck {
323c2c66affSColin Finck /* Yes, we have no work item, setup the interval */
324c2c66affSColin Finck CmpDelayDerefKCBWorkItemActive = TRUE;
325c2c66affSColin Finck Timeout.QuadPart = CmpDelayDerefKCBIntervalInSeconds * -10000000;
326c2c66affSColin Finck KeSetTimer(&CmpDelayDerefKCBTimer, Timeout, &CmpDelayDerefKCBDpc);
327c2c66affSColin Finck }
328c2c66affSColin Finck
329c2c66affSColin Finck /* Release the table lock */
330c2c66affSColin Finck KeReleaseGuardedMutex(&CmpDelayDerefKCBLock);
331c2c66affSColin Finck }
332c2c66affSColin Finck
333c2c66affSColin Finck VOID
334c2c66affSColin Finck NTAPI
CmpArmDelayedCloseTimer(VOID)335c2c66affSColin Finck CmpArmDelayedCloseTimer(VOID)
336c2c66affSColin Finck {
337c2c66affSColin Finck LARGE_INTEGER Timeout;
338c2c66affSColin Finck PAGED_CODE();
339c2c66affSColin Finck
340c2c66affSColin Finck /* Set the worker active */
341c2c66affSColin Finck CmpDelayCloseWorkItemActive = TRUE;
342c2c66affSColin Finck
343c2c66affSColin Finck /* Setup the interval */
344c2c66affSColin Finck Timeout.QuadPart = CmpDelayCloseIntervalInSeconds * -10000000;
345c2c66affSColin Finck KeSetTimer(&CmpDelayCloseTimer, Timeout, &CmpDelayCloseDpc);
346c2c66affSColin Finck }
347c2c66affSColin Finck
348c2c66affSColin Finck VOID
349c2c66affSColin Finck NTAPI
CmpAddToDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb,IN BOOLEAN LockHeldExclusively)350c2c66affSColin Finck CmpAddToDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb,
351c2c66affSColin Finck IN BOOLEAN LockHeldExclusively)
352c2c66affSColin Finck {
353c2c66affSColin Finck ULONG i;
354c2c66affSColin Finck ULONG OldRefCount, NewRefCount;
355c2c66affSColin Finck PCM_DELAYED_CLOSE_ENTRY Entry;
356c2c66affSColin Finck PAGED_CODE();
357c2c66affSColin Finck
358c2c66affSColin Finck /* Sanity check */
359c2c66affSColin Finck CMP_ASSERT_KCB_LOCK(Kcb);
360c2c66affSColin Finck
361c2c66affSColin Finck /* Make sure it's valid */
362c2c66affSColin Finck if (Kcb->DelayedCloseIndex != CmpDelayedCloseSize) ASSERT(FALSE);
363c2c66affSColin Finck
364c2c66affSColin Finck /* Sanity checks */
365c2c66affSColin Finck ASSERT(Kcb->RefCount == 0);
366c2c66affSColin Finck ASSERT(IsListEmpty(&Kcb->KeyBodyListHead) == TRUE);
367c2c66affSColin Finck for (i = 0; i < 4; i++) ASSERT(Kcb->KeyBodyArray[i] == NULL);
368c2c66affSColin Finck
369c2c66affSColin Finck /* Allocate a delay item */
370c2c66affSColin Finck Entry = CmpAllocateDelayItem();
371c2c66affSColin Finck if (!Entry)
372c2c66affSColin Finck {
373c2c66affSColin Finck /* Cleanup immediately */
374c2c66affSColin Finck CmpCleanUpKcbCacheWithLock(Kcb, LockHeldExclusively);
375c2c66affSColin Finck return;
376c2c66affSColin Finck }
377c2c66affSColin Finck
378c2c66affSColin Finck /* Sanity check */
379c2c66affSColin Finck if (Kcb->InDelayClose) ASSERT(FALSE);
380c2c66affSColin Finck
381c2c66affSColin Finck /* Get the previous reference count */
382c2c66affSColin Finck OldRefCount = *(PLONG)&Kcb->InDelayClose;
383c2c66affSColin Finck ASSERT(OldRefCount == 0);
384c2c66affSColin Finck
385c2c66affSColin Finck /* Write the new one */
386c2c66affSColin Finck NewRefCount = 1;
387c2c66affSColin Finck if (InterlockedCompareExchange((PLONG)&Kcb->InDelayClose,
388c2c66affSColin Finck NewRefCount,
389c2c66affSColin Finck OldRefCount) != OldRefCount)
390c2c66affSColin Finck {
391c2c66affSColin Finck /* Sanity check */
392c2c66affSColin Finck ASSERT(FALSE);
393c2c66affSColin Finck }
394c2c66affSColin Finck
395c2c66affSColin Finck /* Reset the delayed close index */
396c2c66affSColin Finck Kcb->DelayedCloseIndex = 0;
397c2c66affSColin Finck
398c2c66affSColin Finck /* Set up the close entry */
399c2c66affSColin Finck Kcb->DelayCloseEntry = Entry;
400c2c66affSColin Finck Entry->KeyControlBlock = Kcb;
401c2c66affSColin Finck
402c2c66affSColin Finck /* Increase the number of elements */
403c2c66affSColin Finck InterlockedIncrement((PLONG)&CmpDelayedCloseElements);
404c2c66affSColin Finck
405c2c66affSColin Finck /* Acquire the delayed close table lock */
406c2c66affSColin Finck KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
407c2c66affSColin Finck
408c2c66affSColin Finck /* Insert the entry into the list */
409c2c66affSColin Finck InsertHeadList(&CmpDelayedLRUListHead, &Entry->DelayedLRUList);
410c2c66affSColin Finck
411c2c66affSColin Finck /* Check if we need to enable anything */
412c2c66affSColin Finck if ((CmpDelayedCloseElements > CmpDelayedCloseSize) &&
413c2c66affSColin Finck !(CmpDelayCloseWorkItemActive))
414c2c66affSColin Finck {
415c2c66affSColin Finck /* Yes, we have too many elements to close, and no work item */
416c2c66affSColin Finck CmpArmDelayedCloseTimer();
417c2c66affSColin Finck }
418c2c66affSColin Finck
419c2c66affSColin Finck /* Release the table lock */
420c2c66affSColin Finck KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
421c2c66affSColin Finck }
422c2c66affSColin Finck
423c2c66affSColin Finck VOID
424c2c66affSColin Finck NTAPI
CmpRemoveFromDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb)425c2c66affSColin Finck CmpRemoveFromDelayedClose(IN PCM_KEY_CONTROL_BLOCK Kcb)
426c2c66affSColin Finck {
427c2c66affSColin Finck PCM_DELAYED_CLOSE_ENTRY Entry;
428c2c66affSColin Finck ULONG NewRefCount, OldRefCount;
429c2c66affSColin Finck PAGED_CODE();
430c2c66affSColin Finck
431c2c66affSColin Finck /* Sanity checks */
432c2c66affSColin Finck CMP_ASSERT_KCB_LOCK(Kcb);
433c2c66affSColin Finck if (Kcb->DelayedCloseIndex == CmpDelayedCloseSize) ASSERT(FALSE);
434c2c66affSColin Finck
435c2c66affSColin Finck /* Get the entry and lock the table */
436c2c66affSColin Finck Entry = Kcb->DelayCloseEntry;
437c2c66affSColin Finck ASSERT(Entry);
438c2c66affSColin Finck KeAcquireGuardedMutex(&CmpDelayedCloseTableLock);
439c2c66affSColin Finck
440c2c66affSColin Finck /* Remove the entry */
441c2c66affSColin Finck RemoveEntryList(&Entry->DelayedLRUList);
442c2c66affSColin Finck
443c2c66affSColin Finck /* Release the lock */
444c2c66affSColin Finck KeReleaseGuardedMutex(&CmpDelayedCloseTableLock);
445c2c66affSColin Finck
446c2c66affSColin Finck /* Free the entry */
447c2c66affSColin Finck CmpFreeDelayItem(Entry);
448c2c66affSColin Finck
449c2c66affSColin Finck /* Reduce the number of elements */
450c2c66affSColin Finck InterlockedDecrement((PLONG)&CmpDelayedCloseElements);
451c2c66affSColin Finck
452c2c66affSColin Finck /* Sanity check */
453c2c66affSColin Finck if (!Kcb->InDelayClose) ASSERT(FALSE);
454c2c66affSColin Finck
455c2c66affSColin Finck /* Get the previous reference count */
456c2c66affSColin Finck OldRefCount = *(PLONG)&Kcb->InDelayClose;
457c2c66affSColin Finck ASSERT(OldRefCount == 1);
458c2c66affSColin Finck
459c2c66affSColin Finck /* Write the new one */
460c2c66affSColin Finck NewRefCount = 0;
461c2c66affSColin Finck if (InterlockedCompareExchange((PLONG)&Kcb->InDelayClose,
462c2c66affSColin Finck NewRefCount,
463c2c66affSColin Finck OldRefCount) != OldRefCount)
464c2c66affSColin Finck {
465c2c66affSColin Finck /* Sanity check */
466c2c66affSColin Finck ASSERT(FALSE);
467c2c66affSColin Finck }
468c2c66affSColin Finck
469c2c66affSColin Finck /* Remove the link to the entry */
470c2c66affSColin Finck Kcb->DelayCloseEntry = NULL;
471c2c66affSColin Finck
472c2c66affSColin Finck /* Set new delay size and remove the delete flag */
473c2c66affSColin Finck Kcb->DelayedCloseIndex = CmpDelayedCloseSize;
474c2c66affSColin Finck }
475