【问题标题】:Flushing the cache and TLB does not work : flush_cache_mm(mm)/flush_tlb_mm(mm)刷新缓存和 TLB 不起作用:flush_cache_mm(mm)/flush_tlb_mm(mm)
【发布时间】:2014-04-26 12:46:43
【问题描述】:

刷新缓存和 TLB 不起作用。以下内核模块接收 pid 并刷新具有该 id 的进程的 tlb/cache 条目。

我修改了 Linux 内核中的 handle_mm_fault() 函数,并在其中添加了一行打印出 pid 和导致页面 if(current->pid == target_process)....的地址。请参阅下面注释掉的行。但是,当我运行测试时,我没有看到由该进程引起的任何页面错误。我正在使用在 x86-64 位处理器上运行的 linux v3.11.6。

#include <linux/module.h>
#include <linux/mm.h>
#include <asm/tlbflush.h>
#include <asm/tlb.h>

static int pid = -1;
module_param(pid, int, 0444);

void do_init(void) {
    struct task_struct *task;
    struct vm_area_struct *next_vma;
    struct mm_struct *mm;

    if (pid == -1)
        return;

    task = pid_task(find_vpid(pid), PIDTYPE_PID);

    //target_process = pid;

    if (!task) {
        printk("Could not find the task struct for process id %d\n", pid);
        return;
    } else {
        printk("Found the task <%s>\n", task->comm);
    }

    mm = task->mm;

    if (!mm) {
        printk("Could not find the mmap struct for process id %d\n", pid);
        return;
    }

    printk("****Start_brk = %lu\n", mm->start_brk);
    down_read(&mm->mmap_sem);

    next_vma = find_vma(mm, mm->start_brk);
    flush_cache_mm(mm); 
    flush_tlb_mm(mm); 
    up_read(&mm->mmap_sem); 

}

int init_module(void) {
    printk("Inserting the module!!!\n");
    do_init();
    return 0;
}

void cleanup_module(void) {
    printk("Module removed!!!\n");
}

MODULE_LICENSE("GPL");

【问题讨论】:

  • TLB 可以在大多数通用架构(如 x86/x86_64)中由硬件重新填充,而不是通过页面错误。要获得页面错误,您应该更改 VMA 的标志(禁用读写)。
  • 我该怎么做?我仍然想从 linux 内核(最好是一个模块)中做到这一点。
  • 可以查看mprotect系统调用(check its man)的实现:SYSCALL_DEFINE3(mprotect in mm/mprotect.c

标签: linux caching memory-management linux-kernel linux-device-driver


【解决方案1】:

刷新缓存和 TLB 不起作用。

实际上它可能会起作用,但 TLB 刷新的效果是不会出现页面错误。刷新 TLB 后,来自目标进程的内存访问将导致 TLB 未命中和 TLB 重新填充。在最常见的 x86/x86_64 和更常见的 ARM 中,Memory management unit 将在硬件中重新填充 TLB,而无需来自操作系统的活动代码。在 refill MMU 将加载页表并遍历它。在更奇特的 SPARC 或 MIPS 中,tlb 重新填充可以由软件完成,但不能由 pagefault 完成。

如果您想在访问某些内存区域时强制出现页面错误,您可以(从用户空间)使用mprotect 系统调用(check its man,只需在标志中设置不读取(PROT_READ)和写入(PROT_WRITE)访问权限。

如果你想从内核空间做同样的事情,你可以检查mprotect:SYSCALL_DEFINE3(mprotect in mm/mprotect.c的实现并做同样的事情......

 unsigned long vm_flags = calc_vm_prot_bits(..flags..); // set flags
 down_write(&current->mm->mmap_sem); // lock mm
 vma = find_vma(current->mm, ..address..); // find needed VMA
 // check for errors...
 vma->vm_flags = newflags;
 vma->vm_page_prot = pgprot_modify(...) // update vm flags, or just call mprotect_fixup
 up_write(&current->mm->mmap_sem); // unlock mm

^^^ 代码未经测试,无效,任何人不得使用。

【讨论】:

    猜你喜欢
    • 2014-10-08
    • 2016-05-15
    • 1970-01-01
    • 2011-05-05
    • 1970-01-01
    • 2022-08-18
    • 1970-01-01
    • 1970-01-01
    • 2019-10-20
    相关资源
    最近更新 更多