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