xref: /reactos/ntoskrnl/config/cmdelay.c (revision 5c7ce447)
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