1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxFileObject.hpp 8 9 Abstract: 10 11 This module implements a frameworks managed FileObject 12 13 Author: 14 15 16 17 Environment: 18 19 Both kernel and user mode 20 21 Revision History: 22 23 24 --*/ 25 26 #include "coreprivshared.hpp" 27 28 // Tracing support 29 extern "C" { 30 // #include "FxFileObject.tmh" 31 } 32 33 // 34 // Public constructors 35 // 36 37 38 FxFileObject::FxFileObject( 39 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 40 __in MdFileObject pWdmFileObject, 41 __in FxDevice* pDevice 42 ) : 43 FxNonPagedObject(FX_TYPE_FILEOBJECT, sizeof(FxFileObject), FxDriverGlobals) 44 { 45 m_FileObject.SetFileObject(pWdmFileObject); 46 m_PkgContext = NULL; 47 m_Device = pDevice; 48 49 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 50 RtlInitUnicodeString(&m_FileName, NULL); 51 m_RelatedFileObject = NULL; 52 #endif 53 54 // 55 // Cannot be deleted by the device driver 56 // 57 MarkNoDeleteDDI(); 58 } 59 60 FxFileObject::~FxFileObject() 61 { 62 #if (FX_CORE_MODE == FX_CORE_USER_MODE) 63 SAFE_RELEASE(m_RelatedFileObject); 64 #endif 65 } 66 67 // 68 // Create the WDFFILEOBJECT and associate it with the WDM PFILE_OBJECT. 69 // 70 _Must_inspect_result_ 71 NTSTATUS 72 FxFileObject::_CreateFileObject( 73 __in FxDevice* pDevice, 74 __in MdIrp Irp, 75 __in WDF_FILEOBJECT_CLASS FileObjectClass, 76 __in_opt PWDF_OBJECT_ATTRIBUTES pObjectAttributes, 77 __in_opt MdFileObject pWdmFileObject, 78 __deref_out_opt FxFileObject** pFileObject 79 ) 80 { 81 NTSTATUS Status; 82 FxFileObject* pfo; 83 KIRQL irql; 84 WDF_FILEOBJECT_CLASS normalizedFileClass; 85 86 PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals(); 87 88 // 89 // Create does require a WDM file obj based on the normalized file obj 90 // class value. 91 // 92 normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass); 93 94 // 95 // No FileObject support 96 // 97 if( normalizedFileClass == WdfFileObjectNotRequired ) { 98 if( pFileObject != NULL ) *pFileObject = NULL; 99 return STATUS_SUCCESS; 100 } 101 102 // 103 // If fileobject support was specified, and a NULL 104 // WDM PFILE_OBJECT is supplied, then it's an error 105 // 106 if( pWdmFileObject == NULL ) { 107 108 // 109 // Seems like some filter driver above us sending a create without fileobject. 110 // We support this only if the FileObjectClass class is set to 111 // WdfFileObjectWdfCannotUseFsContexts and device is created to be 112 // exclusive. 113 // 114 if ( normalizedFileClass == WdfFileObjectWdfCannotUseFsContexts && 115 pDevice->IsExclusive() ) { 116 117 DO_NOTHING(); 118 119 } else { 120 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, 121 "WdfFileObjectWdfCanUseFsContexts is specified, but the Create " 122 "IRP %p doesn't have a fileObject\n", 123 Irp); 124 FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals()); 125 return STATUS_DEVICE_CONFIGURATION_ERROR; 126 } 127 128 } 129 130 // Allocate a new FxFileObject with context 131 pfo = new(pDevice->GetDriverGlobals(), pObjectAttributes) 132 FxFileObject(pDevice->GetDriverGlobals(), pWdmFileObject, pDevice); 133 134 if( pfo == NULL ) { 135 return STATUS_INSUFFICIENT_RESOURCES; 136 } 137 138 pfo->Initialize(Irp); 139 140 // Assign FxDevice as the parent for the file object 141 Status = pfo->Commit(pObjectAttributes, NULL, pDevice); 142 if( !NT_SUCCESS(Status) ) { 143 pfo->DeleteFromFailedCreate(); 144 return Status; 145 } 146 147 // 148 // Place it on the list of FxFileObject's for this FxDevice 149 // 150 pDevice->Lock(&irql); 151 InsertHeadList(&pDevice->m_FileObjectListHead, &pfo->m_Link); 152 pDevice->Unlock(irql); 153 154 // 155 // Set file object context in mode-specific manner 156 // 157 pfo->SetFileObjectContext(pWdmFileObject, 158 normalizedFileClass, 159 Irp, 160 pDevice); 161 162 // FxFileObject* to caller 163 if( pFileObject != NULL ) { 164 *pFileObject = pfo; 165 } 166 167 return STATUS_SUCCESS; 168 } 169 170 // 171 // Destroy (dereference) the WDFFILEOBJECT related to the 172 // WDM PFILE_OBJECT according to its FileObjectClass. 173 // 174 VOID 175 FxFileObject::_DestroyFileObject( 176 __in FxDevice* pDevice, 177 __in WDF_FILEOBJECT_CLASS FileObjectClass, 178 __in_opt MdFileObject pWdmFileObject 179 ) 180 { 181 FxFileObject* pfo = NULL; 182 PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals(); 183 WDF_FILEOBJECT_CLASS normalizedFileClass; 184 185 // 186 // Close does require a WDM file obj based on the normalized file obj 187 // class value. 188 // 189 normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass); 190 191 if( normalizedFileClass == WdfFileObjectNotRequired ) { 192 return; 193 } 194 195 // 196 // Driver has specified file object support, and we 197 // allocated one at Create, so they must pass one 198 // to close, otherwise it's an error and we will leak 199 // the file object. 200 // 201 MxFileObject wdmFileObject(pWdmFileObject); 202 if( pWdmFileObject == NULL && 203 normalizedFileClass != WdfFileObjectWdfCannotUseFsContexts) { 204 205 // 206 // It's likely that IRP_MJ_CREATE had NULL for the Wdm FileObject as well. 207 // 208 // If a driver passes != NULL for Wdm FileObject to create, and NULL to 209 // this routine, a WDF FxFileObject object leak will occur, which will 210 // be reported at driver unload. 211 // 212 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, 213 "PFILE_OBJECT in close IRP is NULL, *Possible Leak of FxFileObject*\n"); 214 215 FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals()); 216 217 return; 218 } 219 else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext ) { 220 pfo = (FxFileObject*)wdmFileObject.GetFsContext(); 221 wdmFileObject.SetFsContext(NULL); 222 223 } 224 else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext2 ) { 225 pfo = (FxFileObject*)wdmFileObject.GetFsContext2(); 226 wdmFileObject.SetFsContext2(NULL); 227 } 228 else { 229 NTSTATUS status; 230 // 231 // We must find the associated FxFileObject from the list 232 // on the device 233 // 234 status = FxFileObject::_GetFileObjectFromWdm( 235 pDevice, 236 WdfFileObjectWdfCannotUseFsContexts, 237 pWdmFileObject, 238 &pfo 239 ); 240 241 // 242 // We should find it, unless a different one was passed to IRP_MJ_CLOSE 243 // than to IRP_MJ_CREATE, which is an error. 244 // 245 if (NT_SUCCESS(status) == FALSE || pfo == NULL) { 246 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 247 "Could not find WDFFILEOBJECT for PFILE_OBJECT 0x%p", 248 pWdmFileObject); 249 250 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 251 "Did a different PFILE_OBJECT get passed to " 252 "IRP_MJ_CLOSE than did to IRP_MJ_CREATE?"); 253 FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals()); 254 } 255 } 256 257 if( pfo != NULL ) { 258 KIRQL irql; 259 260 // 261 // Remove it from the list of FxFileObjects on the FxDevice 262 // 263 pDevice->Lock(&irql); 264 RemoveEntryList(&pfo->m_Link); 265 pDevice->Unlock(irql); 266 267 // Delete the file object 268 pfo->DeleteObject(); 269 } 270 271 return; 272 } 273 274 // 275 // Return the FxFileObject* for the given WDM PFILE_OBJECT 276 // 277 _Must_inspect_result_ 278 NTSTATUS 279 FxFileObject::_GetFileObjectFromWdm( 280 __in FxDevice* pDevice, 281 __in WDF_FILEOBJECT_CLASS FileObjectClass, 282 __in_opt MdFileObject pWdmFileObject, 283 __deref_out_opt FxFileObject** ppFxFileObject 284 ) 285 { 286 FxFileObject* pfo = NULL; 287 PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals(); 288 WDF_FILEOBJECT_CLASS normalizedFileClass; 289 290 // 291 // Normalize file object class value. 292 // 293 normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass); 294 295 // 296 // No FileObject support 297 // 298 if( normalizedFileClass == WdfFileObjectNotRequired ) { 299 *ppFxFileObject = NULL; 300 return STATUS_SUCCESS; 301 } 302 303 if( pWdmFileObject == NULL ) { 304 305 // 306 // Warn if an I/O request has NULL for the WDM PFILE_OBJECT 307 // 308 if ( pDevice->IsExclusive() && 309 normalizedFileClass == WdfFileObjectWdfCannotUseFsContexts ) { 310 // 311 // We allow a NULL file object iff the device is exclusive and 312 // we have to look up the WDFFILEOBJECT by PFILE_OBJECT value 313 // 314 DO_NOTHING(); 315 } 316 else if ( FxIsFileObjectOptional(FileObjectClass) ) { 317 // 318 // Driver told us that it's able to handle this case. 319 // 320 *ppFxFileObject = NULL; 321 return STATUS_SUCCESS; 322 } 323 else { 324 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 325 "NULL passed for PFILE_OBJECT when FileObject " 326 "support is requested in an I/O request"); 327 FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals()); 328 329 return STATUS_UNSUCCESSFUL; 330 } 331 } 332 333 // 334 // Depending on the drivers configuration, we can quickly 335 // get the FxFileObject* from FxContext, or FxContext2. 336 // 337 // Some drivers can not touch either of the FxContext(s), and 338 // in that case we must resort to a list or hashtable. 339 // 340 MxFileObject wdmFileObject(pWdmFileObject); 341 if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext ) { 342 pfo = (FxFileObject*)wdmFileObject.GetFsContext(); 343 } 344 else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext2 ) { 345 pfo = (FxFileObject*)wdmFileObject.GetFsContext2(); 346 } 347 else { 348 PLIST_ENTRY next; 349 FxFileObject* f; 350 KIRQL irql; 351 352 // 353 // Must look it up from the FxDevice->m_FileObjectListHead. 354 // 355 pfo = NULL; 356 357 pDevice->Lock(&irql); 358 359 next = pDevice->m_FileObjectListHead.Flink; 360 361 if(pWdmFileObject == NULL) { 362 // 363 // If the pWdmFileObject is NULL then we will pass the first entry 364 // in the list because the device must be exclusive and there 365 // can be only one fileobject in the list. 366 // 367 ASSERT(IsListEmpty(&pDevice->m_FileObjectListHead) == FALSE); 368 369 f = CONTAINING_RECORD(next, FxFileObject, m_Link); 370 pfo = f; 371 372 } else { 373 374 while( next != &pDevice->m_FileObjectListHead ) { 375 f = CONTAINING_RECORD(next, FxFileObject, m_Link); 376 377 if( f->m_FileObject.GetFileObject()== pWdmFileObject ) { 378 pfo = f; 379 break; 380 } 381 382 next = next->Flink; 383 } 384 } 385 386 387 388 389 390 391 392 393 394 395 if(pfo == NULL 396 && pDevice->IsExclusive() 397 && pDevice->GetMxDeviceObject()->GetDeviceType() == FILE_DEVICE_SERIAL_PORT 398 && !IsListEmpty(&pDevice->m_FileObjectListHead)) { 399 400 f = CONTAINING_RECORD(pDevice->m_FileObjectListHead.Flink, 401 FxFileObject, m_Link); 402 pfo = f; 403 404 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDEVICE, 405 "The PFILE_OBJECT 0x%p in this request (cleanup/close) " 406 "is different from the one specified in " 407 "create request 0x%p.This is bad!", pWdmFileObject, 408 ((f != NULL) ? f->m_FileObject.GetFileObject(): NULL)); 409 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDEVICE, 410 "Since this is a serial port device, framework is " 411 "using a workaround to allow this"); 412 } 413 414 pDevice->Unlock(irql); 415 } 416 417 // 418 // This can happen if a different PFILE_OBJECT is passed to an I/O 419 // request than was presented to IRP_MJ_CREATE 420 // 421 if (pfo == NULL && FxIsFileObjectOptional(FileObjectClass) == FALSE) { 422 423 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 424 "Could not locate WDFFILEOBJECT for " 425 "PFILE_OBJECT 0x%p",pWdmFileObject); 426 427 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 428 "Did a different PFILE_OBJECT get passed to the " 429 "request than was to IRP_MJ_CREATE?"); 430 431 432 433 434 435 436 437 438 439 440 if (FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) { 441 FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals()); 442 } 443 } 444 445 // 446 // We don't do an extra reference count since the file objects 447 // lifetime is controlled by the IoMgr. When the IRP_MJ_CLOSE 448 // occurs, the reference is released after the optional 449 // driver event callback. 450 // 451 452 *ppFxFileObject = pfo; 453 454 return STATUS_SUCCESS; 455 } 456 457 VOID 458 FxFileObject::DeleteFileObjectFromFailedCreate( 459 VOID 460 ) 461 { 462 KIRQL irql; 463 464 // 465 // Remove it from the list of FxFileObjects on the FxDevice 466 // 467 m_Device->Lock(&irql); 468 RemoveEntryList(&m_Link); 469 m_Device->Unlock(irql); 470 471 // Delete the file object 472 DeleteFromFailedCreate(); 473 } 474 475 _Must_inspect_result_ 476 NTSTATUS 477 FxFileObject::QueryInterface( 478 __in FxQueryInterfaceParams* Params 479 ) 480 /*++ 481 482 Routine Description: 483 This routine is used to return the pointer to the Object itself. 484 485 Arguments: 486 Params - query interface parameters. 487 488 Return Value: 489 NTSTATUS 490 491 --*/ 492 493 { 494 switch (Params->Type) { 495 case FX_TYPE_FILEOBJECT: 496 *Params->Object = (FxFileObject*) this; 497 break; 498 499 case FX_TYPE_IHASCALLBACKS: 500 *Params->Object = (IFxHasCallbacks*) this; 501 break; 502 503 default: 504 return FxNonPagedObject::QueryInterface(Params); // __super call 505 } 506 507 return STATUS_SUCCESS; 508 } 509 510 VOID 511 FxFileObject::GetConstraints( 512 __in WDF_EXECUTION_LEVEL* ExecutionLevel, 513 __in WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope 514 ) 515 /*++ 516 517 Routine Description: 518 This routine implements the GetConstraints IfxCallback. The caller gets the 519 ExecutionLevel and the SynchronizationScope of the FileObject. The FileObject's 520 SynchronizationScope and ExecutionLevel is strored in the FxPkgGeneral object. 521 522 Arguments: 523 ExecutionLevel - (opt) receives the execution level. 524 525 SynchronizationScope - (opt) receives the synchronization scope. 526 527 Return Value: 528 None 529 530 --*/ 531 532 { 533 // 534 // Get it from FxPkgGeneral which has the File attributes passed to it at device Creation time. 535 // 536 return GetDevice()->m_PkgGeneral->GetConstraintsHelper(ExecutionLevel, SynchronizationScope); 537 } 538 539 _Must_inspect_result_ 540 FxCallbackLock* 541 FxFileObject::GetCallbackLockPtr( 542 __deref_out_opt FxObject** LockObject 543 ) 544 /*++ 545 546 Routine Description: 547 This routine implements the GetCallbackLockPtr IfxCallback. The caller gets the 548 LockObject to be used before calling the driver callbacks. 549 550 Arguments: 551 LockObject - receives the lock object. 552 553 Return Value: 554 FxCallbackLock * 555 556 --*/ 557 558 { 559 // 560 // Get it from FxPkgGeneral which has the File attributes passed to it at device Creation time. 561 // 562 return GetDevice()->m_PkgGeneral->GetCallbackLockPtrHelper(LockObject); 563 } 564 565 566