Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

813 lines
20 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. FiltrCtx.c
  5. Abstract:
  6. This module provides three routines that allow filesystem filter drivers
  7. to associate state with FILE_OBJECTs -- for filesystems which support
  8. an extended FSRTL_COMMON_HEADER with FsContext.
  9. These routines depend on fields (FastMutext and FilterContexts)
  10. added at the end of FSRTL_COMMON_HEADER in NT 5.0.
  11. Filesystems should set FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS if
  12. these new fields are supported. They must also initialize the mutex
  13. and list head.
  14. Filter drivers must use a common header for the context they wish to
  15. associate with a file object:
  16. FSRTL_FILTER_CONTEXT:
  17. LIST_ENTRY Links;
  18. PVOID OwnerId;
  19. PVOID InstanceId;
  20. The OwnerId is a bit pattern unique to each filter driver
  21. (e.g. the device object).
  22. The InstanceId is used to specify a particular instance of the context
  23. data owned by a filter driver (e.g. the file object).
  24. Author:
  25. Dave Probert [DavePr] 30-May-1997
  26. Revision History:
  27. Neal Christiansen [nealch] 12-Jan-2001 Changed APIs to take
  28. PFSRTL_ADVANCED_FCB_HEADER
  29. structures instead of
  30. FileObjects.
  31. Neal Christiansen [nealch] 19-Jan-2001 Added mutex lock to FsRtlTeardownFilterContexts
  32. because you can get filters
  33. trying to delete at the same
  34. time the file system is trying
  35. to delete.
  36. Neal Christiansen [nealch] 25-Apr-2001 Added FileObject context routines
  37. Neal Christiansen [nealch] 25-Apr-2001 Marked all of this code as pageable
  38. --*/
  39. #include "FsRtlP.h"
  40. #define MySearchList(pHdr, Ptr) \
  41. for ( Ptr = (pHdr)->Flink; Ptr != (pHdr); Ptr = Ptr->Flink )
  42. //
  43. // The rest of the routines are not marked pageable so they can be called
  44. // during the paging path
  45. //
  46. NTKERNELAPI
  47. VOID
  48. FsRtlTeardownFilterContexts (
  49. IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader
  50. );
  51. #ifdef ALLOC_PRAGMA
  52. #pragma alloc_text(PAGE, FsRtlTeardownPerStreamContexts)
  53. #pragma alloc_text(PAGE, FsRtlTeardownFilterContexts)
  54. #pragma alloc_text(PAGE, FsRtlPTeardownPerFileObjectContexts)
  55. #endif
  56. //===========================================================================
  57. // Handles Stream Contexts
  58. //===========================================================================
  59. NTKERNELAPI
  60. NTSTATUS
  61. FsRtlInsertPerStreamContext (
  62. IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader,
  63. IN PFSRTL_PER_STREAM_CONTEXT Ptr
  64. )
  65. /*++
  66. Routine Description:
  67. This routine associates filter driver context with a stream.
  68. Arguments:
  69. AdvFcbHeader - Advanced FCB Header for stream of interest.
  70. Ptr - Pointer to the filter-specific context structure.
  71. The common header fields OwnerId and InstanceId should
  72. be filled in by the filter driver before calling.
  73. Return Value:
  74. STATUS_SUCCESS - operation succeeded.
  75. STATUS_INVALID_DEVICE_REQUEST - underlying filesystem does not support
  76. filter contexts.
  77. --*/
  78. {
  79. if (!AdvFcbHeader ||
  80. !FlagOn(AdvFcbHeader->Flags2,FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS))
  81. {
  82. return STATUS_INVALID_DEVICE_REQUEST;
  83. }
  84. ExAcquireFastMutex(AdvFcbHeader->FastMutex);
  85. InsertHeadList(&AdvFcbHeader->FilterContexts, &Ptr->Links);
  86. ExReleaseFastMutex(AdvFcbHeader->FastMutex);
  87. return STATUS_SUCCESS;
  88. }
  89. NTKERNELAPI
  90. PFSRTL_PER_STREAM_CONTEXT
  91. FsRtlLookupPerStreamContextInternal (
  92. IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader,
  93. IN PVOID OwnerId OPTIONAL,
  94. IN PVOID InstanceId OPTIONAL
  95. )
  96. /*++
  97. Routine Description:
  98. This routine lookups filter driver context associated with a stream.
  99. The macro FsRtlLookupFilterContext should be used instead of calling
  100. this routine directly. The macro optimizes for the common case
  101. of an empty list.
  102. Arguments:
  103. AdvFcbHeader - Advanced FCB Header for stream of interest.
  104. OwnerId - Used to identify context information belonging to a particular
  105. filter driver.
  106. InstanceId - Used to search for a particular instance of a filter driver
  107. context. If not provided, any of the contexts owned by the filter
  108. driver is returned.
  109. If neither the OwnerId nor the InstanceId is provided, any associated
  110. filter context will be returned.
  111. Return Value:
  112. A pointer to the filter context, or NULL if no match found.
  113. --*/
  114. {
  115. PFSRTL_PER_STREAM_CONTEXT ctx;
  116. PFSRTL_PER_STREAM_CONTEXT rtnCtx;
  117. PLIST_ENTRY list;
  118. ASSERT(AdvFcbHeader);
  119. ASSERT(FlagOn(AdvFcbHeader->Flags2,FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS));
  120. ExAcquireFastMutex(AdvFcbHeader->FastMutex);
  121. rtnCtx = NULL;
  122. //
  123. // Use different loops depending on whether we are comparing both Ids or not.
  124. //
  125. if ( ARGUMENT_PRESENT(InstanceId) ) {
  126. MySearchList (&AdvFcbHeader->FilterContexts, list) {
  127. ctx = CONTAINING_RECORD(list, FSRTL_PER_STREAM_CONTEXT, Links);
  128. if (ctx->OwnerId == OwnerId && ctx->InstanceId == InstanceId) {
  129. rtnCtx = ctx;
  130. break;
  131. }
  132. }
  133. } else if ( ARGUMENT_PRESENT(OwnerId) ) {
  134. MySearchList (&AdvFcbHeader->FilterContexts, list) {
  135. ctx = CONTAINING_RECORD(list, FSRTL_PER_STREAM_CONTEXT, Links);
  136. if (ctx->OwnerId == OwnerId) {
  137. rtnCtx = ctx;
  138. break;
  139. }
  140. }
  141. } else if (!IsListEmpty(&AdvFcbHeader->FilterContexts)) {
  142. rtnCtx = (PFSRTL_PER_STREAM_CONTEXT)AdvFcbHeader->FilterContexts.Flink;
  143. }
  144. ExReleaseFastMutex(AdvFcbHeader->FastMutex);
  145. return rtnCtx;
  146. }
  147. NTKERNELAPI
  148. PFSRTL_PER_STREAM_CONTEXT
  149. FsRtlRemovePerStreamContext (
  150. IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader,
  151. IN PVOID OwnerId OPTIONAL,
  152. IN PVOID InstanceId OPTIONAL
  153. )
  154. /*++
  155. Routine Description:
  156. This routine deletes filter driver context associated with a stream.
  157. FsRtlRemoveFilterContext functions identically to FsRtlLookupFilterContext,
  158. except that the returned context has been removed from the list.
  159. Arguments:
  160. AdvFcbHeader - Advanced FCB Header for stream of interest.
  161. OwnerId - Used to identify context information belonging to a particular
  162. filter driver.
  163. InstanceId - Used to search for a particular instance of a filter driver
  164. context. If not provided, any of the contexts owned by the filter
  165. driver is removed and returned.
  166. If neither the OwnerId nor the InstanceId is provided, any associated
  167. filter context will be removed and returned.
  168. Return Value:
  169. A pointer to the filter context, or NULL if no match found.
  170. --*/
  171. {
  172. PFSRTL_PER_STREAM_CONTEXT ctx;
  173. PFSRTL_PER_STREAM_CONTEXT rtnCtx;
  174. PLIST_ENTRY list;
  175. if (!AdvFcbHeader ||
  176. !FlagOn(AdvFcbHeader->Flags2,FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS))
  177. {
  178. return NULL;
  179. }
  180. ExAcquireFastMutex(AdvFcbHeader->FastMutex);
  181. rtnCtx = NULL;
  182. // Use different loops depending on whether we are comparing both Ids or not.
  183. if ( ARGUMENT_PRESENT(InstanceId) ) {
  184. MySearchList (&AdvFcbHeader->FilterContexts, list) {
  185. ctx = CONTAINING_RECORD(list, FSRTL_PER_STREAM_CONTEXT, Links);
  186. if (ctx->OwnerId == OwnerId && ctx->InstanceId == InstanceId) {
  187. rtnCtx = ctx;
  188. break;
  189. }
  190. }
  191. } else if ( ARGUMENT_PRESENT(OwnerId) ) {
  192. MySearchList (&AdvFcbHeader->FilterContexts, list) {
  193. ctx = CONTAINING_RECORD(list, FSRTL_PER_STREAM_CONTEXT, Links);
  194. if (ctx->OwnerId == OwnerId) {
  195. rtnCtx = ctx;
  196. break;
  197. }
  198. }
  199. } else if (!IsListEmpty(&AdvFcbHeader->FilterContexts)) {
  200. rtnCtx = (PFSRTL_PER_STREAM_CONTEXT)AdvFcbHeader->FilterContexts.Flink;
  201. }
  202. if (rtnCtx) {
  203. RemoveEntryList(&rtnCtx->Links); // remove the matched entry
  204. }
  205. ExReleaseFastMutex(AdvFcbHeader->FastMutex);
  206. return rtnCtx;
  207. }
  208. NTKERNELAPI
  209. VOID
  210. FsRtlTeardownPerStreamContexts (
  211. IN PFSRTL_ADVANCED_FCB_HEADER AdvFcbHeader
  212. )
  213. /*++
  214. Routine Description:
  215. This routine is called by filesystems to free the filter contexts
  216. associated with an FSRTL_COMMON_FCB_HEADER by calling the FreeCallback
  217. routine for each FilterContext.
  218. Arguments:
  219. FilterContexts - the address of the FilterContexts field within
  220. the FSRTL_COMMON_FCB_HEADER of the structure being torn down
  221. by the filesystem.
  222. Return Value:
  223. None.
  224. --*/
  225. {
  226. PFSRTL_PER_STREAM_CONTEXT ctx;
  227. PLIST_ENTRY ptr;
  228. BOOLEAN lockHeld;
  229. //
  230. // Acquire the lock because someone could be trying to free this
  231. // entry while we are trying to free it.
  232. //
  233. ExAcquireFastMutex( AdvFcbHeader->FastMutex );
  234. lockHeld = TRUE;
  235. try {
  236. while (!IsListEmpty( &AdvFcbHeader->FilterContexts )) {
  237. //
  238. // Unlink the top entry then release the lock. We must
  239. // release the lock before calling the use or their could
  240. // be potential locking order deadlocks.
  241. //
  242. ptr = RemoveHeadList( &AdvFcbHeader->FilterContexts );
  243. ExReleaseFastMutex(AdvFcbHeader->FastMutex);
  244. lockHeld = FALSE;
  245. //
  246. // Call filter to free this entry
  247. //
  248. ctx = CONTAINING_RECORD( ptr, FSRTL_PER_STREAM_CONTEXT, Links );
  249. ASSERT(ctx->FreeCallback);
  250. (*ctx->FreeCallback)( ctx );
  251. //
  252. // re-get the lock
  253. //
  254. ExAcquireFastMutex( AdvFcbHeader->FastMutex );
  255. lockHeld = TRUE;
  256. }
  257. } finally {
  258. if (lockHeld) {
  259. ExReleaseFastMutex( AdvFcbHeader->FastMutex );
  260. }
  261. }
  262. }
  263. //===========================================================================
  264. // Handles FileObject Contexts
  265. //===========================================================================
  266. //
  267. // Internal structure used to manage the Per FileObject Contexts.
  268. //
  269. typedef struct _PER_FILEOBJECT_CTXCTRL {
  270. //
  271. // This is a pointer to a Fast Mutex which may be used to
  272. // properly synchronize access to the FsRtl header. The
  273. // Fast Mutex must be nonpaged.
  274. //
  275. FAST_MUTEX FastMutex;
  276. //
  277. // This is a pointer to a list of context structures belonging to
  278. // filesystem filter drivers that are linked above the filesystem.
  279. // Each structure is headed by FSRTL_FILTER_CONTEXT.
  280. //
  281. LIST_ENTRY FilterContexts;
  282. } PER_FILEOBJECT_CTXCTRL, *PPER_FILEOBJECT_CTXCTRL;
  283. NTKERNELAPI
  284. NTSTATUS
  285. FsRtlInsertPerFileObjectContext (
  286. IN PFILE_OBJECT FileObject,
  287. IN PFSRTL_PER_FILEOBJECT_CONTEXT Ptr
  288. )
  289. /*++
  290. Routine Description:
  291. This routine associates a context with a file object.
  292. Arguments:
  293. FileObject - Specifies the file object of interest.
  294. Ptr - Pointer to the filter-specific context structure.
  295. The common header fields OwnerId and InstanceId should
  296. be filled in by the filter driver before calling.
  297. Return Value:
  298. STATUS_SUCCESS - operation succeeded.
  299. STATUS_INVALID_DEVICE_REQUEST - underlying filesystem does not support
  300. filter contexts.
  301. --*/
  302. {
  303. PPER_FILEOBJECT_CTXCTRL ctxCtrl;
  304. NTSTATUS status;
  305. //
  306. // Return if no file object
  307. //
  308. if (NULL == FileObject) {
  309. return STATUS_INVALID_PARAMETER;
  310. }
  311. if (!FsRtlSupportsPerFileObjectContexts(FileObject)) {
  312. return STATUS_INVALID_DEVICE_REQUEST;
  313. }
  314. //
  315. // Get the context control structure out of the file object extension
  316. //
  317. ctxCtrl = IoGetFileObjectFilterContext( FileObject );
  318. if (NULL == ctxCtrl) {
  319. //
  320. // There is not a control structure, allocate and initialize one
  321. //
  322. ctxCtrl = ExAllocatePoolWithTag( NonPagedPool,
  323. sizeof(PER_FILEOBJECT_CTXCTRL),
  324. 'XCOF' );
  325. if (NULL == ctxCtrl) {
  326. return STATUS_INSUFFICIENT_RESOURCES;
  327. }
  328. ExInitializeFastMutex( &ctxCtrl->FastMutex );
  329. InitializeListHead( &ctxCtrl->FilterContexts );
  330. //
  331. // Insert into the file object extension
  332. //
  333. status = IoChangeFileObjectFilterContext( FileObject,
  334. ctxCtrl,
  335. TRUE );
  336. if (!NT_SUCCESS(status)) {
  337. //
  338. // If this operation fails it is because someone else inserted the
  339. // entry at the same time. In this case free the memory we
  340. // allocated and re-get the current value.
  341. //
  342. ExFreePool( ctxCtrl );
  343. ctxCtrl = IoGetFileObjectFilterContext( FileObject );
  344. if (NULL == ctxCtrl) {
  345. //
  346. // This should never actually happen. If it does it means
  347. // someone allocated and then freed a context very quickly.
  348. //
  349. ASSERT(!"This operation should not have failed");
  350. return STATUS_UNSUCCESSFUL;
  351. }
  352. }
  353. }
  354. ExAcquireFastMutex( &ctxCtrl->FastMutex );
  355. InsertHeadList( &ctxCtrl->FilterContexts, &Ptr->Links );
  356. ExReleaseFastMutex( &ctxCtrl->FastMutex );
  357. return STATUS_SUCCESS;
  358. }
  359. NTKERNELAPI
  360. PFSRTL_PER_FILEOBJECT_CONTEXT
  361. FsRtlLookupPerFileObjectContext (
  362. IN PFILE_OBJECT FileObject,
  363. IN PVOID OwnerId OPTIONAL,
  364. IN PVOID InstanceId OPTIONAL
  365. )
  366. /*++
  367. Routine Description:
  368. This routine lookups contexts associated with a file object.
  369. Arguments:
  370. FileObject - Specifies the file object of interest.
  371. OwnerId - Used to identify context information belonging to a particular
  372. filter driver.
  373. InstanceId - Used to search for a particular instance of a filter driver
  374. context. If not provided, any of the contexts owned by the filter
  375. driver is returned.
  376. If neither the OwnerId nor the InstanceId is provided, any associated
  377. filter context will be returned.
  378. Return Value:
  379. A pointer to the filter context, or NULL if no match found.
  380. --*/
  381. {
  382. PPER_FILEOBJECT_CTXCTRL ctxCtrl;
  383. PFSRTL_PER_FILEOBJECT_CONTEXT ctx;
  384. PFSRTL_PER_FILEOBJECT_CONTEXT rtnCtx;
  385. PLIST_ENTRY list;
  386. //
  387. // Return if no FileObjecty
  388. //
  389. if (NULL == FileObject) {
  390. return NULL;
  391. }
  392. //
  393. // Get the context control structure out of the file object extension
  394. //
  395. ctxCtrl = IoGetFileObjectFilterContext( FileObject );
  396. if (NULL == ctxCtrl) {
  397. return NULL;
  398. }
  399. rtnCtx = NULL;
  400. ExAcquireFastMutex( &ctxCtrl->FastMutex );
  401. //
  402. // Use different loops depending on whether we are comparing both Ids or not.
  403. //
  404. if ( ARGUMENT_PRESENT(InstanceId) ) {
  405. MySearchList (&ctxCtrl->FilterContexts, list) {
  406. ctx = CONTAINING_RECORD(list, FSRTL_PER_FILEOBJECT_CONTEXT, Links);
  407. if ((ctx->OwnerId == OwnerId) && (ctx->InstanceId == InstanceId)) {
  408. rtnCtx = ctx;
  409. break;
  410. }
  411. }
  412. } else if ( ARGUMENT_PRESENT(OwnerId) ) {
  413. MySearchList (&ctxCtrl->FilterContexts, list) {
  414. ctx = CONTAINING_RECORD(list, FSRTL_PER_FILEOBJECT_CONTEXT, Links);
  415. if (ctx->OwnerId == OwnerId) {
  416. rtnCtx = ctx;
  417. break;
  418. }
  419. }
  420. } else if (!IsListEmpty(&ctxCtrl->FilterContexts)) {
  421. rtnCtx = (PFSRTL_PER_FILEOBJECT_CONTEXT) ctxCtrl->FilterContexts.Flink;
  422. }
  423. ExReleaseFastMutex(&ctxCtrl->FastMutex);
  424. return rtnCtx;
  425. }
  426. NTKERNELAPI
  427. PFSRTL_PER_FILEOBJECT_CONTEXT
  428. FsRtlRemovePerFileObjectContext (
  429. IN PFILE_OBJECT FileObject,
  430. IN PVOID OwnerId OPTIONAL,
  431. IN PVOID InstanceId OPTIONAL
  432. )
  433. /*++
  434. Routine Description:
  435. This routine deletes contexts associated with a file object
  436. Filter drivers must explicitly remove all context they associate with
  437. a file object (otherwise the underlying filesystem will BugCheck at close).
  438. This should be done at IRP_CLOSE time.
  439. FsRtlRemoveFilterContext functions identically to FsRtlLookupFilterContext,
  440. except that the returned context has been removed from the list.
  441. Arguments:
  442. FileObject - Specifies the file object of interest.
  443. OwnerId - Used to identify context information belonging to a particular
  444. filter driver.
  445. InstanceId - Used to search for a particular instance of a filter driver
  446. context. If not provided, any of the contexts owned by the filter
  447. driver is removed and returned.
  448. If neither the OwnerId nor the InstanceId is provided, any associated
  449. filter context will be removed and returned.
  450. Return Value:
  451. A pointer to the filter context, or NULL if no match found.
  452. --*/
  453. {
  454. PPER_FILEOBJECT_CTXCTRL ctxCtrl;
  455. PFSRTL_PER_FILEOBJECT_CONTEXT ctx;
  456. PFSRTL_PER_FILEOBJECT_CONTEXT rtnCtx;
  457. PLIST_ENTRY list;
  458. //
  459. // Return if no file object
  460. //
  461. if (NULL == FileObject) {
  462. return NULL;
  463. }
  464. //
  465. // Get the context control structure out of the file object extension
  466. //
  467. ctxCtrl = IoGetFileObjectFilterContext( FileObject );
  468. if (NULL == ctxCtrl) {
  469. return NULL;
  470. }
  471. rtnCtx = NULL;
  472. ExAcquireFastMutex( &ctxCtrl->FastMutex );
  473. // Use different loops depending on whether we are comparing both Ids or not.
  474. if ( ARGUMENT_PRESENT(InstanceId) ) {
  475. MySearchList (&ctxCtrl->FilterContexts, list) {
  476. ctx = CONTAINING_RECORD(list, FSRTL_PER_FILEOBJECT_CONTEXT, Links);
  477. if ((ctx->OwnerId == OwnerId) && (ctx->InstanceId == InstanceId)) {
  478. rtnCtx = ctx;
  479. break;
  480. }
  481. }
  482. } else if ( ARGUMENT_PRESENT(OwnerId) ) {
  483. MySearchList (&ctxCtrl->FilterContexts, list) {
  484. ctx = CONTAINING_RECORD(list, FSRTL_PER_FILEOBJECT_CONTEXT, Links);
  485. if (ctx->OwnerId == OwnerId) {
  486. rtnCtx = ctx;
  487. break;
  488. }
  489. }
  490. } else if (!IsListEmpty(&ctxCtrl->FilterContexts)) {
  491. rtnCtx = (PFSRTL_PER_FILEOBJECT_CONTEXT)ctxCtrl->FilterContexts.Flink;
  492. }
  493. if (rtnCtx) {
  494. RemoveEntryList(&rtnCtx->Links); // remove the matched entry
  495. }
  496. ExReleaseFastMutex( &ctxCtrl->FastMutex );
  497. return rtnCtx;
  498. }
  499. VOID
  500. FsRtlPTeardownPerFileObjectContexts (
  501. IN PFILE_OBJECT FileObject
  502. )
  503. /*++
  504. Routine Description:
  505. This routine is called by the IOManager when a fileObject is being
  506. deleted. This gives us a chance to delete our file object control
  507. structure.
  508. Arguments:
  509. FileObject - The fileObject being deleted
  510. Return Value:
  511. None.
  512. --*/
  513. {
  514. PPER_FILEOBJECT_CTXCTRL ctxCtrl;
  515. NTSTATUS status;
  516. ASSERT(FileObject != NULL);
  517. ctxCtrl = IoGetFileObjectFilterContext( FileObject );
  518. if (NULL != ctxCtrl) {
  519. status = IoChangeFileObjectFilterContext( FileObject,
  520. ctxCtrl,
  521. FALSE );
  522. ASSERT(STATUS_SUCCESS == status);
  523. ASSERT(IsListEmpty( &ctxCtrl->FilterContexts));
  524. ExFreePool( ctxCtrl );
  525. }
  526. }
  527. LOGICAL
  528. FsRtlIsPagingFile (
  529. IN PFILE_OBJECT FileObject
  530. )
  531. /*++
  532. Routine Description:
  533. This routine will return TRUE if the give file object is for a
  534. paging file. It returns FALSE otherwise
  535. Arguments:
  536. FileObject - The file object to test
  537. Return Value:
  538. TRUE - if paging file
  539. FALSE - if not
  540. --*/
  541. {
  542. return MmIsFileObjectAPagingFile( FileObject );
  543. }