[FASTFAT_NEW] Import again FastFAT from MS. This time from GitHub for license reasons.
[reactos.git] / drivers / filesystems / fastfat_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 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 \f
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 \f
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 \f
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 \f
272 //
273 // Local support routine.
274 //
275
276 VOID
277 FatAddToWorkque (
278 IN PIRP_CONTEXT IrpContext,
279 IN PIRP Irp
280 )
281
282 /*++
283
284 Routine Description:
285
286 This routine is called to acually store the posted Irp to the Fsp
287 workque.
288
289 Arguments:
290
291 IrpContext - Pointer to the IrpContext to be queued to the Fsp
292
293 Irp - I/O Request Packet.
294
295 Return Value:
296
297 None.
298
299 --*/
300
301 {
302 KIRQL SavedIrql;
303 PIO_STACK_LOCATION IrpSp;
304
305 IrpSp = IoGetCurrentIrpStackLocation( Irp );
306
307 //
308 // Check if this request has an associated file object, and thus volume
309 // device object.
310 //
311
312 if ( IrpSp->FileObject != NULL ) {
313
314 PVOLUME_DEVICE_OBJECT Vdo;
315
316 Vdo = CONTAINING_RECORD( IrpSp->DeviceObject,
317 VOLUME_DEVICE_OBJECT,
318 DeviceObject );
319
320 //
321 // Check to see if this request should be sent to the overflow
322 // queue. If not, then send it off to an exworker thread.
323 //
324
325 KeAcquireSpinLock( &Vdo->OverflowQueueSpinLock, &SavedIrql );
326
327 if ( Vdo->PostedRequestCount > FSP_PER_DEVICE_THRESHOLD) {
328
329 //
330 // We cannot currently respond to this IRP so we'll just enqueue it
331 // to the overflow queue on the volume.
332 //
333
334 InsertTailList( &Vdo->OverflowQueue,
335 &IrpContext->WorkQueueItem.List );
336
337 Vdo->OverflowQueueCount += 1;
338
339 KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
340
341 return;
342
343 } else {
344
345 //
346 // We are going to send this Irp to an ex worker thread so up
347 // the count.
348 //
349
350 Vdo->PostedRequestCount += 1;
351
352 KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
353 }
354 }
355
356 //
357 // Send it off.....
358 //
359
360 ExInitializeWorkItem( &IrpContext->WorkQueueItem,
361 FatFspDispatch,
362 IrpContext );
363
364 #ifdef _MSC_VER
365 #pragma prefast( suppress:28159, "prefast indicates this is an obsolete API but it is ok for fastfat to keep using it." )
366 #endif
367 ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
368
369 return;
370 }
371
372