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