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 Fat File
12     system.
13 
14 
15 --*/
16 
17 #include "fatprocs.h"
18 
19 //
20 //  The following constant is the maximum number of ExWorkerThreads that we
21 //  will allow to be servicing a particular target device at any one time.
22 //
23 
24 #define FSP_PER_DEVICE_THRESHOLD         (2)
25 
26 #ifdef ALLOC_PRAGMA
27 #pragma alloc_text(PAGE, FatOplockComplete)
28 #pragma alloc_text(PAGE, FatPrePostIrp)
29 #pragma alloc_text(PAGE, FatFsdPostRequest)
30 #endif
31 
32 
33 VOID
34 NTAPI
35 FatOplockComplete (
36     IN PVOID Context,
37     IN PIRP Irp
38     )
39 
40 /*++
41 
42 Routine Description:
43 
44     This routine is called by the oplock package when an oplock break has
45     completed, allowing an Irp to resume execution.  If the status in
46     the Irp is STATUS_SUCCESS, then we queue the Irp to the Fsp queue.
47     Otherwise we complete the Irp with the status in the Irp.
48 
49 Arguments:
50 
51     Context - Pointer to the IrpContext to be queued to the Fsp
52 
53     Irp - I/O Request Packet.
54 
55 Return Value:
56 
57     None.
58 
59 --*/
60 
61 {
62     PAGED_CODE();
63 
64     //
65     //  Check on the return value in the Irp.
66     //
67 
68     if (Irp->IoStatus.Status == STATUS_SUCCESS) {
69 
70         //
71         //  Insert the Irp context in the workqueue.
72         //
73 
74         FatAddToWorkque( (PIRP_CONTEXT) Context, Irp );
75 
76     //
77     //  Otherwise complete the request.
78     //
79 
80     } else {
81 
82         FatCompleteRequest( (PIRP_CONTEXT) Context, Irp, Irp->IoStatus.Status );
83     }
84 
85     return;
86 }
87 
88 
89 VOID
90 NTAPI
91 FatPrePostIrp (
92     IN PVOID Context,
93     IN PIRP Irp
94     )
95 
96 /*++
97 
98 Routine Description:
99 
100     This routine performs any neccessary work before STATUS_PENDING is
101     returned with the Fsd thread.  This routine is called within the
102     filesystem and by the oplock package.
103 
104 Arguments:
105 
106     Context - Pointer to the IrpContext to be queued to the Fsp
107 
108     Irp - I/O Request Packet.
109 
110 Return Value:
111 
112     None.
113 
114 --*/
115 
116 {
117     PIO_STACK_LOCATION IrpSp;
118     PIRP_CONTEXT IrpContext;
119 
120     PAGED_CODE();
121 
122     //
123     //  If there is no Irp, we are done.
124     //
125 
126     if (Irp == NULL) {
127 
128         return;
129     }
130 
131     IrpSp = IoGetCurrentIrpStackLocation( Irp );
132 
133     IrpContext = (PIRP_CONTEXT) Context;
134 
135     //
136     //  If there is a STACK FatIoContext pointer, clean and NULL it.
137     //
138 
139     if ((IrpContext->FatIoContext != NULL) &&
140         FlagOn(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT)) {
141 
142         ClearFlag(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT);
143         IrpContext->FatIoContext = NULL;
144     }
145 
146     //
147     //  We need to lock the user's buffer, unless this is an MDL-read,
148     //  in which case there is no user buffer.
149     //
150     //  **** we need a better test than non-MDL (read or write)!
151 
152     if (IrpContext->MajorFunction == IRP_MJ_READ ||
153         IrpContext->MajorFunction == IRP_MJ_WRITE) {
154 
155         //
156         //  If not an Mdl request, lock the user's buffer.
157         //
158 
159         if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
160 
161             FatLockUserBuffer( IrpContext,
162                                Irp,
163                                (IrpContext->MajorFunction == IRP_MJ_READ) ?
164                                IoWriteAccess : IoReadAccess,
165                                (IrpContext->MajorFunction == IRP_MJ_READ) ?
166                                IrpSp->Parameters.Read.Length : IrpSp->Parameters.Write.Length );
167         }
168 
169     //
170     //  We also need to check whether this is a query file operation.
171     //
172 
173     } else if (IrpContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL
174                && IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
175 
176         FatLockUserBuffer( IrpContext,
177                            Irp,
178                            IoWriteAccess,
179                            IrpSp->Parameters.QueryDirectory.Length );
180 
181     //
182     //  We also need to check whether this is a query ea operation.
183     //
184 
185     } else if (IrpContext->MajorFunction == IRP_MJ_QUERY_EA) {
186 
187         FatLockUserBuffer( IrpContext,
188                            Irp,
189                            IoWriteAccess,
190                            IrpSp->Parameters.QueryEa.Length );
191 
192     //
193     //  We also need to check whether this is a set ea operation.
194     //
195 
196     } else if (IrpContext->MajorFunction == IRP_MJ_SET_EA) {
197 
198         FatLockUserBuffer( IrpContext,
199                            Irp,
200                            IoReadAccess,
201                            IrpSp->Parameters.SetEa.Length );
202 
203     //
204     //  These two FSCTLs use neither I/O, so check for them.
205     //
206 
207     } else if ((IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
208                (IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST) &&
209                ((IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_VOLUME_BITMAP) ||
210                 (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_RETRIEVAL_POINTERS))) {
211 
212         FatLockUserBuffer( IrpContext,
213                            Irp,
214                            IoWriteAccess,
215                            IrpSp->Parameters.FileSystemControl.OutputBufferLength );
216     }
217 
218     //
219     //  Mark that we've already returned pending to the user
220     //
221 
222     IoMarkIrpPending( Irp );
223 
224     return;
225 }
226 
227 
228 NTSTATUS
229 FatFsdPostRequest(
230     IN PIRP_CONTEXT IrpContext,
231     IN PIRP Irp
232     )
233 
234 /*++
235 
236 Routine Description:
237 
238     This routine enqueues the request packet specified by IrpContext to the
239     Ex Worker threads.  This is a FSD routine.
240 
241 Arguments:
242 
243     IrpContext - Pointer to the IrpContext to be queued to the Fsp
244 
245     Irp - I/O Request Packet, or NULL if it has already been completed.
246 
247 Return Value:
248 
249     STATUS_PENDING
250 
251 
252 --*/
253 
254 {
255     PAGED_CODE();
256 
257     NT_ASSERT( ARGUMENT_PRESENT(Irp) );
258     NT_ASSERT( IrpContext->OriginatingIrp == Irp );
259 
260     FatPrePostIrp( IrpContext, Irp );
261 
262     FatAddToWorkque( IrpContext, Irp );
263 
264     //
265     //  And return to our caller
266     //
267 
268     return STATUS_PENDING;
269 }
270 
271 
272 //
273 //  Local support routine.
274 //
275 
276 VOID
277 #ifdef __REACTOS__
278 NTAPI
279 #endif
280 FatAddToWorkque (
281     IN PIRP_CONTEXT IrpContext,
282     IN PIRP Irp
283     )
284 
285 /*++
286 
287 Routine Description:
288 
289     This routine is called to acually store the posted Irp to the Fsp
290     workque.
291 
292 Arguments:
293 
294     IrpContext - Pointer to the IrpContext to be queued to the Fsp
295 
296     Irp - I/O Request Packet.
297 
298 Return Value:
299 
300     None.
301 
302 --*/
303 
304 {
305     KIRQL SavedIrql;
306     PIO_STACK_LOCATION IrpSp;
307 
308     IrpSp = IoGetCurrentIrpStackLocation( Irp );
309 
310     //
311     //  Check if this request has an associated file object, and thus volume
312     //  device object.
313     //
314 
315     if ( IrpSp->FileObject != NULL ) {
316 
317         PVOLUME_DEVICE_OBJECT Vdo;
318 
319         Vdo = CONTAINING_RECORD( IrpSp->DeviceObject,
320                                  VOLUME_DEVICE_OBJECT,
321                                  DeviceObject );
322 
323         //
324         //  Check to see if this request should be sent to the overflow
325         //  queue.  If not, then send it off to an exworker thread.
326         //
327 
328         KeAcquireSpinLock( &Vdo->OverflowQueueSpinLock, &SavedIrql );
329 
330         if ( Vdo->PostedRequestCount > FSP_PER_DEVICE_THRESHOLD) {
331 
332             //
333             //  We cannot currently respond to this IRP so we'll just enqueue it
334             //  to the overflow queue on the volume.
335             //
336 
337             InsertTailList( &Vdo->OverflowQueue,
338                             &IrpContext->WorkQueueItem.List );
339 
340             Vdo->OverflowQueueCount += 1;
341 
342             KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
343 
344             return;
345 
346         } else {
347 
348             //
349             //  We are going to send this Irp to an ex worker thread so up
350             //  the count.
351             //
352 
353             Vdo->PostedRequestCount += 1;
354 
355             KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
356         }
357     }
358 
359     //
360     //  Send it off.....
361     //
362 
363     ExInitializeWorkItem( &IrpContext->WorkQueueItem,
364                           FatFspDispatch,
365                           IrpContext );
366 
367 #ifdef _MSC_VER
368 #pragma prefast( suppress:28159, "prefast indicates this is an obsolete API but it is ok for fastfat to keep using it." )
369 #endif
370     ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
371 
372     return;
373 }
374 
375 
376