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
FxFileObject(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in MdFileObject pWdmFileObject,__in FxDevice * pDevice)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
~FxFileObject()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
_CreateFileObject(__in FxDevice * pDevice,__in MdIrp Irp,__in WDF_FILEOBJECT_CLASS FileObjectClass,__in_opt PWDF_OBJECT_ATTRIBUTES pObjectAttributes,__in_opt MdFileObject pWdmFileObject,__deref_out_opt FxFileObject ** pFileObject)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
_DestroyFileObject(__in FxDevice * pDevice,__in WDF_FILEOBJECT_CLASS FileObjectClass,__in_opt MdFileObject pWdmFileObject)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
_GetFileObjectFromWdm(__in FxDevice * pDevice,__in WDF_FILEOBJECT_CLASS FileObjectClass,__in_opt MdFileObject pWdmFileObject,__deref_out_opt FxFileObject ** ppFxFileObject)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
DeleteFileObjectFromFailedCreate(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
QueryInterface(__in FxQueryInterfaceParams * Params)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
GetConstraints(__in WDF_EXECUTION_LEVEL * ExecutionLevel,__in WDF_SYNCHRONIZATION_SCOPE * SynchronizationScope)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*
GetCallbackLockPtr(__deref_out_opt FxObject ** LockObject)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