缓存管理器

news/2024/7/20 14:22:31 标签: java, 运维, 内存管理
标 题: 【分享】缓存管理器
作 者: yaolibing
时 间: 2009-07-31,21:48:35
链 接: http://bbs.pediy.com/showthread.php?t=94762

简言之,就是会预先读入文件和延迟写入文件。当ReadFile时,会调用NtReadFile()系统调用,它会构造一个IRP下发到FSD,FSD会检查这个IRP看是不是可以缓存 的,是的话,如果还没有为此文件建立缓存的话,就会调用 CcInitializeCacheMap()函数建立缓存,它里面会调用内存管理器(VMM)函数建立一个节对象 。当用到时,会把这个节对象(和文件关联)映射到内核空间。如果IRP是可缓存 的,则调用CcCopyRead()函数进行从缓存中读入文件。

如果此文件还没有在内存中,则会产生页面错误,交给MmAccessFault()函数处理,它会调用IoPageRead()分配一个不缓存 的IRP,但是它会走FSD,不会调用缓存的函数,而是最终调用磁盘驱动进行真实的磁盘读写读入到内存。之后CcCopyRead()再不会产生错误了,会从缓存复制到用户Buffer中

NtReadFile (
    __in HANDLE FileHandle,
    __in_opt HANDLE Event,
    __in_opt PIO_APC_ROUTINE ApcRoutine,
    __in_opt PVOID ApcContext,
    __out PIO_STATUS_BLOCK IoStatusBlock,
    __out_bcount(Length) PVOID Buffer,
    __in ULONG Length,
    __in_opt PLARGE_INTEGER ByteOffset,
    __in_opt PULONG Key
    )

status = ObReferenceObjectByHandle( FileHandle,
                                        FILE_READ_DATA,
                                        IoFileObjectType,
                                        requestorMode,
                                        (PVOID *) &fileObject,
                                        NULL );//得到文件对象

deviceObject = IoGetRelatedDeviceObject( fileObject );//得到设备对象

// 如果文件已经有缓存了,直接调用

if (fileObject->PrivateCacheMap) {

            IO_STATUS_BLOCK localIoStatus;

            ASSERT(fastIoDispatch && fastIoDispatch->FastIoRead);

            //
            // Negative file offsets are illegal.
            //

            if (fileOffset.HighPart < 0) {
                if (eventObject) {
                    ObDereferenceObject( eventObject );
                }
                IopReleaseFileObjectLock( fileObject );
                ObDereferenceObject( fileObject );
                return STATUS_INVALID_PARAMETER;
            }

            if (fastIoDispatch->FastIoRead( fileObject,
                                            &fileOffset,
                                            Length,
                                            TRUE,
                                            keyValue,
                                            Buffer,
                                            &localIoStatus,
                                            deviceObject )

否则的话还要分配IRP,下发到文件系统驱动 ,(注意有三种处理用户Buffer的方法,因为有可能FSD驱动不是在本用户进程的地址空间中执行的,则访问Buffer(尽管虚拟地址相同,但是一般会被映射到不同的物理地址),所以要做如下处理Buffer。

1,是调用irp->AssociatedIrp.SystemBuffer =
                    ExAllocatePoolWithQuota( NonPagedPoolCacheAligned, Length );在非分页内存中分配内存,因为都是在内核空间,所以就算另一个进程也能访问。

2,是调用mdl = IoAllocateMdl( Buffer, Length, FALSE, TRUE, irp );分配一个内存描述符,再调用 MmProbeAndLockPages( mdl, requestorMode, IoWriteAccess );
把此Buffer所在的物理页锁定在内存中,防止换出去。

3,直接就是那个 irp->Flags = 0; irp->UserBuffer = Buffer;

调用 这个IopSynchronousServiceTail()函数下发到FSD 

注意先是IopfCallDriver()调用fltMgr.sys驱动的分派函数,最后它也调用IofCallDriver()函数下发IRP到下层驱动(既ntfs.sys的NtfsFsdRead()函数)

NTSTATUS
NtfsFsdRead (
    IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
    IN PIRP Irp
    )
最后调用NtfsCommonRead()这个函数里面会做好多判断,之后会建立该文件的Cache

if (FileObject->PrivateCacheMap == NULL) {

                    DebugTrace( 0, Dbg, ("Initialize cache mapping.\n") );

                    //
                    // Now initialize the cache map.
                    //
                    // Make sure we are serialized with the FileSizes, and
                    // will remove this condition if we abort.
                    //

                    if (!DoingIoAtEof) {
                        FsRtlLockFsRtlHeader( Header );
                        IrpContext->FcbWithPagingExclusive = (PFCB)Scb;
                    }

CcInitializeCacheMap( FileObject,
                                          (PCC_FILE_SIZES)&Header->AllocationSize,
                                          FALSE,
                                          &NtfsData.CacheManagerCallbacks,
                                          Scb );

它里面会分配SharedCacheMap = ExAllocatePoolWithTag( NonPagedPool, sizeof(SHARED_CACHE_MAP), 'cScC' );

初始化这个结构,最后调用内存管理器(VMM) 函数SharedCacheMap->Status = MmCreateSection( &SharedCacheMap->Section,
                                                      SECTION_MAP_READ
                                                        | SECTION_MAP_WRITE
                                                        | SECTION_QUERY,
                                                      NULL,
                                                      &LocalSizes.AllocationSize,
                                                      PAGE_READWRITE,
                                                      SEC_COMMIT,
                                                      NULL,
                                                      FileObject );
建立一个共享节对象

之后FSD调用 if (!CcCopyRead( FileObject,
                                     (PLARGE_INTEGER)&StartingVbo,
                                     (ULONG)ByteCount,
                                     Wait,
                                     SystemBuffer,
                                     &Irp->IoStatus ))进行从缓存中读入数据

如果缓存没有这个要读文件的页面,则会产生页面异常,最终进入MmAccessFault()处理,它会调用IoPageRead()分配一个IRP_PAGING_IO | IRP _NOCACHE (没有缓存的IRP)再次调用IoCallDriver调用FSD的函数,这里和上面一样,同样进入FSD的NtfsFsdRead()-》NtfsNonCachedIo()进行没有缓存的IRP请求。-》NtfsSingleAsync()它里面先调用IoSetCompletionRoutine()设置一个FSD回调函数,然后调用    IoCallDriver( DeviceObject, Irp );调用1,volsnap!VolSnapRead------->2,ftdisk!FtDiskReadWrite------>3,PartMgr!PmReadWrite------->4,CLASSPNP!ClassReadWrite----->5,SCSIPORT!ScsiPortGlobalDispatch()等等会进行真正磁盘读写文件内容

当读写磁盘完成了后会产生中断之后进入KiDispatchInterrupt()

ScsiPortCompletionDpc()一层一层的调用SCSIPORT!SpCompleteRequest()完成回调函数,最后会调用到FSD先前建立的Ntfs!NtfsSingleSyncCompletionRoutine()也算是完成了磁盘读写。

转载于:https://www.cnblogs.com/bugchecker/archive/2012/04/27/3041596.html


http://www.niftyadmin.cn/n/537506.html

相关文章

pep8 python 编码规范_我的 Python 编码规范

版权声明&#xff1a;本文为CSDN博主「天元浪子」 原文链接&#xff1a;https://blog.csdn.net/xufive/article/details/84957425python 文件的组成为了便于描述&#xff0c;先上一个 demo#!/usr/bin/env python# -*- coding: utf-8 -*-"""通常这里是关于本文档…

MySQL使用float类型精确查询结果为空

在MYSQL中&#xff0c;字段类型为float的字段&#xff0c;如果不指定float的长度和小数点位数&#xff0c;要根据float字段的值精确查找&#xff0c;结果会是空&#xff1b; 原因是在mysql中&#xff0c;float是浮点数&#xff0c;Mysql存储的时候是近似值&#xff0c;所以用精…

汉迪机器人_碧桂园财报:手握2683亿现金,布局机器人和农业探索第二增长曲线...

撰写 | 菲兹编辑 | 森淼3月27日&#xff0c;碧桂园(http://02007.HK)披露2019年年报并召开业绩发布会。报告期内&#xff0c;碧桂园收入、毛利润、净利润等核心盈利指标均表现优异。其中&#xff0c;总营业收入同比增长28.2%至4859.1亿元&#xff1b;毛利润同比增长23.6%至1266…

双曲线和直线联立公式_高中数学:求双曲线离心率的取值范围

求双曲线离心率的取值范围涉及到解析几何、平面几何、代数等多个知识点&#xff0c;解题关键是挖掘题中的隐含条件&#xff0c;构造不等式&#xff0c;下面举例说明。一、利用双曲线性质例1、设点P在双曲线的左支上&#xff0c;双曲线两焦点为&#xff0c;已知是点P到左准线的距…

.net开发_2019,.Net开发者的高光时刻

随着微软发布的一系列关于Windows、.net和C#的公告&#xff0c;.Net开发者将在2019年&#xff0c;迎来自己的高光时刻&#xff0c;毕竟“世界上只有少数几种语言是多功能的&#xff0c;而没有一个像C#那样干净整洁。”一、现在学C#还有多少意义&#xff1f;2019年&#xff0c;C…

王济川logistic回归模型_Logistic回归——回归模型评价

在模型创建完成后&#xff0c;我们需要考虑模型的适当性&#xff0c;如模型的拟合优度&#xff0c;预测准确性和模型的检验。1拟合优度评价我们在对模型的拟合优度进行评价时&#xff0c;需要判断模型的预测值与对应的观测值是否具有较高的一致性&#xff0c;如果匹配性较好&am…

java url路径包含中文_Java面试笔试必考题总结

1.full GC触发的条件触发Full GC执行的情况有如下五种&#xff1a;<1>. 旧生代(老年代)空间不足旧生代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象&#xff0c;当执行Full GC后空间仍然不足&#xff0c;则抛出如下错误&#xff1a;java.lang.Ou…

原生JS实现点击一个按钮显示一个div,再点击按钮div隐藏,或点击除div外其它空白处div隐藏...

<!DOCTYPE html> <html style"font-size: 24px"> <head><title>js点击按钮显示再点击空白地方隐藏</title><style type"text/css">#div {border: 1px solid red;display: flex;align-items: center;justify-content: …