Thursday, February 11, 2010

Filter Manager Concepts: Part 2 – FLT_VOLUME

Right below the FLTP_FRAME in the hierarchy of filter manager objects is the FLT_VOLUME. It is a structure that describes the attachment of the FLTP_FRAME to a volume:

Volumes

So, as you can see, each frame is pretty much a list of volumes. These volumes are in fact DEVICE_OBJECTs with which FltMgr attaches to each IO stack in the system. So let’s see what they look like in the debugger:

0: kd> !fltkd.volumes
Volume List: fffff98001218bf0 "Frame 0"
   FLT_VOLUME: fffff980012f6810 "\Device\Mup"
      FLT_INSTANCE: fffff9800133abb0 "FileInfo" "45000"
   FLT_VOLUME: fffff980016b6800 "\Device\HarddiskVolume1"
      FLT_INSTANCE: fffff9800822c4c0 "luafv" "135000"
      FLT_INSTANCE: fffff980017c6bb0 "FileInfo" "45000"
   FLT_VOLUME: fffff980045ec800 "\Device\HarddiskVolume2"
      FLT_INSTANCE: fffff9800450cbb0 "FileInfo" "45000"
   FLT_VOLUME: fffff980064d2820 "\Device\CdRom0"
      FLT_INSTANCE: fffff98006514bb0 "FileInfo" "45000"


Let’s look in more detail at the volume for \Device\HarddiskVolume1:



0: kd> !fltkd.volume fffff980016b6800
FLT_VOLUME: fffff980016b6800 "\Device\HarddiskVolume1"
   FLT_OBJECT: fffff980016b6800  [04000000] Volume
      RundownRef               : 0x000000000000008c (70)
      PointerCount             : 0x00000001
      PrimaryLink              : [fffff98003ce6810-fffff980012f6820]
   Frame                    : fffff98001218ac0 "Frame 0"
   Flags                    : [00000064] SetupNotifyCalled EnableNameCaching FilterAttached
   FileSystemType           : [00000002] FLT_FSTYPE_NTFS
   VolumeLink               : [fffff98003ce6810-fffff980012f6820]
   DeviceObject             : fffffa8003678690
   DiskDeviceObject         : fffffa80036015f0
   FrameZeroVolume          : fffff980016b6800
   VolumeInNextFrame        : 0000000000000000
   Guid                     : ""
   CDODeviceName            : "\Ntfs"
   CDODriverName            : "\FileSystem\Ntfs"
   TargetedOpenCount        : 67
   Callbacks                : (fffff980016b6910)
   ContextLock              : (fffff980016b6cf8)
   VolumeContexts           : (fffff980016b6d00)  Count=0
   StreamListCtrls          : (fffff980016b6d08)  rCount=2378
   FileListCtrls            : (fffff980016b6d88)  rCount=0
   NameCacheCtrl            : (fffff980016b6e08)
   InstanceList             : (fffff980016b6890)
      FLT_INSTANCE: fffff9800822c4c0 "luafv" "135000"
      FLT_INSTANCE: fffff980017c6bb0 "FileInfo" "45000"


This is somewhat more interesting than a frame. It obviously has a reference to the frame it’s in, but it also has pointers to the DEVICE_OBJECT it’s associated with as well as the DEVICE_OBJECT for the disk, it knows what file system is at the bottom of the stack and it has a bunch of other information we will address later, once we’re done going through all the concepts. 



That last thing I’d like to show you is how to get to the FLT_VOLUME structure from one of FltMgr’s DEVICE_OBJECTs (this comes up quite a lot for some reason):



0: kd> !devstack fffffa8003678690
  !DevObj   !DrvObj            !DevExt   ObjectName
> fffffa8003678690  \FileSystem\FltMgr fffffa80036787e0
  fffffa800367d030  \FileSystem\Ntfs   fffffa800367d180
0: kd> dt fffffa80036787e0 fltmgr!_VOLUME_DEVICE_EXTENSION
   +0x000 Type             : _FLT_TYPE
   +0x008 AttachedToDeviceObject : 0xfffffa80`0367d030 _DEVICE_OBJECT
   +0x010 Frame            : 0xfffff980`01218ac0 _FLTP_FRAME
   +0x018 VolumeAccessLock : _FAST_MUTEX
   +0x050 Volume           : 0xfffff980`016b6800 _FLT_VOLUME


Please note that FltMgr attaches to CDOs as well as VDOs so not all FltMgr’s devices have a DeviceExtension of type fltmgr!_VOLUME_DEVICE_EXTENSION.

Filter Manager Concepts: Part 1 – FLTP_FRAME

Filter Manager's only purpose is to simplify writing file system filters and sometimes it does this by abstracting some of the things that a filter needs to deal with. However, in my experience a good understanding of the mechanisms behind any abstraction is worth having as there usually are some corner cases where abstractions are either broken or unnatural. Also, even though some of the FltMgr's internal structures are not accessible to developers, they might still show up in debugging. So, without further ado, let's go through them one by one:

 

The FLTP_FRAME structure

A FRAME is a structure that describes a range of altitudes in FltMgr, across all volumes. If there are no legacy filters present, there is only one frame, "Frame 0". If there are some legacy filters present on the system (attached on top of Frame 0), FltMgr might create more frames. They aren’t very interesting for the minifilter writer but still one can see them in the debugger (this is the output on one of my test machines):

 

0: kd> !fltkd.frames
Frame List: fffff88001ab7380
   FLTP_FRAME: fffff98020692ac0 "Frame 3" "361111111.1 to 421111111.1"
   FLTP_FRAME: fffff9801e04eac0 "Frame 2" "271111111.1 to 361111111.1"
   FLTP_FRAME: fffff9801f7acac0 "Frame 1" "41111111.1 to 271111111.1"
   FLTP_FRAME: fffff98001218ac0 "Frame 0" "0 to 41111111.1"
      FLT_FILTER: fffff980163fe7b0 "PassThrough" "370130"
         FLT_INSTANCE: fffff9801629a6b0 "PassThrough Instance" "370130"
      FLT_FILTER: fffff980082026a0 "luafv" "135000"
         FLT_INSTANCE: fffff980082f84c0 "luafv" "135000"
      FLT_FILTER: fffff980012d2b40 "FileInfo" "45000"
         FLT_INSTANCE: fffff980012e2bb0 "FileInfo" "45000"
         FLT_INSTANCE: fffff9801ec96bb0 "FileInfo" "45000"


 



One important thing to note is that the frame is a logical unit that has no references to any objects outside itself. Which means that a frame is not aware of the existence of other frames in the system and of any objects in those frames and as such some of the functions that enumerate objects will only show objects inside a certain frame (for example FltGetLowerInstance, FltGetTopInstance, FltGetVolumeInstanceFromName and so on; these functions usually get a parameter that references some other object from which the function can figure out which frame it should look at). This can get in the way when trying to use more than one minifilter for some particular application as it is possible that each minifilter is in a different frame and this might need to be dealt with.



 



Also, a frame attaches to ALL mounted volumes in the system, which can lead to pretty strange layering:



 



clip_image001



 



As you can see, on \Device\HarddiskVolume1 there is only Frame 2 on top of Frame 1 on top of Frame 0. However, on \Device\CdRom0 there is Frame 2 on top of Legacy Filter 2 on top of Frame 1 on top of Frame 0. Currently frames can be created only when a minifilter is registering so it is possible that there are two legacy filters directly on top of one another without a frame between them, but I can't think of any case where that would cause problems.



 



I guess that's it for tonight. Frames aren't particularly interesting but I had to start somewhere. I also needed some entries on the blog so I can play with formatting :).

Ello, ello… What's all this, then !?

The main focus of this blog is development of file system filters. I’m not sure how many people are interested in this particular subject, but for those brave few souls things are, in my opinion, unnecessarily complicated. The documentation is rather minimal, the semantics are counterintuitive and even the basic concepts aren’t very clear (nor are they basic for that matter). I’ve experienced this first hand when I started working in this field and I’m sure my experience was rather the norm than the exception.

I’d like to use this blog to talk about things that I find interesting in this space, things that I found or still find puzzling and all sorts of other things are more or less related to my day to day experience writing and debugging file system filters. I’ll start by going over a couple of general concepts and some frequently asked questions and then I’ll try to move on to other things based on the feedback I get from you. So please feel free to send me suggestions and questions and I’ll try to come up with new material based on that.

One last thing to note is that this blog is not intended to replace or extend documentation and things that are not specifically mentioned in the documentation are, as always, subject to change without notice. Of course, I’ll do my best to make sure that the things I write are accurate, but if they do change in the future it’s unlikely that I’ll revisit older posts. So please don’t treat these entries here as anything more than a best effort on my part. The documentation always has the final say.