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