文件驱动,绑定指定卷

 
我们平时看sfilter的时候,发现它一方面面面俱到,一方面弄乱了我们的脑子。特别是绑定卷的那一部分,到底是怎么实现的,总觉得七拐八拐,拐弯太多。能不能写一个比较简单的绑定函数?比如我指定只要过滤c盘,那么我只要绑定c盘就够了。我试着写了一个,本文介绍我的这部分代码。我定义了一个函数:
BOOLEAN Attach2C_Volume(PUNICODE_STRING nameString)
nameString指定了要绑定的卷名。如果要绑定c盘,则nameString应是://DosDevices//C://
        InitializeObjectAttributes( &objectAttributes, &nameString, 
                OBJ_CASE_INSENSITIVE, NULL, NULL );
        ntStatus = ZwCreateFile( &ntFileHandle, SYNCHRONIZE|FILE_ANY_ACCESS, 
                &objectAttributes, &ioStatus, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, 
                FILE_OPEN, 
                FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, 
                NULL, 0 );
 
        if( !NT_SUCCESS( ntStatus ) ) 
        {
                //DbgPrint(("Filemon: Could not open drive %c: /n", 'C'+0));
                return FALSE;
        }

        // Got the file handle, so now look-up the file-object it refers to
        //
        ntStatus = ObReferenceObjectByHandle( ntFileHandle, FILE_READ_DATA, 
                NULL, KernelMode, &fileObject, NULL );
        if( !NT_SUCCESS( ntStatus )) {
 
                //DbgPrint(("Filemon: Could not get fileobject from handle: %c/n", 'C'));
                ZwClose( ntFileHandle );
                return FALSE;
        }
 
        // 
        // Next, find out what device is associated with the file object by getting its related
        // device object
        //
        fileSysDevice = IoGetRelatedDeviceObject( fileObject );
 
        if( ! fileSysDevice ) {
 
                //DbgPrint(("Filemon: Could not get related device object: %c/n", 'A'+Drive ));
                ObDereferenceObject( fileObject );
                ZwClose( ntFileHandle );
                return FALSE;
        }
      上面代码的作用是打开卷设备,保存在fileSysDevice中。我们来一步步地看它是怎么做的。我们知道,在应用层里面,CreateFile函数的作用不仅可以打开一个File,还可以打开管道,邮件槽,磁盘。这里的ZwCreateFile就是CreateFile在内核的实现,现在调用它打开磁盘并取得句柄ntFileHandle,通过这个句柄可以找到它所对应的文件对象。形象地来说明句柄和文件对象的关系吧,文件对象就象一只古董瓷瓶,珍贵易碎,而句柄则是一只细心包裹着这只瓷瓶的皮箱,保护着它。我们在介绍古董瓷瓶的时候,只是让别人知道,它正放在箱子里面,有图片在此请看云云。
好,找到文件对象的方法是ObReferenceObjectByHandle,调用它就可以了。继续调用IoGetRelatedDeviceObject,这个函数可以让你进一步通过文件对象获得设备对象,也就是C盘的设备对象,正是我们绑定的时候要用到的。对上面的这一个过程,请你记住就行了,不必特别的研究,他们之间的关系都是一顺的,好像通过爷爷找孙子一样,有既定的脉络关系。接下来:
    ntStatus = IoCreateDevice( gSFilterDriverObject,
                sizeof(SFILTER_DEVICE_EXTENSION),
                NULL,
                fileSysDevice->DeviceType,
                0,
                FALSE,
                &VolumeDeviceObject );
        if( !NT_SUCCESS(ntStatus) ) {
 
                //DbgPrint(("Filemon: failed to create associated device: %c/n", 'A'+0 ));   
 
                ObDereferenceObject( fileObject );
                ZwClose( ntFileHandle );
 
                return FALSE;
        } 
        
        // Clear the device's init flag as per NT DDK KB article on creating device 
        // objects from a dispatch routine
        //
        VolumeDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
         这段代码用来创建一个新的设备对象,过会我就用它来绑定到刚才取得的c盘设备对象上去。之后要设置一下新设备对象的标志位,使它的初始化位为空。
现在,我们已把一切准备工作都完成啦。是不是很快?!最后的一步就是完成绑定,代码如下:
attachedObject = IoAttachDeviceToDeviceStack( VolumeDeviceObject, fileSysDevice );
        if( NULL == attachedObject ) 
        {
                //DbgPrint(("Filemon: Connect with Filesystem failed: %c (%x) =>%x/n", 
                //      'C', fileSysDevice, (LONG)ntStatus ));
 
                // Derefence the object and get out
                ObDereferenceObject( fileObject );
                ZwClose( ntFileHandle );
 
                return FALSE;
        } 
 
        //
        // Setup the device extensions. The drive letter and file system object are stored
        // in the extension.
        //
        sfExtention = VolumeDeviceObject->DeviceExtension;
        sfExtention->AttachedToDeviceObject = attachedObject;//fileSysDevice;
        
最后还有一定后继的东西:
// Close the file and update the hooked drive list by entering a 
    // pointer to the hook device object in it. 
    ObDereferenceObject( fileObject ); 
    ZwClose( ntFileHandle );
    return TRUE;

          结束了!代码真的很简洁。把Attach2C_Volume放在DriverEntry最后的结束的地方进行调用,如果你的程序没有别的问题的话,就能轻松的实现指定盘符的绑定了。
 
<think>我们正在处理用户的问题:如何将设备驱动绑定指定CPU核心(Linux和Windows)根据用户提供的引用,我们主要关注Linux部分,因为引用中提供了Linux下的方法(Windows部分可能需要另外的知识,但用户要求中提到了Windows,所以需要补充)在Linux中,我们可以通过以下方式绑定进程(包括驱动程序)到特定的CPU核心:1.使用taskset命令:这是Linux下常用的工具,可以设置或查看进程的CPU亲和性(affinity)。2.使用cset命令:这是一个更高级的工具,可以用于管理cgroup,从而更精细地控制CPU分配。3.在程序代码中设置:通过调用系统函数(如sched_setaffinity)来实现。另外,对于设备中断的绑定,用户引用[3]提到了smp_affinity,这是一个设置中断亲和性的方法。但是,用户的问题是关于“设备驱动”的绑定。这里需要区分:-驱动程序的进程(内核线程)的绑定-设备中断的绑定通常,驱动程序可能包含内核线程,这些线程可以绑定到特定CPU。同时,设备产生的中断也可以绑定到特定CPU。因此,我们分两部分回答:Linux下驱动程序线程的绑定和中断的绑定,以及Windows下的方法。由于用户引用中主要涉及Linux,且没有提供Windows的引用,所以Windows部分需要依靠我们的知识库。步骤:1.Linux下绑定驱动程序线程到指定CPU核心:-使用taskset命令:例如,将进程ID为1234的进程绑定到CPU0和CPU1上:`taskset-p0x31234`(0x3是掩码,代表CPU0和CPU1)-在代码中:使用sched_setaffinity函数(在C/C++中)。2.Linux下绑定设备中断到指定CPU核心:-查看中断号:`cat/proc/interrupts`-设置中断的smp_affinity:例如,将中断号为55的中断绑定到CPU0和CPU1:`echo3>/proc/irq/55/smp_affinity`(注意:这里的3是十进制还是十六进制?实际上,/proc/irq/55/smp_affinity文件需要的是十六进制掩码,但写入时可以直接写十六进制数或十进制数?实际上,内核文档说明这是一个位掩码,通常用十六进制表示,但在写入时也可以使用十进制。不过,为了准确,我们通常使用十六进制。但注意,在echo命令中,我们可以直接写十进制数,因为内核会将其解释为位掩码。但更常见的是使用十六进制前缀0x。然而,在写入/proc文件时,我们通常不写0x,而是直接写十六进制数字字符串。但实际测试发现,写入十进制和十六进制都可以,因为内核会按位掩码解析。例如,写入3(十进制)表示二进制0011,即使用CPU0和CPU1。而写入0x3也是同样的效果。但是,为了清晰,建议使用十六进制。但注意:该文件在读取时显示的是十六进制,而写入时可以使用十进制或十六进制(不带0x)?实际上,写入时直接写数字(可以是十进制、八进制或十六进制,但通常用十进制或十六进制)。更安全的做法是使用十六进制,因为掩码可能很长。例如,对于8核CPU,要绑定到CPU3(从0开始),掩码是8(即1000二进制),可以写8(十进制)或者8(十六进制)?实际上,写入8(十进制)和0x8(十六进制字符串)都可以,但是写入文件时不能带0x,所以直接写8(十六进制)是不行的,因为8在字符串中就是数字8。所以,我们通常写十进制数。但注意:掩码的每一位对应一个CPU,所以第0位对应CPU0,第1位对应CPU1,以此类推。例如,绑定到CPU3,掩码是8(十进制)=1000二进制。3.Windows下绑定进程到指定CPU核心:-使用任务管理器:在“详细信息”选项卡中,右键点击进程,选择“设置相关性”。-使用命令行工具:可以使用PowerShell命令(例如,使用Get-Process和Set-ProcessAffinity)或者使用Start命令的/Affinity参数(例如:start/Affinity0x1notepad.exe,表示将记事本绑定到CPU0)。-在代码中:使用SetProcessAffinityMask函数。但是,用户的问题是关于设备驱动绑定。在Windows中,设备驱动运行在内核模式,通常由系统管理,用户一般不能直接设置设备驱动的CPU亲和性。但可以设置设备中断的亲和性吗?在Windows中,中断的亲和性可以通过设备管理器的“高级”设置来调整(如果设备支持)。另外,对于驱动程序创建的线程,可以在驱动代码中调用KeSetSystemAffinityThread函数来设置。因此,我们回答需要分清楚是驱动程序的线程还是中断。由于用户问题没有明确,我们提供两部分的信息。回答结构:1.Linux下设备驱动线程的CPU绑定2.Linux下设备中断的CPU绑定3.Windows下设备驱动线程的CPU绑定(可能需要在驱动代码中实现)4.Windows下设备中断的CPU绑定(通过设备管理器)注意:在Linux中,驱动程序通常以内核线程的形式运行,因此我们可以像绑定普通进程一样绑定它们(使用taskset或代码)。但在Windows中,驱动程序的线程设置需要在内核编程时完成。我们根据以上思路组织回答。同时,根据系统指令,我们需要生成相关问题。注意:用户引用[1]提到使用isolcpus参数启动内核,这样指定的CPU就不会被调度器使用,只能通过绑定来使用。这是提高绑定效果的一种方法。下面开始回答:</think>### 如何将设备驱动绑定指定CPU核心(Linux/Windows) #### **Linux 系统实现** ##### 1. **驱动线程绑定** 设备驱动的内核线程可通过 **`taskset` 命令**或 **编程接口** 绑定: - **`taskset` 命令** 示例(将进程绑定到 CPU0 和 CPU1): ```bash taskset -cp 0,1 <驱动进程PID> # 查看PID: ps aux | grep 驱动名 ``` - 掩码格式:`taskset -p 0x3 <PID>`(`0x3` 对应二进制 `0011`,绑定 CPU0 和 CPU1)[^1][^2]。 - **编程实现(C/C++)** 在驱动代码中使用 `sched_setaffinity`: ```c #include <sched.h> cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(0, &cpuset); // 绑定到 CPU0 sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); ``` ##### 2. **设备中断绑定** 通过 **`smp_affinity`** 设置中断的 CPU 亲和性: 1. 查询设备中断号: ```bash cat /proc/interrupts | grep <设备名> ``` 2. 绑定中断到 CPU(例如绑定到 CPU0): ```bash echo 1 > /proc/irq/<中断号>/smp_affinity # 1 对应二进制 0001(CPU0) ``` - 掩码规则:十六进制位掩码,如 `0xF`(二进制 `1111`)绑定到所有 CPU[^3]。 ##### 3. **高级隔离(`isolcpus`)** 启动内核时隔离 CPU 核心,禁止系统调度: ```bash # 在 GRUB 配置中添加 GRUB_CMDLINE_LINUX="isolcpus=2,3" # 隔离 CPU2 和 CPU3 ``` 隔离后需手动绑定驱动进程到隔离核心[^1]。 --- #### **Windows 系统实现** ##### 1. **驱动线程绑定** 需在驱动代码中调用 **`KeSetSystemAffinityThread`**: ```c #include <wdm.h> KAFFINITY affinity = 1; // 二进制 0001,绑定到 CPU0 KeSetSystemAffinityThread(affinity); ``` ##### 2. **设备中断绑定** 通过设备管理器设置: 1. 打开 **设备管理器** → 目标设备 → **属性** → **资源** 选项卡。 2. 修改 **中断亲和性**(需硬件支持,部分设备不可调)。 ##### 3. **进程绑定(用户层工具)** - **任务管理器**: 进程详情页 → 右键 **设置相关性** → 选择 CPU。 - **命令行**: ```cmd start /Affinity 0x1 <驱动进程.exe> # 0x1 绑定到 CPU0 ``` --- #### **关键注意事项** 1. **权限要求**:Linux 需 `root`;Windows 需管理员权限。 2. **硬件支持**:中断绑定需设备驱动支持。 3. **性能影响**: - 减少 CPU 缓存失效,提升性能[^2]。 - 过度绑定可能导致负载不均衡。 4. **调试工具**: - Linux:`top -H` 或 `htop`(按 `F2` 显示 CPU 亲和性)。 - Windows:Process Explorer(查看线程亲和性)。 --- ### 相关问题 1. 如何验证 Linux 中 CPU 绑定是否生效? 2. Windows 驱动开发中如何动态切换线程的 CPU 亲和性? 3. 绑定设备中断到特定 CPU 有哪些实际应用场景? 4. 在多核系统中,CPU 隔离(`isolcpus`)对实时性任务有何优势? [^1]: Linux性能优化(十五)——CPU绑定。一旦Linux Kernel使用isolcpus参数启动,Linux Kernel任务均衡调度器不会再将进程调度给指定CPU核心。 [^2]: Linux 中用c++实现线程绑定CPU。CPU的亲和性,就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器。 [^3]: Linux将中断绑定指定多个CPU。注意smp_affinity是一个十六进制的bitmask,它和CPU序列的“与”运算结果决定中断亲和性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值