xref: /reactos/drivers/filesystems/cdfs/workque.c (revision 4561998a)
1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     WorkQue.c
8 
9 Abstract:
10 
11     This module implements the Work queue routines for the Cdfs File
12     system.
13 
14 
15 --*/
16 
17 #include "cdprocs.h"
18 
19 //
20 //  The Bug check file id for this module
21 //
22 
23 #define BugCheckFileId                   (CDFS_BUG_CHECK_WORKQUE)
24 
25 //
26 //  The following constant is the maximum number of ExWorkerThreads that we
27 //  will allow to be servicing a particular target device at any one time.
28 //
29 
30 #define FSP_PER_DEVICE_THRESHOLD         (2)
31 
32 //
33 //  Local support routines
34 //
35 
36 VOID
37 CdAddToWorkque (
38     _Inout_ PIRP_CONTEXT IrpContext,
39     _Inout_ PIRP Irp
40     );
41 
42 #ifdef ALLOC_PRAGMA
43 #pragma alloc_text(PAGE, CdFsdPostRequest)
44 #pragma alloc_text(PAGE, CdOplockComplete)
45 #pragma alloc_text(PAGE, CdPrePostIrp)
46 #endif
47 
48 
49 _Requires_lock_held_(_Global_critical_region_)
50 NTSTATUS
51 CdFsdPostRequest (
52     _Inout_ PIRP_CONTEXT IrpContext,
53     _Inout_ PIRP Irp
54     )
55 
56 /*++
57 
58 Routine Description:
59 
60     This routine enqueues the request packet specified by IrpContext to the
61     work queue associated with the FileSystemDeviceObject.  This is a FSD
62     routine.
63 
64 Arguments:
65 
66     IrpContext - Pointer to the IrpContext to be queued to the Fsp.
67 
68     Irp - I/O Request Packet.
69 
70 Return Value:
71 
72     STATUS_PENDING
73 
74 --*/
75 
76 {
77     PAGED_CODE();
78 
79     ASSERT_IRP_CONTEXT( IrpContext );
80     ASSERT_IRP( Irp );
81 
82     //
83     //  Posting is a three step operation.  First lock down any buffers
84     //  in the Irp.  Next cleanup the IrpContext for the post and finally
85     //  add this to a workque.
86     //
87 
88     CdPrePostIrp( IrpContext, Irp );
89 
90     CdAddToWorkque( IrpContext, Irp );
91 
92     //
93     //  And return to our caller
94     //
95 
96     return STATUS_PENDING;
97 }
98 
99 
100 
101 _Requires_lock_held_(_Global_critical_region_)
102 VOID
103 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
104 CdPrePostIrp (
105     _Inout_ PIRP_CONTEXT IrpContext,
106     _Inout_ PIRP Irp
107     )
108 
109 /*++
110 
111 Routine Description:
112 
113     This routine performs any neccessary work before STATUS_PENDING is
114     returned with the Fsd thread.  This routine is called within the
115     filesystem and by the oplock package.
116 
117 Arguments:
118 
119     Context - Pointer to the IrpContext to be queued to the Fsp
120 
121     Irp - I/O Request Packet.
122 
123 Return Value:
124 
125     None.
126 
127 --*/
128 
129 {
130     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
131     BOOLEAN RemovedFcb;
132 
133     PAGED_CODE();
134 
135     ASSERT_IRP_CONTEXT( IrpContext );
136     ASSERT_IRP( Irp );
137 
138     //
139     //  Case on the type of the operation.
140     //
141 
142     switch (IrpContext->MajorFunction) {
143 
144     case IRP_MJ_CREATE :
145 
146         //
147         //  If called from the oplock package then there is an
148         //  Fcb to possibly teardown.  We will call the teardown
149         //  routine and release the Fcb if still present.  The cleanup
150         //  code in create will know not to release this Fcb because
151         //  we will clear the pointer.
152         //
153 
154         if ((IrpContext->TeardownFcb != NULL) &&
155             *(IrpContext->TeardownFcb) != NULL) {
156 
157             CdTeardownStructures( IrpContext, *(IrpContext->TeardownFcb), &RemovedFcb );
158 
159             if (!RemovedFcb) {
160 
161                 _Analysis_assume_lock_held_((*IrpContext->TeardownFcb)->FcbNonpaged->FcbResource);
162                 CdReleaseFcb( IrpContext, *(IrpContext->TeardownFcb) );
163             }
164 
165             *(IrpContext->TeardownFcb) = NULL;
166             IrpContext->TeardownFcb = NULL;
167         }
168 
169         break;
170 
171     //
172     //  We need to lock the user's buffer, unless this is an MDL read/write,
173     //  in which case there is no user buffer.
174     //
175 
176     case IRP_MJ_READ :
177 
178         if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
179 
180             CdLockUserBuffer( IrpContext, IrpSp->Parameters.Read.Length, IoWriteAccess );
181         }
182 
183         break;
184 
185     case IRP_MJ_WRITE :
186 
187         if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
188 
189             CdLockUserBuffer( IrpContext, IrpSp->Parameters.Read.Length, IoReadAccess );
190         }
191 
192         break;
193 
194     //
195     //  We also need to check whether this is a query file operation.
196     //
197 
198     case IRP_MJ_DIRECTORY_CONTROL :
199 
200         if (IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
201 
202             CdLockUserBuffer( IrpContext, IrpSp->Parameters.QueryDirectory.Length, IoWriteAccess );
203         }
204 
205         break;
206     }
207 
208     //
209     //  Cleanup the IrpContext for the post.
210     //
211 
212     SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
213     CdCleanupIrpContext( IrpContext, TRUE );
214 
215     //
216     //  Mark the Irp to show that we've already returned pending to the user.
217     //
218 
219     IoMarkIrpPending( Irp );
220 
221     return;
222 }
223 
224 
225 
226 _Requires_lock_held_(_Global_critical_region_)
227 VOID
228 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
229 CdOplockComplete (
230     _Inout_ PIRP_CONTEXT IrpContext,
231     _Inout_ PIRP Irp
232     )
233 
234 /*++
235 
236 Routine Description:
237 
238     This routine is called by the oplock package when an oplock break has
239     completed, allowing an Irp to resume execution.  If the status in
240     the Irp is STATUS_SUCCESS, then we queue the Irp to the Fsp queue.
241     Otherwise we complete the Irp with the status in the Irp.
242 
243     If we are completing due to an error then check if there is any
244     cleanup to do.
245 
246 Arguments:
247 
248     Irp - I/O Request Packet.
249 
250 Return Value:
251 
252     None.
253 
254 --*/
255 
256 {
257     BOOLEAN RemovedFcb;
258 
259     PAGED_CODE();
260 
261     //
262     //  Check on the return value in the Irp.  If success then we
263     //  are to post this request.
264     //
265 
266     if (Irp->IoStatus.Status == STATUS_SUCCESS) {
267 
268         //
269         //  Check if there is any cleanup work to do.
270         //
271 
272         switch (IrpContext->MajorFunction) {
273 
274         case IRP_MJ_CREATE :
275 
276             //
277             //  If called from the oplock package then there is an
278             //  Fcb to possibly teardown.  We will call the teardown
279             //  routine and release the Fcb if still present.  The cleanup
280             //  code in create will know not to release this Fcb because
281             //  we will clear the pointer.
282             //
283 
284             if (IrpContext->TeardownFcb != NULL) {
285 
286                 CdTeardownStructures( IrpContext, *(IrpContext->TeardownFcb), &RemovedFcb );
287 
288                 if (!RemovedFcb) {
289 
290                     _Analysis_assume_lock_held_((*IrpContext->TeardownFcb)->FcbNonpaged->FcbResource);
291                     CdReleaseFcb( IrpContext, *(IrpContext->TeardownFcb) );
292                 }
293 
294                 *(IrpContext->TeardownFcb) = NULL;
295                 IrpContext->TeardownFcb = NULL;
296             }
297 
298             break;
299         }
300 
301         //
302         //  Insert the Irp context in the workqueue.
303         //
304 
305         CdAddToWorkque( IrpContext, Irp );
306 
307     //
308     //  Otherwise complete the request.
309     //
310 
311     } else {
312 
313         CdCompleteRequest( IrpContext, Irp, Irp->IoStatus.Status );
314     }
315 
316     return;
317 }
318 
319 
320 //
321 //  Local support routine
322 //
323 
324 VOID
325 CdAddToWorkque (
326     _Inout_ PIRP_CONTEXT IrpContext,
327     _Inout_ PIRP Irp
328     )
329 
330 /*++
331 
332 Routine Description:
333 
334     This routine is called to acually store the posted Irp to the Fsp
335     workque.
336 
337 Arguments:
338 
339     IrpContext - Pointer to the IrpContext to be queued to the Fsp
340 
341     Irp - I/O Request Packet.
342 
343 Return Value:
344 
345     None.
346 
347 --*/
348 
349 {
350     PVOLUME_DEVICE_OBJECT Vdo;
351     KIRQL SavedIrql;
352     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
353 
354     //
355     //  Check if this request has an associated file object, and thus volume
356     //  device object.
357     //
358 
359     if (IrpSp->FileObject != NULL) {
360 
361 
362         Vdo = CONTAINING_RECORD( IrpSp->DeviceObject,
363                                  VOLUME_DEVICE_OBJECT,
364                                  DeviceObject );
365 
366         //
367         //  Check to see if this request should be sent to the overflow
368         //  queue.  If not, then send it off to an exworker thread.
369         //
370 
371         KeAcquireSpinLock( &Vdo->OverflowQueueSpinLock, &SavedIrql );
372 
373         if (Vdo->PostedRequestCount > FSP_PER_DEVICE_THRESHOLD) {
374 
375             //
376             //  We cannot currently respond to this IRP so we'll just enqueue it
377             //  to the overflow queue on the volume.
378             //
379 
380             InsertTailList( &Vdo->OverflowQueue,
381                             &IrpContext->WorkQueueItem.List );
382 
383             Vdo->OverflowQueueCount += 1;
384 
385             KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
386 
387             return;
388 
389         } else {
390 
391             //
392             //  We are going to send this Irp to an ex worker thread so up
393             //  the count.
394             //
395 
396             Vdo->PostedRequestCount += 1;
397 
398             KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
399         }
400     }
401 
402     //
403     //  Send it off.....
404     //
405 
406 #ifdef _MSC_VER
407 #pragma prefast(suppress:28155, "the function prototype is correct")
408 #endif
409     ExInitializeWorkItem( &IrpContext->WorkQueueItem,
410                           (PVOID)CdFspDispatch,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
411                           IrpContext );
412 
413 #ifdef _MSC_VER
414 #pragma prefast(suppress: 28159, "prefast believes this routine is obsolete, but it is ok for CDFS to continue using it")
415 #endif
416     ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
417 
418     return;
419 }
420 
421 
422 
423