We all know that the TLB is flushed when the page table is switched, so that you can use the new address space, what is the lazy mode of TLB refresh?
What is the TLB? There is no explanation here, it can be simply understood that, in order to expedite the increase in the cache of the virtual address of the MMU, it records the physical address of a memory page corresponding to a virtual address. In fact, according to the first 20 bits of the virtual address, to establish a list of entries, corresponding to the record by looking up the page table to record the physical address of the page.
Since there is a cache, then the content of the cache is changed, it involves the cache refresh, is the TLB refresh problem, when a page table structure changes, the use of the page table node-structured CPU should refresh its own TLB.
Obviously when the process is switched, the TLB should be refreshed because the address space has changed, however, the kernel process accesses only the address range of the kernel space, and the address range of the kernel space for each process is the same, so if the CPU switches from one user process to a kernel process, Because the user process and kernel process kernel address space part of the same, actually do not switch page table, kernel process can still use the kernel part of the previous user process address space. This eliminates the performance loss associated with flushing the TLB.
Imagination is perfect, but under the SMP architecture, this will bring some problems, for example, on a certain core CPU0 just switched from a user process to a kernel process, which inherits the address space of the user process, but it only accesses the kernel space section, which is not problematic, however, if the user process is in another CPU1 The kernel is dispatched, and when CPU0 uses its address space, it executes on the CPU1 and exits, then its address space will be destroyed, at this point, if CPU0 access to its address space is very dangerous, whether it is cached address or not cached address will have unintended serious consequences.
So, is this good thing to be killed by the above situation, and each time to refresh the TLB, reload the page table. Obviously there is a remedy, if the kernel process during the execution of the CPU0, it refers to the user process of the address space is not scheduled and completed the situation is still very much, this does not flush the performance improvement of the TLB or can be exploited, who let Linux is a prudent kernel.
How to do this, in fact, is very simple, when the address space is destroyed, notice that the kernel process is using this address space. So we just need to record what the current address space has the CPU in the reference line, when the address space is destroyed, send a IPI to other reference that address space CPU, let them reload their page table structure, it is OK.
This introduces the lazy mode of TLB refresh.
Linux creates a node structure for each CPU, which is a per-CPU data, so there is no need to lock, each CPU only accesses its own node structure, it records the state of the CPU, TLBSTATE_OK represents non-lazy mode, Tlbstate_lazy represents lazy mode. It also records the address space section of the CPU reference, is a mm_struct type of the node-body pointer, it records all the information of a process's address space, Mm_struct has a member Cpu_vm_mask, is a default 32-bit mask, if a CPU is using this address Space, the corresponding position is set, and it is clear that it will support a maximum of 32 CPUs. This is simple, when a CPU from a user process, call a kernel process, it will set its own into the Tlbstate_lazy mode, and it refers to the user process mm_struct in the corresponding location bit, this time does not switch page table node structure, That is, the page directory of the kernel space is not loaded, and if the user process of the address space it refers to exits and the address space is destroyed, the destroyed logic will know to which CPU the IPI message is sent according to the corresponding mask in the Mm_struct, at which point the CPU using that address space will receive this message. The response function for the message is Smp_invalidate_interrupt, and the code is as follows:
void Smp_invalidate_interrupt (struct pt_regs *regs) {unsigned long cpu;cpu = GET_CPU (); if (!cpu_isset (CPU, Flush_cpumask ) Goto out;/* * This is a BUG () but until someone can quote me the * line from the Intel Manual, guarantees an IPI to * Multiple CPUs is retried _only_ in the erroring CPUs * Its staying as a return * * BUG (); */if (flush_mm = = PER_CPU (cpu_tlbstate, CPU). active_mm) {if (PER_CPU (cpu_tlbstate, CPU). State = = TLBSTATE_OK) {if (flush_ VA = = Tlb_flush_all) local_flush_tlb (); Else__flush_tlb_one (FLUSH_VA);} ELSELEAVE_MM (CPU);} ACK_APIC_IRQ (); Smp_mb__before_clear_bit (); Cpu_clear (CPU, flush_cpumask); Smp_mb__after_clear_bit (); out:put_cpu_ No_resched (); __get_cpu_var (Irq_stat). irq_tlb_count++;
It compares to see if the address space you are referring to is the address space being destroyed, and if so, whether to see if it is lazy mode, if it is lazy mode, then call LEAVE_MM, the code is as follows:
void leave_mm (int cpu) {if (PER_CPU (cpu_tlbstate, CPU). State = = TLBSTATE_OK) BUG (); Cpu_clear (CPU, PER_CPU (Cpu_tlbstate, CPU). Active_mm->cpu_vm_mask); Load_cr3 (Swapper_pg_dir);}
It clears itself from the mask in the address space and loads the Swapper_pg_dir page directory, which is the page directory of the kernel space, which causes the TLB to flush, which should be loaded when the CPU is dispatched to the kernel process, and is then called lazy flush TLB.
Lazy mode for Linux TLB refresh