ee548826ba9e6fc30b5f4a6fc3eceef7a3cb5f2e
[reactos.git] / drivers / filesystems / cdfs_new / workque.c
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 \f
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 \f
100
101 _Requires_lock_held_(_Global_critical_region_)
102 VOID
103 CdPrePostIrp (
104 _Inout_ PIRP_CONTEXT IrpContext,
105 _Inout_ PIRP Irp
106 )
107
108 /*++
109
110 Routine Description:
111
112 This routine performs any neccessary work before STATUS_PENDING is
113 returned with the Fsd thread. This routine is called within the
114 filesystem and by the oplock package.
115
116 Arguments:
117
118 Context - Pointer to the IrpContext to be queued to the Fsp
119
120 Irp - I/O Request Packet.
121
122 Return Value:
123
124 None.
125
126 --*/
127
128 {
129 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
130 BOOLEAN RemovedFcb;
131
132 PAGED_CODE();
133
134 ASSERT_IRP_CONTEXT( IrpContext );
135 ASSERT_IRP( Irp );
136
137 //
138 // Case on the type of the operation.
139 //
140
141 switch (IrpContext->MajorFunction) {
142
143 case IRP_MJ_CREATE :
144
145 //
146 // If called from the oplock package then there is an
147 // Fcb to possibly teardown. We will call the teardown
148 // routine and release the Fcb if still present. The cleanup
149 // code in create will know not to release this Fcb because
150 // we will clear the pointer.
151 //
152
153 if ((IrpContext->TeardownFcb != NULL) &&
154 *(IrpContext->TeardownFcb) != NULL) {
155
156 CdTeardownStructures( IrpContext, *(IrpContext->TeardownFcb), &RemovedFcb );
157
158 if (!RemovedFcb) {
159
160 _Analysis_assume_lock_held_((*IrpContext->TeardownFcb)->FcbNonpaged->FcbResource);
161 CdReleaseFcb( IrpContext, *(IrpContext->TeardownFcb) );
162 }
163
164 *(IrpContext->TeardownFcb) = NULL;
165 IrpContext->TeardownFcb = NULL;
166 }
167
168 break;
169
170 //
171 // We need to lock the user's buffer, unless this is an MDL read/write,
172 // in which case there is no user buffer.
173 //
174
175 case IRP_MJ_READ :
176
177 if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
178
179 CdLockUserBuffer( IrpContext, IrpSp->Parameters.Read.Length, IoWriteAccess );
180 }
181
182 break;
183
184 case IRP_MJ_WRITE :
185
186 if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
187
188 CdLockUserBuffer( IrpContext, IrpSp->Parameters.Read.Length, IoReadAccess );
189 }
190
191 break;
192
193 //
194 // We also need to check whether this is a query file operation.
195 //
196
197 case IRP_MJ_DIRECTORY_CONTROL :
198
199 if (IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
200
201 CdLockUserBuffer( IrpContext, IrpSp->Parameters.QueryDirectory.Length, IoWriteAccess );
202 }
203
204 break;
205 }
206
207 //
208 // Cleanup the IrpContext for the post.
209 //
210
211 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
212 CdCleanupIrpContext( IrpContext, TRUE );
213
214 //
215 // Mark the Irp to show that we've already returned pending to the user.
216 //
217
218 IoMarkIrpPending( Irp );
219
220 return;
221 }
222
223 \f
224
225 _Requires_lock_held_(_Global_critical_region_)
226 VOID
227 CdOplockComplete (
228 _Inout_ PIRP_CONTEXT IrpContext,
229 _Inout_ PIRP Irp
230 )
231
232 /*++
233
234 Routine Description:
235
236 This routine is called by the oplock package when an oplock break has
237 completed, allowing an Irp to resume execution. If the status in
238 the Irp is STATUS_SUCCESS, then we queue the Irp to the Fsp queue.
239 Otherwise we complete the Irp with the status in the Irp.
240
241 If we are completing due to an error then check if there is any
242 cleanup to do.
243
244 Arguments:
245
246 Irp - I/O Request Packet.
247
248 Return Value:
249
250 None.
251
252 --*/
253
254 {
255 BOOLEAN RemovedFcb;
256
257 PAGED_CODE();
258
259 //
260 // Check on the return value in the Irp. If success then we
261 // are to post this request.
262 //
263
264 if (Irp->IoStatus.Status == STATUS_SUCCESS) {
265
266 //
267 // Check if there is any cleanup work to do.
268 //
269
270 switch (IrpContext->MajorFunction) {
271
272 case IRP_MJ_CREATE :
273
274 //
275 // If called from the oplock package then there is an
276 // Fcb to possibly teardown. We will call the teardown
277 // routine and release the Fcb if still present. The cleanup
278 // code in create will know not to release this Fcb because
279 // we will clear the pointer.
280 //
281
282 if (IrpContext->TeardownFcb != NULL) {
283
284 CdTeardownStructures( IrpContext, *(IrpContext->TeardownFcb), &RemovedFcb );
285
286 if (!RemovedFcb) {
287
288 _Analysis_assume_lock_held_((*IrpContext->TeardownFcb)->FcbNonpaged->FcbResource);
289 CdReleaseFcb( IrpContext, *(IrpContext->TeardownFcb) );
290 }
291
292 *(IrpContext->TeardownFcb) = NULL;
293 IrpContext->TeardownFcb = NULL;
294 }
295
296 break;
297 }
298
299 //
300 // Insert the Irp context in the workqueue.
301 //
302
303 CdAddToWorkque( IrpContext, Irp );
304
305 //
306 // Otherwise complete the request.
307 //
308
309 } else {
310
311 CdCompleteRequest( IrpContext, Irp, Irp->IoStatus.Status );
312 }
313
314 return;
315 }
316
317 \f
318 //
319 // Local support routine
320 //
321
322 VOID
323 CdAddToWorkque (
324 _Inout_ PIRP_CONTEXT IrpContext,
325 _Inout_ PIRP Irp
326 )
327
328 /*++
329
330 Routine Description:
331
332 This routine is called to acually store the posted Irp to the Fsp
333 workque.
334
335 Arguments:
336
337 IrpContext - Pointer to the IrpContext to be queued to the Fsp
338
339 Irp - I/O Request Packet.
340
341 Return Value:
342
343 None.
344
345 --*/
346
347 {
348 PVOLUME_DEVICE_OBJECT Vdo;
349 KIRQL SavedIrql;
350 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
351
352 //
353 // Check if this request has an associated file object, and thus volume
354 // device object.
355 //
356
357 if (IrpSp->FileObject != NULL) {
358
359
360 Vdo = CONTAINING_RECORD( IrpSp->DeviceObject,
361 VOLUME_DEVICE_OBJECT,
362 DeviceObject );
363
364 //
365 // Check to see if this request should be sent to the overflow
366 // queue. If not, then send it off to an exworker thread.
367 //
368
369 KeAcquireSpinLock( &Vdo->OverflowQueueSpinLock, &SavedIrql );
370
371 if (Vdo->PostedRequestCount > FSP_PER_DEVICE_THRESHOLD) {
372
373 //
374 // We cannot currently respond to this IRP so we'll just enqueue it
375 // to the overflow queue on the volume.
376 //
377
378 InsertTailList( &Vdo->OverflowQueue,
379 &IrpContext->WorkQueueItem.List );
380
381 Vdo->OverflowQueueCount += 1;
382
383 KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
384
385 return;
386
387 } else {
388
389 //
390 // We are going to send this Irp to an ex worker thread so up
391 // the count.
392 //
393
394 Vdo->PostedRequestCount += 1;
395
396 KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
397 }
398 }
399
400 //
401 // Send it off.....
402 //
403
404 #pragma prefast(suppress:28155, "the function prototype is correct")
405 ExInitializeWorkItem( &IrpContext->WorkQueueItem,
406 CdFspDispatch,
407 IrpContext );
408
409 #pragma prefast(suppress: 28159, "prefast believes this routine is obsolete, but it is ok for CDFS to continue using it")
410 ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
411
412 return;
413 }
414
415
416