注一:
File system recognizer 文件系统识别器(下文简称为recognizer)
File system 文件系统 (下文简称为fs)
File system filter 文件系统过滤器(下文简称为filter)
文件系统识别器是一个标准的NT内核模式驱动程序;它只实现一项功能:检查物理介质设备,如果它能够识别存储介质的格式便加载相应的文件系统驱动程序,利用它主要是为节约系统内存,文件系统驱动程序没用到时为什么让他在内存中呢?
文件系统过滤驱动的一般处理流程(参照sfilter):
DriverEntry
||
||初始化dispatch表中的IRP_MJ_FILE_SYSTEM_CONTROL
||routine
||
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = SfFsControl ...
||
||注册一个SfFsNotification;当文件系统或文件系统识别器
||registers or unregisters时被调用
||
IoRegisterFsRegistrationChange(DriverObject, SfFsNotification)
||
||
//
SfFsNotification(PDEVICE_OBJECT DeviceObject, BOOLEAN FsActive)
||
|| FsActive
TRUE <----------//------------> FALSE
|| ||
|| ||
IoAttachDeviceToDeviceStack IoDetachDevice
||
||
/-------//------->Attach to (Filesystem)-----------------/IRP_MJ_FILE_SYSTEM_CONTROL
| |
| |MN:IRP_MN_MOUNT_VOLUME
/---------------->Attach to (recognizer) |你就尽管Mount,只要fs
|| |处理状态为STATUS_SUCCESS;
||MJ:IRP_MJ_FILE_SYSTEM_CONTROL |fs中关于卷的Mount处理
// |参见FatMountVolume函数
SfFsControl (PDEVICE_OBJECT DeviceObject, PIRP Irp) |
|| //filter其他处理参见sfilter
||MN:
/--------------//-----------------------------/
| |
|IRP_MN_MOUNT_VOLUME |
| |
filter等待recognizer处理完成
|| |
|| |
/-----//-->STATUS_FS_DRIVER_REQUIRED(1)---|/ |
| ||
/-------->STATUS_UNRECOGNIZED_VOLUME(2)---||
|| |
|| |
// |
不论结果是哪一个,filter什么动作也没有;
但IO管理器收到recognizer处理结果后,处理各不相同:
(1)表示recognizer认识这个卷,但对应的fs还没启动 |
(2)表示recognizer不认识这个卷,对应的fs不能处理 ||
如果是第一种情况I/O管理器就会向这个设备发送---------------||IRP_MN_LOAD_FILE_SYSTEM
||
||原来我们一直挂接在recognizer上的
//
IoDetachDevice(recognizer)
||
||
wait recognizer load fs status
||
||
Other status<-----------//----------->STATUS_SUCCESS
||
||recognizer加载对应的fs失败
||只好还挂到recognizer上
||
//
IoAttachDeviceToDeviceStack(recognizer)
注二:IoRegisterFsRegistrationChange函数
在winxp,win2003下会对已加载的文件系统重新枚举一遍
而nt4.0和win2000下则不会,具体原因代码见...
(留意一下IopNotifyAlreadyRegisteredFileSystems的作用和实现)
//win2000
NTSTATUS
IoRegisterFsRegistrationChange(
IN PDRIVER_OBJECT DriverObject,
IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine
)
/*++
Routine Description:
This routine registers the specified driver's notification routine to be
invoked whenever a file system registers or unregisters itself as an active
file system in the system.
Arguments:
DriverObject - Pointer to the driver object for the driver.
DriverNotificationRoutine - Address of routine to invoke when a file system
registers or unregisters itself.
Return Value:
The return status is the final value of the function.
--*/
{
PNOTIFICATION_PACKET nPacket;
PAGED_CODE();
//
// Begin by attempting to allocate storage for the shutdown packet. If
// one cannot be allocated, simply return an appropriate error.
//
nPacket = ExAllocatePoolWithTag( PagedPool,
sizeof( NOTIFICATION_PACKET ),
'sFoI' );
if (!nPacket) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize the notification packet and insert it onto the tail of the
// list.
//
nPacket->DriverObject = DriverObject;
nPacket->NotificationRoutine = DriverNotificationRoutine;
ExAcquireResourceExclusive( &IopDatabaseResource, TRUE );
InsertTailList( &IopFsNotifyChangeQueueHead, &nPacket->ListEntry );
ExReleaseResource( &IopDatabaseResource );
//
// Increment the number of reasons that this driver cannot be unloaded.
//
ObReferenceObject( DriverObject );
return STATUS_SUCCESS;
}
//win2003
NTSTATUS
IoRegisterFsRegistrationChange(
IN PDRIVER_OBJECT DriverObject,
IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine
)
/*++
Routine Description:
This routine registers the specified driver's notification routine to be
invoked whenever a file system registers or unregisters itself as an active
file system in the system.
Arguments:
DriverObject - Pointer to the driver object for the driver.
DriverNotificationRoutine - Address of routine to invoke when a file system
registers or unregisters itself.
Return Value:
STATUS_DEVICE_ALREADY_ATTACHED -
Indicates that the caller has already registered
last with the same driver object & driver notification
STATUS_INSUFFICIENT_RESOURCES
STATUS_SUCCESS
--*/
{
PNOTIFICATION_PACKET nPacket;
PAGED_CODE();
ExAcquireResourceExclusiveLite( &IopDatabaseResource, TRUE );
if (!IsListEmpty( &IopFsNotifyChangeQueueHead )) {
//
// Retrieve entry at tail of list
//
nPacket = CONTAINING_RECORD( IopFsNotifyChangeQueueHead.Blink, NOTIFICATION_PACKET, ListEntry );
if ((nPacket->DriverObject == DriverObject) &&
(nPacket->NotificationRoutine == DriverNotificationRoutine)) {
ExReleaseResourceLite( &IopDatabaseResource);
return STATUS_DEVICE_ALREADY_ATTACHED;
}
}
//
// Begin by attempting to allocate storage for the shutdown packet. If
// one cannot be allocated, simply return an appropriate error.
//
nPacket = ExAllocatePoolWithTag( PagedPool|POOL_COLD_ALLOCATION,
sizeof( NOTIFICATION_PACKET ),
'sFoI' );
if (!nPacket) {
ExReleaseResourceLite( &IopDatabaseResource );
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize the notification packet and insert it onto the tail of the
// list.
//
nPacket->DriverObject = DriverObject;
nPacket->NotificationRoutine = DriverNotificationRoutine;
InsertTailList( &IopFsNotifyChangeQueueHead, &nPacket->ListEntry );
IopNotifyAlreadyRegisteredFileSystems(&IopNetworkFileSystemQueueHead, DriverNotificationRoutine, FALSE);
IopNotifyAlreadyRegisteredFileSystems(&IopCdRomFileSystemQueueHead, DriverNotificationRoutine, TRUE);
IopNotifyAlreadyRegisteredFileSystems(&IopDiskFileSystemQueueHead, DriverNotificationRoutine, TRUE);
IopNotifyAlreadyRegisteredFileSystems(&IopTapeFileSystemQueueHead, DriverNotificationRoutine, TRUE);
//
// Notify this driver about all already notified filesystems
// registered as an active file system of some type.
//
ExReleaseResourceLite( &IopDatabaseResource );
//
// Increment the number of reasons that this driver cannot be unloaded.
//
ObReferenceObject( DriverObject );
return STATUS_SUCCESS;
}
VOID
IopNotifyAlreadyRegisteredFileSystems(
IN PLIST_ENTRY ListHead,
IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine,
IN BOOLEAN SkipRaw
)
/*++
Routine Description:
This routine calls the driver notification routine for filesystems
that have already been registered at the time of the call.
Arguments:
ListHead - Pointer to the filesystem registration list head.
DriverNotificationRoutine - Pointer to the routine that has to be called.
Return Value:
None.
--*/
{
PLIST_ENTRY entry;
PDEVICE_OBJECT fsDeviceObject;
entry = ListHead->Flink;
while (entry != ListHead) {
//
// Skip raw filesystem notification
//
if ((entry->Flink == ListHead) && (SkipRaw)) {
break;
}
fsDeviceObject = CONTAINING_RECORD( entry, DEVICE_OBJECT, Queue.ListEntry );
entry = entry->Flink;
DriverNotificationRoutine( fsDeviceObject, TRUE );
}
}
注三:IoRegisterFileSystem函数
是文件系统在DriverEntry中最后要调用的函数,主要是向IO管理器中注册一下,以后有卷需要Mount时通知我...
VOID
IoRegisterFileSystem(
IN OUT PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This routine inserts the device object for the file system which the device
object represents into the list of file systems in the system.
Arguments:
DeviceObject - Pointer to device object for the file system.
Return Value:
None.
--*/
{
PNOTIFICATION_PACKET nPacket;
PLIST_ENTRY entry;
PAGED_CODE();
//
// Allocate the I/O database resource for a write operation.
//
(VOID) ExAcquireResourceExclusive( &IopDatabaseResource, TRUE );
//
// Insert the device object into the appropriate file system queue based on
// the driver type in the device object. Notice that if the device type is
// unrecognized, the file system is simply not registered.
//
if (DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) {
InsertHeadList( &IopNetworkFileSystemQueueHead,
&DeviceObject->Queue.ListEntry );
} else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) {
InsertHeadList( &IopCdRomFileSystemQueueHead,
&DeviceObject->Queue.ListEntry );
} else if (DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
InsertHeadList( &IopDiskFileSystemQueueHead,
&DeviceObject->Queue.ListEntry );
} else if (DeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM) {
InsertHeadList( &IopTapeFileSystemQueueHead,
&DeviceObject->Queue.ListEntry );
}
//
// Ensure that this file system's device is operable.
//
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
//
// Notify all of the registered drivers that this file system has been
// registered as an active file system of some type.
//
//PS:看到了吧,如果你的filter调用了IoRegisterFsRegistrationChange,
//文件系统注册时就要通过你啦,TRUE-Load/FALSE-unload.
entry = IopFsNotifyChangeQueueHead.Flink;
while (entry != &IopFsNotifyChangeQueueHead) {
nPacket = CONTAINING_RECORD( entry, NOTIFICATION_PACKET, ListEntry );
entry = entry->Flink;
nPacket->NotificationRoutine( DeviceObject, TRUE );
}
//
// Release the I/O database resource.
//
ExReleaseResource( &IopDatabaseResource );
//
// Increment the number of reasons that this driver cannot be unloaded.
//
ExInterlockedAddUlong( &DeviceObject->ReferenceCount, 1, &IopDatabaseLock );
}
注四:
有兴趣的话可以看看文件识别器,IO管理器,文件系统的实现.